diff -r f8a1e9f364a3 -r b9a6e2c22745 master/master.c --- a/master/master.c Thu Apr 20 14:34:58 2006 +0000 +++ b/master/master.c Fri Apr 21 12:35:17 2006 +0000 @@ -6,6 +6,23 @@ * * $Id$ * + * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 of the License. + * + * The IgH EtherCAT Master is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * *****************************************************************************/ #include @@ -56,6 +73,7 @@ /** Master constructor. \return 0 in case of success, else < 0 + \ingroup Master */ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ @@ -101,6 +119,7 @@ Master destructor. Removes all pending commands, clears the slave list, clears all domains and frees the device. + \ingroup Master */ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) @@ -130,6 +149,7 @@ Resets the master. Note: This function has to be called, everytime ec_master_release() is called, to free the slave list, domains etc. + \ingroup Master */ void ec_master_reset(ec_master_t *master /**< EtherCAT master */) @@ -190,6 +210,7 @@ /** Places a command in the command queue. + \ingroup Master */ void ec_master_queue_command(ec_master_t *master, /**< EtherCAT master */ @@ -217,6 +238,7 @@ /** Sends the commands in the queue. \return 0 in case of success, else < 0 + \ingroup Master */ void ec_master_send_commands(ec_master_t *master /**< EtherCAT master */) @@ -318,6 +340,7 @@ Processes a received frame. This function is called by the network driver for every received frame. \return 0 in case of success, else < 0 + \ingroup Master */ void ec_master_receive(ec_master_t *master, /**< EtherCAT master */ @@ -405,6 +428,7 @@ Sends a single command and waits for its reception. If the slave doesn't respond, the command is sent again. \return 0 in case of success, else < 0 + \ingroup Master */ int ec_master_simple_io(ec_master_t *master, /**< EtherCAT master */ @@ -449,6 +473,7 @@ Scans the EtherCAT bus for slaves. Creates a list of slave structures for further processing. \return 0 in case of success, else < 0 + \ingroup Master */ int ec_master_bus_scan(ec_master_t *master /**< EtherCAT master */) @@ -572,6 +597,7 @@ Output statistics in cyclic mode. This function outputs statistical data on demand, but not more often than necessary. The output happens at most once a second. + \ingroup Master */ void ec_master_output_stats(ec_master_t *master /**< EtherCAT master */) @@ -607,6 +633,7 @@ /** Starts the Free-Run mode. + \ingroup Master */ void ec_master_freerun_start(ec_master_t *master /**< EtherCAT master */) @@ -639,6 +666,7 @@ /** Stops the Free-Run mode. + \ingroup Master */ void ec_master_freerun_stop(ec_master_t *master /**< EtherCAT master */) @@ -655,6 +683,7 @@ /** Free-Run mode function. + \ingroup Master */ void ec_master_freerun(unsigned long data /**< private timer data = master */) @@ -678,115 +707,9 @@ /*****************************************************************************/ /** - Translates an ASCII coded bus-address to a slave pointer. - These are the valid addressing schemes: - - \a "X" = the X. slave on the bus, - - \a "X:Y" = the Y. slave after the X. branch (bus coupler), - - \a "#X" = the slave with alias X, - - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X. - X and Y are zero-based indices and may be provided in hexadecimal or octal - notation (with respective prefix). - \return pointer to the slave on success, else NULL -*/ - -ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */ - const char *address /**< address string */ - ) -{ - unsigned long first, second; - char *remainder, *remainder2; - unsigned int alias_requested, alias_found; - ec_slave_t *alias_slave = NULL, *slave; - - if (!address || address[0] == 0) return NULL; - - alias_requested = 0; - if (address[0] == '#') { - alias_requested = 1; - address++; - } - - first = simple_strtoul(address, &remainder, 0); - if (remainder == address) { - EC_ERR("Slave address \"%s\" - First number empty!\n", address); - return NULL; - } - - if (alias_requested) { - alias_found = 0; - list_for_each_entry(alias_slave, &master->slaves, list) { - if (alias_slave->sii_alias == first) { - alias_found = 1; - break; - } - } - if (!alias_found) { - EC_ERR("Slave address \"%s\" - Alias not found!\n", address); - return NULL; - } - } - - if (!remainder[0]) { // absolute position - if (alias_requested) { - return alias_slave; - } - else { - list_for_each_entry(slave, &master->slaves, list) { - if (slave->ring_position == first) return slave; - } - EC_ERR("Slave address \"%s\" - Absolute position invalid!\n", - address); - } - } - else if (remainder[0] == ':') { // field position - remainder++; - second = simple_strtoul(remainder, &remainder2, 0); - - if (remainder2 == remainder) { - EC_ERR("Slave address \"%s\" - Second number empty!\n", address); - return NULL; - } - - if (remainder2[0]) { - EC_ERR("Slave address \"%s\" - Invalid trailer!\n", address); - return NULL; - } - - if (alias_requested) { - if (!alias_slave->type || - alias_slave->type->special != EC_TYPE_BUS_COUPLER) { - EC_ERR("Slave address \"%s\": Alias slave must be bus coupler" - " in colon mode.\n", address); - return NULL; - } - list_for_each_entry(slave, &master->slaves, list) { - if (slave->coupler_index == alias_slave->coupler_index - && slave->coupler_subindex == second) - return slave; - } - EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave" - " following!\n", address, alias_slave->ring_position, - second); - return NULL; - } - else { - list_for_each_entry(slave, &master->slaves, list) { - if (slave->coupler_index == first - && slave->coupler_subindex == second) return slave; - } - } - } - else - EC_ERR("Slave address \"%s\" - Invalid format!\n", address); - - return NULL; -} - -/*****************************************************************************/ - -/** Initializes a sync manager configuration page. The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes. + \ingroup Master */ void ec_sync_config(const ec_sync_t *sync, /**< sync manager */ @@ -805,6 +728,7 @@ /** Initializes a sync manager configuration page with EEPROM data. The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes. + \ingroup Master */ void ec_eeprom_sync_config(const ec_eeprom_sync_t *sync, /**< sync manager */ @@ -823,6 +747,7 @@ /** Initializes an FMMU configuration page. The referenced memory (\a data) must be at least EC_FMMU_SIZE bytes. + \ingroup Master */ void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */ @@ -845,6 +770,7 @@ /** Formats attribute data for SysFS read access. \return number of bytes to read + \ingroup Master */ ssize_t ec_show_master_attribute(struct kobject *kobj, /**< kobject */ @@ -875,6 +801,7 @@ /** Processes the watchdog command. + \ingroup Master */ void ec_master_process_watch_command(ec_master_t *master @@ -918,6 +845,22 @@ } } +/*****************************************************************************/ + +/** + Does the Ethernet-over-EtherCAT processing. + \ingroup Master +*/ + +void ec_master_run_eoe(ec_master_t *master /**< EtherCAT master */) +{ + ec_eoe_t *eoe; + + list_for_each_entry(eoe, &master->eoe_slaves, list) { + ec_eoe_run(eoe); + } +} + /****************************************************************************** * Realtime interface *****************************************************************************/ @@ -925,6 +868,7 @@ /** Creates a domain. \return pointer to new domain on success, else NULL + \ingroup Master */ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */) @@ -970,6 +914,7 @@ managers and FMMUs, and does the appropriate transitions, until the slave is operational. \return 0 in case of success, else < 0 + \ingroup Master */ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) @@ -1156,6 +1101,7 @@ /** Resets all slaves to INIT state. + \ingroup Master */ void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT master */) @@ -1175,6 +1121,7 @@ Fetches the SDO dictionaries of all slaves. Slaves that do not support the CoE protocol are left out. \return 0 in case of success, else < 0 + \ingroup Master */ int ecrt_master_fetch_sdo_lists(ec_master_t *master /**< EtherCAT master */) @@ -1198,6 +1145,7 @@ /** Sends queued commands and waits for their reception. + \ingroup Master */ void ecrt_master_sync_io(ec_master_t *master /**< EtherCAT master */) @@ -1253,6 +1201,7 @@ /** Asynchronous sending of commands. + \ingroup Master */ void ecrt_master_async_send(ec_master_t *master /**< EtherCAT master */) @@ -1279,6 +1228,7 @@ /** Asynchronous receiving of commands. + \ingroup Master */ void ecrt_master_async_receive(ec_master_t *master /**< EtherCAT master */) @@ -1313,6 +1263,7 @@ Prepares synchronous IO. Queues all domain commands and sends them. Then waits a certain time, so that ecrt_master_sasync_receive() can be called securely. + \ingroup Master */ void ecrt_master_prepare_async_io(ec_master_t *master /**< EtherCAT master */) @@ -1340,6 +1291,7 @@ /** Does all cyclic master work. + \ingroup Master */ void ecrt_master_run(ec_master_t *master /**< EtherCAT master */) @@ -1358,10 +1310,119 @@ /*****************************************************************************/ /** + Translates an ASCII coded bus-address to a slave pointer. + These are the valid addressing schemes: + - \a "X" = the X. slave on the bus, + - \a "X:Y" = the Y. slave after the X. branch (bus coupler), + - \a "#X" = the slave with alias X, + - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X. + X and Y are zero-based indices and may be provided in hexadecimal or octal + notation (with respective prefix). + \return pointer to the slave on success, else NULL + \ingroup Master +*/ + +ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */ + const char *address /**< address string */ + ) +{ + unsigned long first, second; + char *remainder, *remainder2; + unsigned int alias_requested, alias_found; + ec_slave_t *alias_slave = NULL, *slave; + + if (!address || address[0] == 0) return NULL; + + alias_requested = 0; + if (address[0] == '#') { + alias_requested = 1; + address++; + } + + first = simple_strtoul(address, &remainder, 0); + if (remainder == address) { + EC_ERR("Slave address \"%s\" - First number empty!\n", address); + return NULL; + } + + if (alias_requested) { + alias_found = 0; + list_for_each_entry(alias_slave, &master->slaves, list) { + if (alias_slave->sii_alias == first) { + alias_found = 1; + break; + } + } + if (!alias_found) { + EC_ERR("Slave address \"%s\" - Alias not found!\n", address); + return NULL; + } + } + + if (!remainder[0]) { // absolute position + if (alias_requested) { + return alias_slave; + } + else { + list_for_each_entry(slave, &master->slaves, list) { + if (slave->ring_position == first) return slave; + } + EC_ERR("Slave address \"%s\" - Absolute position invalid!\n", + address); + } + } + else if (remainder[0] == ':') { // field position + remainder++; + second = simple_strtoul(remainder, &remainder2, 0); + + if (remainder2 == remainder) { + EC_ERR("Slave address \"%s\" - Second number empty!\n", address); + return NULL; + } + + if (remainder2[0]) { + EC_ERR("Slave address \"%s\" - Invalid trailer!\n", address); + return NULL; + } + + if (alias_requested) { + if (!alias_slave->type || + alias_slave->type->special != EC_TYPE_BUS_COUPLER) { + EC_ERR("Slave address \"%s\": Alias slave must be bus coupler" + " in colon mode.\n", address); + return NULL; + } + list_for_each_entry(slave, &master->slaves, list) { + if (slave->coupler_index == alias_slave->coupler_index + && slave->coupler_subindex == second) + return slave; + } + EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave" + " following!\n", address, alias_slave->ring_position, + second); + return NULL; + } + else { + list_for_each_entry(slave, &master->slaves, list) { + if (slave->coupler_index == first + && slave->coupler_subindex == second) return slave; + } + } + } + else + EC_ERR("Slave address \"%s\" - Invalid format!\n", address); + + return NULL; +} + +/*****************************************************************************/ + +/** Sets the debug level of the master. The following levels are valid: - 1: only output positions marks and basic data - 2: additional frame data output + \ingroup Master */ void ecrt_master_debug(ec_master_t *master, /**< EtherCAT master */ @@ -1382,6 +1443,7 @@ - 0: Only slave types and positions - 1: with EEPROM contents - >1: with SDO dictionaries + \ingroup Master */ void ecrt_master_print(const ec_master_t *master, /**< EtherCAT master */ @@ -1408,21 +1470,6 @@ /*****************************************************************************/ -/** - Does the Ethernet-over-EtherCAT processing. -*/ - -void ec_master_run_eoe(ec_master_t *master /**< EtherCAT master */) -{ - ec_eoe_t *eoe; - - list_for_each_entry(eoe, &master->eoe_slaves, list) { - ec_eoe_run(eoe); - } -} - -/*****************************************************************************/ - EXPORT_SYMBOL(ecrt_master_create_domain); EXPORT_SYMBOL(ecrt_master_activate); EXPORT_SYMBOL(ecrt_master_deactivate);