The patch I have is for the latest stable-1.5 tag. To use the patch, put the
SII information (export using TwinCAT) in
[FIRMWARE_LOCATION]/ethercat/ec_[VENDOR ID]_[PRODUCT CODE].bin
For my distro, OpenSuSE, the firmware location is
/lib/firmware/[KERNEL_VERSION], but this can differ between distro's.
Regards,
Jesper
Op dinsdag 1 november 2011 10:00:04 schreef Graeme Foot:
> Hi,
>
> Yes, I'm interested in the patch.
>
> Thanks,
> Graeme.
>
>
> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]] On Behalf Of Jesper Smith
> Sent: Friday, 28 October 2011 04:02
> To: [email protected]
> Subject: Re: [etherlab-users] Problem reading SII configuration from
> slave
>
> Hello,
>
> Because the supplier of our slaves told us that their SII information
> will
> never fit in the slave (the SII binary is 3kb and the slave only has a
> 2kb
> memory location) and we're stuck with 14 of them I've cleaned up the
> hack to
> read the SII information from a binary file and made it work in
> combination
> with other slaves. If someone is interested I can make a patch to the
> most
> recent master code.
>
> I've adjusted the fsm_slave_scan state machine to works as follows
>
> - Read vendor id + product code from slave
> - Use the kernels firmware_request to load
> ec_${vendor_id}_${product_code}.bin
> /lib/firmware/${uname -r}/ethercat (or whatever path your distribution
> uses)
>
> If firmware is found,
> use that to load the SII information
> else
> read SII information from the slave
>
>
> I think this can be used as starting point for reading XML files. I'm
> thinking
> of the following solutions
>
> - Make a separate user space program that compiles the XML files to SII
> binaries and stores them in /lib/firmware
> - Store the XML file in /lib/firmware and parse it in the master module
> - Create a separate communication between the kernel and user space that
>
> requests slave information from a daemon/udev.
>
> Maybe someone on this list can voice their opinion what would be the
> neatest
> way to do it.
>
>
> Regards,
>
> Jesperdiff -rup ethercat-default.orig/master/fsm_master.c ethercat-default/master/fsm_master.c
--- ethercat-default.orig/master/fsm_master.c 2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_master.c 2011-10-27 10:45:40.000000000 -0500
@@ -100,7 +100,7 @@ void ec_fsm_master_init(
ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram,
&fsm->fsm_change, &fsm->fsm_coe, &fsm->fsm_pdo);
ec_fsm_slave_scan_init(&fsm->fsm_slave_scan, fsm->datagram,
- &fsm->fsm_slave_config, &fsm->fsm_pdo);
+ &fsm->fsm_slave_config, &fsm->fsm_pdo, &fsm->master->class_device);
ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
}
@@ -332,6 +332,7 @@ int ec_fsm_master_action_process_sii(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
+
ec_master_t *master = fsm->master;
ec_sii_write_request_t *request;
diff -rup ethercat-default.orig/master/fsm_slave_scan.c ethercat-default/master/fsm_slave_scan.c
--- ethercat-default.orig/master/fsm_slave_scan.c 2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_slave_scan.c 2011-10-26 17:56:48.000000000 -0500
@@ -34,6 +34,7 @@
/*****************************************************************************/
+#include <linux/firmware.h>
#include "globals.h"
#include "master.h"
#include "mailbox.h"
@@ -50,8 +51,11 @@ void ec_fsm_slave_scan_state_base(ec_fsm
void ec_fsm_slave_scan_state_dc_cap(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_dc_times(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_device(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_request(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_parse(ec_fsm_slave_scan_t *);
#ifdef EC_REGALIAS
void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *);
#endif
@@ -78,12 +82,18 @@ void ec_fsm_slave_scan_init(
ec_datagram_t *datagram, /**< Datagram to use. */
ec_fsm_slave_config_t *fsm_slave_config, /**< Slave configuration
state machine to use. */
- ec_fsm_pdo_t *fsm_pdo /**< PDO configuration machine to use. */
+ ec_fsm_pdo_t *fsm_pdo, /**< PDO configuration machine to use. */
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ struct device **class_device /**< Master class device. */
+ #else
+ struct class_device **class_device /**< Master class device. */
+ #endif
)
{
fsm->datagram = datagram;
fsm->fsm_slave_config = fsm_slave_config;
fsm->fsm_pdo = fsm_pdo;
+ fsm->class_device = class_device;
// init sub state machines
ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
@@ -480,16 +490,142 @@ void ec_fsm_slave_scan_state_datalink(ec
// Start fetching SII size
- fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
- ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
- EC_FSM_SII_USE_CONFIGURED_ADDRESS);
- fsm->state = ec_fsm_slave_scan_state_sii_size;
+ if (slave->vendor_words) {
+ EC_SLAVE_WARN(slave, "Freeing old vendor data...\n");
+ kfree(slave->vendor_words);
+ }
+
+ if (!(slave->vendor_words =
+ (uint16_t *) kmalloc(32, GFP_KERNEL))) {
+ EC_SLAVE_ERR(slave, "Failed to allocate 16 words of SII data.\n");
+ slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_scan_state_error;
+ return;
+ }
+ fsm->sii_offset = 0;
+ ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+ EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+ fsm->state = ec_fsm_slave_scan_state_sii_device;
+
fsm->state(fsm); // execute state immediately
}
/*****************************************************************************/
/**
+ Slave scan state: SII Device
+ */
+
+
+void ec_fsm_slave_scan_state_sii_device(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+ ec_slave_t *slave = fsm->slave;
+ if (ec_fsm_sii_exec(&fsm->fsm_sii))
+ return;
+
+ if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
+ fsm->slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_scan_state_error;
+ EC_SLAVE_ERR(slave, "Failed to determine product and vendor ID:"
+ " Reading word offset 0x%04x failed. \n",
+ fsm->sii_offset);
+ return;
+ }
+
+ memcpy(slave->vendor_words + fsm->sii_offset, fsm->fsm_sii.value, 4);
+
+ if (fsm->sii_offset + 2 < 16) {
+ // fetch the next 2 words
+ fsm->sii_offset += 2;
+ ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+ EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+ ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
+ return;
+ }
+
+ // Evaluate SII contents
+ slave->sii.alias =
+ EC_READ_U16(slave->vendor_words + 0x0004);
+ slave->effective_alias = slave->sii.alias;
+ slave->sii.vendor_id =
+ EC_READ_U32(slave->vendor_words + 0x0008);
+ slave->sii.product_code =
+ EC_READ_U32(slave->vendor_words + 0x000A);
+ slave->sii.revision_number =
+ EC_READ_U32(slave->vendor_words + 0x000C);
+ slave->sii.serial_number =
+ EC_READ_U32(slave->vendor_words + 0x000E);
+
+
+ fsm->state = ec_fsm_slave_scan_state_sii_request;
+
+}
+
+/*****************************************************************************/
+
+/**
+ Slave scan state: SII REQUEST.
+*/
+
+void ec_fsm_slave_scan_state_sii_request(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+ ec_slave_t *slave = fsm->slave;
+ const struct firmware *firmware;
+
+ char buffer[48];
+ sprintf(buffer, "ethercat/ec_%08x_%08x.bin", slave->sii.vendor_id, slave->sii.product_code);
+
+ EC_SLAVE_DBG(slave, 1, "Trying to load SII firmware: %s", buffer);
+
+ if(!*(fsm->class_device))
+ {
+ EC_SLAVE_ERR(slave, "Cannot acces master device");
+ fsm->state = ec_fsm_slave_scan_state_error;
+ return;
+ }
+ if (request_firmware(&firmware, buffer, *(fsm->class_device)) == 0)
+ {
+ EC_SLAVE_DBG(slave, 1, "Firmware file found, reading %zu bytes.\n", firmware->size);
+ // Load firmware from file
+ slave->sii_nwords = firmware->size/2;
+
+
+ if (slave->sii_words) {
+ EC_SLAVE_WARN(slave, "Freeing old SII data...\n");
+ kfree(slave->sii_words);
+ }
+
+ if (!(slave->sii_words =
+ (uint16_t *) kmalloc(slave->sii_nwords * 2, GFP_KERNEL))) {
+ EC_SLAVE_ERR(slave, "Failed to allocate %zu words of SII data.\n",
+ slave->sii_nwords);
+ slave->sii_nwords = 0;
+ slave->error_flag = 1;
+ fsm->state = ec_fsm_slave_scan_state_error;
+ return;
+ }
+
+ memcpy(slave->sii_words, firmware->data, slave->sii_nwords*2);
+ fsm->state = ec_fsm_slave_scan_state_sii_parse;
+
+ release_firmware(firmware);
+ }
+ else
+ {
+ EC_SLAVE_DBG(slave, 1, "SII firmware file not found, reading SII data from slave.\n");
+ // Read firmware from device
+ fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
+ ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+ EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+ fsm->state = ec_fsm_slave_scan_state_sii_size;
+ }
+}
+
+
+/*****************************************************************************/
+
+/**
Slave scan state: SII SIZE.
*/
@@ -513,7 +649,6 @@ void ec_fsm_slave_scan_state_sii_size(ec
cat_type = EC_READ_U16(fsm->fsm_sii.value);
cat_size = EC_READ_U16(fsm->fsm_sii.value + 2);
-
if (cat_type != 0xFFFF) { // not the last category
off_t next_offset = 2UL + fsm->sii_offset + cat_size;
if (next_offset >= EC_MAX_SII_SIZE) {
@@ -551,10 +686,15 @@ alloc_sii:
// Start fetching SII contents
fsm->state = ec_fsm_slave_scan_state_sii_data;
- fsm->sii_offset = 0x0000;
+ fsm->sii_offset = 0x0016;
+
+ // Copy vendor data to sii_words
+ memcpy(slave->sii_words, slave->vendor_words, 32);
+
ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
EC_FSM_SII_USE_CONFIGURED_ADDRESS);
ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
}
/*****************************************************************************/
@@ -566,10 +706,10 @@ alloc_sii:
void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
{
ec_slave_t *slave = fsm->slave;
- uint16_t *cat_word, cat_type, cat_size;
if (ec_fsm_sii_exec(&fsm->fsm_sii)) return;
+
if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
fsm->slave->error_flag = 1;
fsm->state = ec_fsm_slave_scan_state_error;
@@ -591,24 +731,28 @@ void ec_fsm_slave_scan_state_sii_data(ec
ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
EC_FSM_SII_USE_CONFIGURED_ADDRESS);
ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
+
return;
}
+ fsm->state = ec_fsm_slave_scan_state_sii_parse;
+}
+/*****************************************************************************/
+
+/**
+ Slave scan state: SII PARSE.
+*/
+
+void ec_fsm_slave_scan_state_sii_parse(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+ ec_slave_t *slave = fsm->slave;
+ uint16_t *cat_word, cat_type, cat_size;
+
// Evaluate SII contents
ec_slave_clear_sync_managers(slave);
- slave->sii.alias =
- EC_READ_U16(slave->sii_words + 0x0004);
- slave->effective_alias = slave->sii.alias;
- slave->sii.vendor_id =
- EC_READ_U32(slave->sii_words + 0x0008);
- slave->sii.product_code =
- EC_READ_U32(slave->sii_words + 0x000A);
- slave->sii.revision_number =
- EC_READ_U32(slave->sii_words + 0x000C);
- slave->sii.serial_number =
- EC_READ_U32(slave->sii_words + 0x000E);
slave->sii.boot_rx_mailbox_offset =
EC_READ_U16(slave->sii_words + 0x0014);
slave->sii.boot_rx_mailbox_size =
Only in ethercat-default/master: fsm_slave_scan.c.orig
diff -rup ethercat-default.orig/master/fsm_slave_scan.h ethercat-default/master/fsm_slave_scan.h
--- ethercat-default.orig/master/fsm_slave_scan.h 2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_slave_scan.h 2011-10-26 17:00:36.000000000 -0500
@@ -37,6 +37,7 @@
#ifndef __EC_FSM_SLAVE_SCAN_H__
#define __EC_FSM_SLAVE_SCAN_H__
+#include <linux/device.h>
#include "globals.h"
#include "datagram.h"
#include "slave.h"
@@ -50,6 +51,7 @@
/** \see ec_fsm_slave_scan */
typedef struct ec_fsm_slave_scan ec_fsm_slave_scan_t;
+
/** Finite state machine for scanning an EtherCAT slave.
*/
struct ec_fsm_slave_scan
@@ -65,12 +67,24 @@ struct ec_fsm_slave_scan
uint16_t sii_offset; /**< SII offset in words. */
ec_fsm_sii_t fsm_sii; /**< SII state machine. */
+
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ struct device **class_device; /**< Master class device. */
+ #else
+ struct class_device **class_device; /**< Master class device. */
+ #endif
};
/*****************************************************************************/
void ec_fsm_slave_scan_init(ec_fsm_slave_scan_t *, ec_datagram_t *,
- ec_fsm_slave_config_t *, ec_fsm_pdo_t *);
+ ec_fsm_slave_config_t *, ec_fsm_pdo_t *,
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ struct device **
+ #else
+ struct class_device **
+ #endif
+ );
void ec_fsm_slave_scan_clear(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_start(ec_fsm_slave_scan_t *, ec_slave_t *);
Only in ethercat-default/master: Makefile.in
diff -rup ethercat-default.orig/master/slave.c ethercat-default/master/slave.c
--- ethercat-default.orig/master/slave.c 2011-10-28 09:34:58.000000000 -0500
+++ ethercat-default/master/slave.c 2011-10-26 14:25:00.000000000 -0500
@@ -110,6 +110,7 @@ void ec_slave_init(
slave->has_dc_system_time = 0;
slave->transmission_delay = 0U;
+ slave->vendor_words = NULL;
slave->sii_words = NULL;
slave->sii_nwords = 0;
@@ -253,8 +254,12 @@ void ec_slave_clear(ec_slave_t *slave /*
kfree(pdo);
}
+ if (slave->vendor_words)
+ kfree(slave->vendor_words);
+
if (slave->sii_words)
kfree(slave->sii_words);
+
ec_fsm_slave_clear(&slave->fsm);
ec_datagram_clear(&slave->fsm_datagram);
}
diff -rup ethercat-default.orig/master/slave.h ethercat-default/master/slave.h
--- ethercat-default.orig/master/slave.h 2011-10-28 09:34:58.000000000 -0500
+++ ethercat-default/master/slave.h 2011-10-26 14:20:07.000000000 -0500
@@ -255,6 +255,7 @@ struct ec_slave
(offset from reference clock). */
// SII
+ uint16_t *vendor_words; /**< First 16 words of SII image. */
uint16_t *sii_words; /**< Complete SII image. */
size_t sii_nwords; /**< Size of the SII contents in words. */
Only in ethercat-default/master: .svn
_______________________________________________
etherlab-users mailing list
[email protected]
http://lists.etherlab.org/mailman/listinfo/etherlab-users