CANopenNode V2.0 pre-release
This commit is contained in:
parent
7a43f98f24
commit
f73025ef65
24 changed files with 5079 additions and 4467 deletions
1067
301/CO_Emergency.c
1067
301/CO_Emergency.c
File diff suppressed because it is too large
Load diff
|
|
@ -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 <https://github.com/CANopenNode/CANopenNode>.
|
||||
|
|
@ -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.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ###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.
|
||||
* 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.
|
||||
*
|
||||
* ####Contents of _Pre Defined Error Field_ (object dictionary, index 0x1003):
|
||||
* bytes 0..3 are equal to bytes 0..3 in the Emergency message.
|
||||
* ### 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.
|
||||
*
|
||||
* @see #CO_Default_CAN_ID_t
|
||||
* ### 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 */
|
||||
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,
|
||||
|
||||
#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 */
|
||||
/** @} */
|
||||
/** 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.
|
||||
* 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.
|
||||
*
|
||||
* 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).
|
||||
* 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) */
|
||||
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,
|
||||
|
||||
#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) */
|
||||
/** 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,
|
||||
|
||||
#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) */
|
||||
/** 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,
|
||||
|
||||
#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 */
|
||||
/** 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,
|
||||
|
||||
#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 */
|
||||
/** @} */
|
||||
/** 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;
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/** From CO_EM_initCallbackPre() or NULL */
|
||||
void *functSignalObjectPre;
|
||||
#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);
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN
|
||||
/** From CO_EM_initCallbackPre() or NULL */
|
||||
void (*pFunctSignalPre)(void *object);
|
||||
/** From CO_EM_initCallbackPre() or NULL */
|
||||
void *functSignalObjectPre;
|
||||
#endif
|
||||
#ifdef CO_SDO_SERVER_H
|
||||
} CO_EM_t;
|
||||
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
/* Optional signal to RTOS, which can resume task, which handles NMT. */
|
||||
if (NMT->pFunctSignalPre != NULL) {
|
||||
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;
|
||||
NMT->operatingStatePrev = NMTstateCpy;
|
||||
|
||||
/* 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;
|
||||
/* 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;
|
||||
}
|
||||
#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 {
|
||||
*timerNext_us = 0;
|
||||
NMT->pFunctNMT(NMTstateCpy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (CO_NMT_reset_cmd_t) NMT->resetCommand;
|
||||
#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT
|
||||
/* 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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/* 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->state = CO_SDO_ST_IDLE;
|
||||
CO_FLAG_CLEAR(SDO_C->CANrxNew);
|
||||
/* prepare circular fifo buffer */
|
||||
CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf,
|
||||
CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1);
|
||||
|
||||
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);
|
||||
/* 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
|
||||
|
||||
CO_SDO_return_t cliSetupRet = CO_SDOclient_setup(SDO_C,
|
||||
COB_IDClientToServer,
|
||||
COB_IDServerToClient,
|
||||
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 */
|
||||
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 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 */
|
||||
CanIdC2S, /* CAN identifier */
|
||||
0, /* rtr */
|
||||
8, /* number of data bytes */
|
||||
0); /* synchronous message flag bit */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
/* Max data size is limited to fifo size (for now). */
|
||||
size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo);
|
||||
/* search object dictionary in first pass */
|
||||
if (SDO_C->OD_IO.write == NULL) {
|
||||
ODR_t odRet;
|
||||
OD_subEntry_t subEntry;
|
||||
|
||||
if (SDO_C->sizeInd > 0 && SDO_C->sizeInd != count) {
|
||||
abortCode = CO_SDO_AB_TYPE_MISMATCH;
|
||||
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 {
|
||||
/* 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);
|
||||
SDO_C->OD_IO.write = subEntry.write;
|
||||
}
|
||||
}
|
||||
/* 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];
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
/* Max data size is limited to fifo size (for now). */
|
||||
size_t count = CO_fifo_getSpace(&SDO_C->bufFifo);
|
||||
/* search object dictionary in first pass */
|
||||
if (SDO_C->OD_IO.read == NULL) {
|
||||
ODR_t odRet;
|
||||
OD_subEntry_t subEntry;
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
ret = CO_SDO_RT_endedWithServerAbort;
|
||||
SDO_C->OD_IO.read = subEntry.read;
|
||||
}
|
||||
}
|
||||
SDO_C->state = CO_SDO_ST_IDLE;
|
||||
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
ret = CO_SDO_RT_waitingLocalTransfer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
2675
301/CO_SDOserver.c
2675
301/CO_SDOserver.c
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
476
CANopen.h
476
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
|
||||
#ifdef CO_DOXYGEN
|
||||
#define CO_MULTIPLE_OD
|
||||
#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
|
||||
#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 */
|
||||
|
||||
|
||||
/**
|
||||
* CANopen object with pointers to all CANopenNode objects.
|
||||
* 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
|
||||
|
||||
|
||||
#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 {
|
||||
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 */
|
||||
/** 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
|
||||
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
|
||||
/** 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
|
||||
#if CO_NO_TIME == 1 || defined CO_DOXYGEN
|
||||
CO_TIME_t *TIME; /**< TIME object */
|
||||
/** 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
|
||||
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_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_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
|
||||
#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 */
|
||||
|
||||
|
|
|
|||
21
Makefile
21
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
|
||||
|
||||
|
|
|
|||
13
README.md
13
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
12
example/OD.c
Normal file
12
example/OD.c
Normal file
|
|
@ -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]
|
||||
};
|
||||
45
example/OD.h
Normal file
45
example/OD.h
Normal file
|
|
@ -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]
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
#ifndef CO_OD_STORAGE
|
||||
#define CO_OD_STORAGE 1
|
||||
#define CO_OD_STORAGE 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
#include <sys/reboot.h>
|
||||
|
||||
#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 <Node ID> CANopen Node-id (1..127) or 0xFF(unconfigured). If not\n"
|
||||
" specified, value from Object dictionary (0x2101) is used.\n");
|
||||
" -i <Node ID> CANopen Node-id (1..127) or 0xFF (LSS unconfigured).\n");
|
||||
#ifndef CO_SINGLE_THREAD
|
||||
printf(
|
||||
" -p <RT priority> 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; i<OD_traceEnable && i<CO_NO_TRACE; i++) {
|
||||
for(i=0; i<OD_traceEnable && i<co->CNT_TRACE; i++) {
|
||||
CO_trace_process(CO->trace[i], *CO_time.epochTimeOffsetMs);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue