diff --git a/NEWS b/NEWS index 4248666919e4713f0cb1fd7674dff9a886634f92..906005fbab475bdd6b9623d0cd25381e3b72fd45 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ Changes since 1.4.0: * Added a userspace library for accessing the application interface. This library is licensed under LGPLv2. * Added distributed clocks support. +* Added watchdog configuration via application interface (thanks to J. Mohre). * Added VoE mailbox protocol support. * Improved the callback mechanism. ecrt_master_callbacks() now takes two callback functions for sending and receiving datagrams. diff --git a/TODO b/TODO index 60fad664883d31675486fe61417b901957a859d8..3b43cd5e08f7ab01f934142a426eb7a75c63f704 100644 --- a/TODO +++ b/TODO @@ -43,7 +43,6 @@ Version 1.5.0: * Check for ioctl() interface version. * Improve application-triggered SDO transfers by moving the state machine into the SDO handlers. -* Apply watchdog patches from J. Mohre. * Move device driver files in subdirectories. * Document ec_fsm_foe members. * Test KBUILD_EXTRA_SYMBOLS. diff --git a/include/ecrt.h b/include/ecrt.h index f8921ba390294b581c2ad33cc88e7e2f2db3e460..5238aee44063ec7e5ace5496da7400524419dc2a 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -50,6 +50,9 @@ * callback functions for sending and receiving datagrams. * ecrt_master_send_ext() is used to execute the sending of non-application * datagrams. + * - Added watchdog configuration (method ecrt_slave_config_watchdog(), + * #ec_watchdog_mode_t, \a watchdog_mode parameter in ec_sync_info_t and + * ecrt_slave_config_sync_manager()). * - Added ecrt_open_master() and ecrt_master_reserve() separation for * userspace. * - Added ecrt_master() userspace interface, to get information about a @@ -61,7 +64,7 @@ * ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*(). * - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See * ecrt_slave_config_create_voe_handler(). - * - Renamed ec_sdo_request_state_t to ec_request_state_t, because it is also + * - Renamed ec_sdo_request_state_t to #ec_request_state_t, because it is also * used by VoE handlers. * - Removed 'const' from argument of ecrt_sdo_request_state(), because the * userspace library has to modify object internals. @@ -275,6 +278,18 @@ typedef enum { /*****************************************************************************/ +/** Watchdog mode for sync manager configuration. + * + * Used to specify, if a sync manager's watchdog is to be enabled. + */ +typedef enum { + EC_WD_DEFAULT, /**< Use the default setting of the sync manager. */ + EC_WD_ENABLE, /**< Enable the watchdog. */ + EC_WD_DISABLE, /**< Disable the watchdog. */ +} ec_watchdog_mode_t; + +/*****************************************************************************/ + /** PDO entry configuration information. * * This is the data type of the \a entries field in ec_pdo_info_t. @@ -322,6 +337,7 @@ typedef struct { unsigned int n_pdos; /**< Number of PDOs in \a pdos. */ ec_pdo_info_t *pdos; /**< Array with PDOs to assign. This must contain at least \a n_pdos PDOs. */ + ec_watchdog_mode_t watchdog_mode; /**< Watchdog mode. */ } ec_sync_info_t; /*****************************************************************************/ @@ -709,7 +725,18 @@ int ecrt_slave_config_sync_manager( ec_slave_config_t *sc, /**< Slave configuration. */ uint8_t sync_index, /**< Sync manager index. Must be less than #EC_MAX_SYNC_MANAGERS. */ - ec_direction_t dir /**< Input/Output. */ + ec_direction_t direction, /**< Input/Output. */ + ec_watchdog_mode_t watchdog_mode /** Watchdog mode. */ + ); + +/** Configure a slave's watchdog times. +*/ +void ecrt_slave_config_watchdog( + ec_slave_config_t *sc, /**< Slave configuration. */ + uint16_t watchdog_divider, /**< Number of 40 ns intervals. Used as a + base unit for all slave watchdogs. */ + uint16_t watchdog_intervals /**< Number of base intervals for process + data watchdog. */ ); /** Add a PDO to a sync manager's PDO assignment. diff --git a/lib/slave_config.c b/lib/slave_config.c index 8f1f11ec0023bcb29e344884662ae83a4881d55f..0b62b8cf7b386f816b34eb09398709c8e5e083a5 100644 --- a/lib/slave_config.c +++ b/lib/slave_config.c @@ -44,7 +44,7 @@ /*****************************************************************************/ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index, - ec_direction_t dir) + ec_direction_t dir, ec_watchdog_mode_t watchdog_mode) { ec_ioctl_config_t data; unsigned int i; @@ -55,6 +55,8 @@ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index, memset(&data, 0x00, sizeof(ec_ioctl_config_t)); data.config_index = sc->index; data.syncs[sync_index].dir = dir; + data.syncs[sync_index].watchdog_mode = watchdog_mode; + data.syncs[sync_index].config_this = 1; if (ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data) == -1) { fprintf(stderr, "Failed to config sync manager: %s\n", @@ -67,6 +69,24 @@ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index, /*****************************************************************************/ +void ecrt_slave_config_watchdog(ec_slave_config_t *sc, + uint16_t divider, uint16_t intervals) +{ + ec_ioctl_config_t data; + + memset(&data, 0x00, sizeof(ec_ioctl_config_t)); + data.config_index = sc->index; + data.watchdog_divider = divider; + data.watchdog_intervals = intervals; + + if (ioctl(sc->master->fd, EC_IOCTL_SC_WATCHDOG, &data) == -1) { + fprintf(stderr, "Failed to config watchdog: %s\n", + strerror(errno)); + } +} + +/*****************************************************************************/ + int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc, uint8_t sync_index, uint16_t pdo_index) { @@ -166,8 +186,8 @@ int ecrt_slave_config_pdos(ec_slave_config_t *sc, return -ENOENT; } - ret = ecrt_slave_config_sync_manager( - sc, sync_info->index, sync_info->dir); + ret = ecrt_slave_config_sync_manager(sc, sync_info->index, + sync_info->dir, sync_info->watchdog_mode); if (ret) return ret; diff --git a/master/cdev.c b/master/cdev.c index 399429f3dc43b84816a87d3ccdd8769d20c23b3d..57e7bf33078157b267e6ce6749a95c53a8b8200e 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -1759,7 +1759,7 @@ int ec_cdev_ioctl_sync_slaves( /*****************************************************************************/ -/** Set the direction of a sync manager. +/** Configure a sync manager. */ int ec_cdev_ioctl_sc_sync( ec_master_t *master, /**< EtherCAT master. */ @@ -1793,9 +1793,9 @@ int ec_cdev_ioctl_sc_sync( } for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { - ec_direction_t dir = data.syncs[i].dir; - if (dir == EC_DIR_INPUT || dir == EC_DIR_OUTPUT) { - if (ecrt_slave_config_sync_manager(sc, i, dir)) { + if (data.syncs[i].config_this) { + if (ecrt_slave_config_sync_manager(sc, i, data.syncs[i].dir, + data.syncs[i].watchdog_mode)) { ret = -EINVAL; goto out_up; } @@ -1810,6 +1810,49 @@ out_return: /*****************************************************************************/ +/** Configure a slave's watchdogs. + */ +int ec_cdev_ioctl_sc_watchdog( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_config_t data; + ec_slave_config_t *sc; + int ret = 0; + + if (unlikely(!priv->requested)) { + ret = -EPERM; + goto out_return; + } + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + ret = -EFAULT; + goto out_return; + } + + if (down_interruptible(&master->master_sem)) { + ret = -EINTR; + goto out_return; + } + + if (!(sc = ec_master_get_config(master, data.config_index))) { + ret = -ENOENT; + goto out_up; + } + + ecrt_slave_config_watchdog(sc, + data.watchdog_divider, data.watchdog_intervals); + +out_up: + up(&master->master_sem); +out_return: + return ret; +} + +/*****************************************************************************/ + /** Add a PDO to the assignment. */ int ec_cdev_ioctl_sc_add_pdo( @@ -3229,6 +3272,10 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; return ec_cdev_ioctl_sc_sync(master, arg, priv); + case EC_IOCTL_SC_WATCHDOG: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_sc_watchdog(master, arg, priv); case EC_IOCTL_SC_ADD_PDO: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; diff --git a/master/fsm_slave_config.c b/master/fsm_slave_config.c index 4f1b4ebf45cd2d0c5db4be291bddfca3c3f80ee9..74bb493741d34a8f6bf7d366439b6c4145e72c8a 100644 --- a/master/fsm_slave_config.c +++ b/master/fsm_slave_config.c @@ -54,6 +54,8 @@ void ec_fsm_slave_config_state_dc_write_offset(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *); @@ -70,6 +72,8 @@ void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *); @@ -558,7 +562,7 @@ void ec_fsm_slave_config_enter_mbox_sync( for (i = 0; i < 2; i++) { ec_sync_page(&slave->sii.syncs[i], i, slave->sii.syncs[i].default_length, - EC_DIR_INVALID, // use default direction + NULL, // use default sync manager configuration datagram->data + EC_SYNC_PAGE_SIZE * i); } @@ -587,7 +591,7 @@ void ec_fsm_slave_config_enter_mbox_sync( sync.control_register = 0x26; sync.enable = 1; ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size, - EC_DIR_INVALID, // use default direction + NULL, // use default sync manager configuration datagram->data); slave->configured_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset; @@ -599,7 +603,7 @@ void ec_fsm_slave_config_enter_mbox_sync( sync.control_register = 0x22; sync.enable = 1; ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size, - EC_DIR_INVALID, // use default direction + NULL, // use default sync manager configuration datagram->data + EC_SYNC_PAGE_SIZE); slave->configured_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset; @@ -844,6 +848,125 @@ void ec_fsm_slave_config_state_pdo_conf( fsm->slave->ring_position); } + ec_fsm_slave_config_enter_watchdog_divider(fsm); +} + +/*****************************************************************************/ + +/** WATCHDOG_DIVIDER entry function. + */ +void ec_fsm_slave_config_enter_watchdog_divider( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_datagram_t *datagram = fsm->datagram; + ec_master_t *master = slave->master; + ec_slave_config_t *config = slave->config; + + if (config && config->watchdog_divider) { + if (master->debug_level) + EC_DBG("Setting watchdog divider to %u.\n", + config->watchdog_divider); + + ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2); + EC_WRITE_U16(datagram->data, config->watchdog_divider); + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_slave_config_state_watchdog_divider; + } else { + ec_fsm_slave_config_enter_watchdog(fsm); + } +} + +/*****************************************************************************/ + +/** Slave configuration state: WATCHDOG_DIVIDER. + */ +void ec_fsm_slave_config_state_watchdog_divider( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) + return; + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_slave_config_state_error; + EC_ERR("Failed to receive watchdog divider configuration datagram for" + " slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + slave->error_flag = 1; + EC_WARN("Failed to set watchdog divider of slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + ec_fsm_slave_config_enter_watchdog(fsm); +} + +/*****************************************************************************/ + +/** WATCHDOG entry function + */ +void ec_fsm_slave_config_enter_watchdog( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + ec_slave_config_t *config = slave->config; + + if (config && config->watchdog_intervals) { + if (slave->master->debug_level) + EC_DBG("Setting process data watchdog intervals to %u.\n", + config->watchdog_intervals); + + ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2); + EC_WRITE_U16(datagram->data, config->watchdog_intervals); + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_slave_config_state_watchdog; + } + + ec_fsm_slave_config_enter_pdo_sync(fsm); +} + +/*****************************************************************************/ + +/** Slave configuration state: WATCHDOG. + */ + +void ec_fsm_slave_config_state_watchdog( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) + return; + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_slave_config_state_error; + EC_ERR("Failed to receive sync manager watchdog configuration " + "datagram for slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + EC_WARN("Failed to set process data watchdog intervals of slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + } + ec_fsm_slave_config_enter_pdo_sync(fsm); } @@ -861,7 +984,6 @@ void ec_fsm_slave_config_enter_pdo_sync( uint8_t sync_index; const ec_sync_t *sync; uint16_t size; - ec_direction_t dir; if (slave->sii.mailbox_protocols) { offset = 2; // slave has mailboxes @@ -884,21 +1006,20 @@ void ec_fsm_slave_config_enter_pdo_sync( ec_datagram_zero(datagram); for (i = 0; i < num_pdo_syncs; i++) { + const ec_sync_config_t *sync_config; sync_index = i + offset; sync = &slave->sii.syncs[sync_index]; if (slave->config) { - const ec_sync_config_t *sync_config; sync_config = &slave->config->sync_configs[sync_index]; size = ec_pdo_list_total_size(&sync_config->pdos); - dir = sync_config->dir; } else { + sync_config = NULL; size = sync->default_length; - dir = EC_DIR_INVALID; } - ec_sync_page(sync, sync_index, size, dir, datagram->data + - EC_SYNC_PAGE_SIZE * i); + ec_sync_page(sync, sync_index, size, sync_config, + datagram->data + EC_SYNC_PAGE_SIZE * i); } fsm->retries = EC_FSM_RETRIES; diff --git a/master/ioctl.h b/master/ioctl.h index 50e7a511b5b78e32c3ca577021d44c595f3c355b..0661d63d5fd563709c8815d8686e56ed9f865de9 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -91,32 +91,33 @@ #define EC_IOCTL_SYNC_REF EC_IO(0x21) #define EC_IOCTL_SYNC_SLAVES EC_IO(0x22) #define EC_IOCTL_SC_SYNC EC_IOW(0x23, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x24, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x25, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x26, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x27, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x28, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_DC EC_IOW(0x29, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x2a, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2b, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x2c, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x2d, ec_ioctl_sc_state_t) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x2e) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x2f) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x30) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x31, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x32, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x33, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x34, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x35, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x36, ec_ioctl_sdo_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x37, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x38, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x39, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3a, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3b, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x3c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x3d, ec_ioctl_voe_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x24, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x25, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x26, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x27, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x28, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x29, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_DC EC_IOW(0x2a, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x2b, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2c, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x2d, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x2e, ec_ioctl_sc_state_t) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x2f) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x20) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x31) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x32, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x33, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x34, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x35, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x36, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x37, ec_ioctl_sdo_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x38, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x39, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x3a, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3b, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3c, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x3d, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x3e, ec_ioctl_voe_t) /*****************************************************************************/ @@ -389,8 +390,12 @@ typedef struct { uint32_t product_code; struct { ec_direction_t dir; + ec_watchdog_mode_t watchdog_mode; uint32_t pdo_count; + uint8_t config_this; } syncs[EC_MAX_SYNC_MANAGERS]; + uint16_t watchdog_divider; + uint16_t watchdog_intervals; uint32_t sdo_count; int32_t slave_position; uint16_t dc_assign_activate; diff --git a/master/slave_config.c b/master/slave_config.c index a1f33ce2a4d3503f7e37af3cc7941e2dae208cc3..874ed8bce879fb946f795c5e5538b309233f6ae9 100644 --- a/master/slave_config.c +++ b/master/slave_config.c @@ -66,6 +66,8 @@ void ec_slave_config_init( sc->position = position; sc->vendor_id = vendor_id; sc->product_code = product_code; + sc->watchdog_divider = 0; // use default + sc->watchdog_intervals = 0; // use default sc->slave = NULL; @@ -411,13 +413,14 @@ ec_voe_handler_t *ec_slave_config_find_voe_handler( *****************************************************************************/ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index, - ec_direction_t dir) + ec_direction_t dir, ec_watchdog_mode_t watchdog_mode) { ec_sync_config_t *sync_config; if (sc->master->debug_level) EC_DBG("ecrt_slave_config_sync_manager(sc = 0x%x, sync_index = %u, " - "dir = %u)\n", (u32) sc, sync_index, dir); + "dir = %i, watchdog_mode = %i)\n", + (u32) sc, sync_index, dir, watchdog_mode); if (sync_index >= EC_MAX_SYNC_MANAGERS) { EC_ERR("Invalid sync manager index %u!\n", sync_index); @@ -431,11 +434,25 @@ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index, sync_config = &sc->sync_configs[sync_index]; sync_config->dir = dir; + sync_config->watchdog_mode = watchdog_mode; return 0; } /*****************************************************************************/ +void ecrt_slave_config_watchdog(ec_slave_config_t *sc, + uint16_t divider, uint16_t intervals) +{ + if (sc->master->debug_level) + EC_DBG("%s(sc = 0x%x, divider = %u, intervals = %u)\n", + __func__, (u32) sc, divider, intervals); + + sc->watchdog_divider = divider; + sc->watchdog_intervals = intervals; +} + +/*****************************************************************************/ + int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc, uint8_t sync_index, uint16_t pdo_index) { @@ -579,8 +596,8 @@ int ecrt_slave_config_pdos(ec_slave_config_t *sc, return -ENOENT; } - ret = ecrt_slave_config_sync_manager( - sc, sync_info->index, sync_info->dir); + ret = ecrt_slave_config_sync_manager(sc, sync_info->index, + sync_info->dir, sync_info->watchdog_mode); if (ret) return ret; @@ -894,6 +911,7 @@ void ecrt_slave_config_state(const ec_slave_config_t *sc, /** \cond */ EXPORT_SYMBOL(ecrt_slave_config_sync_manager); +EXPORT_SYMBOL(ecrt_slave_config_watchdog); EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_add); EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_clear); EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add); diff --git a/master/slave_config.h b/master/slave_config.h index 297633f048f3f57a1d8ab7da0e7ddd7d016cac58..4954a8f1f59836390473b42fc3fe8f6ce55449db 100644 --- a/master/slave_config.h +++ b/master/slave_config.h @@ -58,6 +58,11 @@ struct ec_slave_config { uint32_t vendor_id; /**< Slave vendor ID. */ uint32_t product_code; /**< Slave product code. */ + uint16_t watchdog_divider; /**< Watchdog divider as a number of 40ns + intervals (see spec. reg. 0x0400). */ + uint16_t watchdog_intervals; /**< Process data watchdog intervals (see + spec. reg. 0x0420). */ + ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is offline. */ diff --git a/master/sync.c b/master/sync.c index 0a6cbe97c5398e103fd82df3094a2027875f2775..0a3f27057757de68f4d06a82e8ba59806a36646d 100644 --- a/master/sync.c +++ b/master/sync.c @@ -95,8 +95,7 @@ void ec_sync_page( const ec_sync_t *sync, /**< Sync manager. */ uint8_t sync_index, /**< Index of the sync manager. */ uint16_t data_size, /**< Data size. */ - ec_direction_t dir, /**< Direction (overrides the control byte, - if set to EC_DIR_INPUT or EC_DIR_OUTPUT). */ + const ec_sync_config_t *sync_config, /**< Configuration. */ uint8_t *data /**> Configuration memory. */ ) { @@ -104,10 +103,28 @@ void ec_sync_page( uint16_t enable = sync->enable && data_size; uint8_t control = sync->control_register; - if (dir == EC_DIR_OUTPUT || dir == EC_DIR_INPUT) { - // override sync manager direction bits with dir parameter - EC_WRITE_BIT(&control, 2, dir == EC_DIR_OUTPUT ? 1 : 0); - EC_WRITE_BIT(&control, 3, 0); + if (sync_config) { + + switch (sync_config->dir) { + case EC_DIR_OUTPUT: + case EC_DIR_INPUT: + EC_WRITE_BIT(&control, 2, + sync_config->dir == EC_DIR_OUTPUT ? 1 : 0); + EC_WRITE_BIT(&control, 3, 0); + break; + default: + break; + } + + switch (sync_config->watchdog_mode) { + case EC_WD_ENABLE: + case EC_WD_DISABLE: + EC_WRITE_BIT(&control, 6, + sync_config->watchdog_mode == EC_WD_ENABLE); + break; + default: + break; + } } if (sync->slave->master->debug_level) diff --git a/master/sync.h b/master/sync.h index 837edcb0c279e65d99854bdfcb438a3287a09d27..b41a229be90200d020066abb1705fd18e472750b 100644 --- a/master/sync.h +++ b/master/sync.h @@ -38,6 +38,7 @@ #include "globals.h" #include "pdo_list.h" +#include "sync_config.h" /*****************************************************************************/ @@ -57,8 +58,8 @@ typedef struct { void ec_sync_init(ec_sync_t *, ec_slave_t *); void ec_sync_init_copy(ec_sync_t *, const ec_sync_t *); void ec_sync_clear(ec_sync_t *); -void ec_sync_page(const ec_sync_t *, uint8_t, uint16_t, ec_direction_t, - uint8_t *); +void ec_sync_page(const ec_sync_t *, uint8_t, uint16_t, + const ec_sync_config_t *, uint8_t *); int ec_sync_add_pdo(ec_sync_t *, const ec_pdo_t *); ec_direction_t ec_sync_default_direction(const ec_sync_t *); diff --git a/master/sync_config.c b/master/sync_config.c index c8d275495ce554857171597463b517b13eb48665..e3c441d21326d43791ca05c4f79e2f818ffab62f 100644 --- a/master/sync_config.c +++ b/master/sync_config.c @@ -45,6 +45,7 @@ void ec_sync_config_init( ) { sync_config->dir = EC_DIR_INVALID; + sync_config->watchdog_mode = EC_WD_DEFAULT; ec_pdo_list_init(&sync_config->pdos); } diff --git a/master/sync_config.h b/master/sync_config.h index b94195de0d1f9e5147f43f9c7695f9a262f48e07..c8fc3e88fe41072fb9339309441427e8667d619b 100644 --- a/master/sync_config.h +++ b/master/sync_config.h @@ -45,6 +45,7 @@ */ typedef struct { ec_direction_t dir; /**< Sync manager direction. */ + ec_watchdog_mode_t watchdog_mode; /**< Watchdog mode. */ ec_pdo_list_t pdos; /**< Current PDO assignment. */ } ec_sync_config_t;