Implemented going to bootstrap state BOOT. 1.4-foe
authorFlorian Pose <fp@igh-essen.com>
Mon, 19 Jan 2009 14:46:55 +0000
branch1.4-foe
changeset 1709 63e4bc918640
parent 1708 fae3a1759126
child 1710 4522459bb5a4
Implemented going to bootstrap state BOOT.
NEWS
master/cdev.c
master/ethernet.c
master/fsm_change.c
master/fsm_coe.c
master/fsm_foe.c
master/fsm_master.c
master/fsm_slave_config.c
master/fsm_slave_scan.c
master/globals.h
master/ioctl.h
master/mailbox.c
master/module.c
master/slave.c
master/slave.h
tool/Command.cpp
tool/CommandSlaves.cpp
tool/CommandStates.cpp
--- a/NEWS	Mon Jan 19 12:36:18 2009 +0000
+++ b/NEWS	Mon Jan 19 14:46:55 2009 +0000
@@ -6,6 +6,12 @@
 
 -------------------------------------------------------------------------------
 
+Changes since 1.4.0:
+
+* Implemented the File Access over EtherCAT (FoE) mailbox protocol.
+* Going to the Bootstrap state is now supported by the state machines and the
+  command-line tool.
+
 Changes in version 1.4.0:
 
 * Fixed race condition in jiffy-based frame timeout calculation.
--- a/master/cdev.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/cdev.c	Mon Jan 19 14:46:55 2009 +0000
@@ -188,10 +188,14 @@
     data.revision_number = slave->sii.revision_number;
     data.serial_number = slave->sii.serial_number;
     data.alias = slave->sii.alias;
-    data.rx_mailbox_offset = slave->sii.rx_mailbox_offset;
-    data.rx_mailbox_size = slave->sii.rx_mailbox_size;
-    data.tx_mailbox_offset = slave->sii.tx_mailbox_offset;
-    data.tx_mailbox_size = slave->sii.tx_mailbox_size;
+    data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset;
+    data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size;
+    data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+    data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size;
+    data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset;
+    data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size;
+    data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset;
+    data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size;
     data.mailbox_protocols = slave->sii.mailbox_protocols;
     data.has_general_category = slave->sii.has_general;
     data.coe_details = slave->sii.coe_details;
--- a/master/ethernet.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/ethernet.c	Mon Jan 19 14:46:55 2009 +0000
@@ -217,6 +217,7 @@
 
 /**
    Sends a frame or the next fragment.
+   \todo bootstrap mailboxes / use configured mailbox sizes
 */
 
 int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */)
@@ -230,12 +231,11 @@
 
     remaining_size = eoe->tx_frame->skb->len - eoe->tx_offset;
 
-    if (remaining_size <= eoe->slave->sii.tx_mailbox_size - 10) {
+    if (remaining_size <= eoe->slave->sii.std_tx_mailbox_size - 10) {
         current_size = remaining_size;
         last_fragment = 1;
-    }
-    else {
-        current_size = ((eoe->slave->sii.tx_mailbox_size - 10) / 32) * 32;
+    } else {
+        current_size = ((eoe->slave->sii.std_tx_mailbox_size - 10) / 32) * 32;
         last_fragment = 0;
     }
 
--- a/master/fsm_change.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_change.c	Mon Jan 19 14:46:55 2009 +0000
@@ -187,7 +187,7 @@
     if (datagram->working_counter == 0) {
         if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
             char state_str[EC_STATE_STRING_SIZE];
-            ec_state_string(fsm->requested_state, state_str);
+            ec_state_string(fsm->requested_state, state_str, 0);
             fsm->state = ec_fsm_change_state_error;
             EC_ERR("Failed to set state %s on slave %u: ",
                     state_str, fsm->slave->ring_position);
@@ -204,7 +204,7 @@
 
     if (unlikely(datagram->working_counter > 1)) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, state_str);
+        ec_state_string(fsm->requested_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Failed to set state %s on slave %u: ",
                 state_str, fsm->slave->ring_position);
@@ -246,7 +246,7 @@
 
     if (datagram->working_counter != 1) {
         char req_state[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, req_state);
+        ec_state_string(fsm->requested_state, req_state, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Failed to check state %s on slave %u: ",
                req_state, slave->ring_position);
@@ -270,7 +270,7 @@
     if (slave->current_state != fsm->old_state) { // state changed
         char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
 
-        ec_state_string(slave->current_state, cur_state);
+        ec_state_string(slave->current_state, cur_state, 0);
 
         if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
             // Slave spontaneously changed its state just before the new state
@@ -286,7 +286,7 @@
         // state change error
 
         slave->error_flag = 1;
-        ec_state_string(fsm->requested_state, req_state);
+        ec_state_string(fsm->requested_state, req_state, 0);
 
         EC_ERR("Failed to set %s state, slave %u refused state change (%s).\n",
                req_state, slave->ring_position, cur_state);
@@ -302,7 +302,7 @@
     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
         // timeout while checking
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(fsm->requested_state, state_str);
+        ec_state_string(fsm->requested_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Timeout while setting state %s on slave %u.\n",
                 state_str, slave->ring_position);
@@ -323,7 +323,7 @@
 
 const ec_code_msg_t al_status_messages[] = {
     {0x0001, "Unspecified error"},
-    {0x0011, "Invalud requested state change"},
+    {0x0011, "Invalid requested state change"},
     {0x0012, "Unknown requested state"},
     {0x0013, "Bootstrap not supported"},
     {0x0014, "No valid firmware"},
@@ -494,7 +494,7 @@
 
     if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
             fsm->state = ec_fsm_change_state_error;
         }
@@ -509,7 +509,7 @@
     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
         // timeout while checking
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         fsm->state = ec_fsm_change_state_error;
         EC_ERR("Timeout while acknowledging state %s on slave %u.\n",
                state_str, slave->ring_position);
--- a/master/fsm_coe.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_coe.c	Mon Jan 19 14:46:55 2009 +0000
@@ -1089,7 +1089,7 @@
         }
 	}
     else { // request->data_size > 4, use normal transfer type
-	    if (slave->sii.rx_mailbox_size < 6 + 10 + request->data_size) {
+	    if (slave->sii.std_rx_mailbox_size < 6 + 10 + request->data_size) {
 	        EC_ERR("SDO fragmenting not supported yet!\n");
 	        fsm->state = ec_fsm_coe_error;
 	        return;
--- a/master/fsm_foe.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_foe.c	Mon Jan 19 14:46:55 2009 +0000
@@ -214,12 +214,13 @@
 
     remaining_size = fsm->tx_buffer_size - fsm->tx_buffer_offset;
 
-    if (remaining_size < fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE) {
+    if (remaining_size < fsm->slave->sii.std_tx_mailbox_size
+            - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE) {
         current_size = remaining_size;
         fsm->tx_last_packet = 1;
-    }
-    else {
-        current_size = fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE;
+    } else {
+        current_size = fsm->slave->sii.std_tx_mailbox_size
+            - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE;
     }
 
     if (!(data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram,
@@ -788,12 +789,12 @@
 
     fsm->rx_last_packet =
         (rec_size + EC_MBOX_HEADER_SIZE + EC_FOE_HEADER_SIZE
-         != fsm->slave->sii.rx_mailbox_size);
+         != fsm->slave->sii.std_rx_mailbox_size);
 
     if (fsm->rx_last_packet ||
-    	(slave->sii.rx_mailbox_size - EC_MBOX_HEADER_SIZE
-         - EC_FOE_HEADER_SIZE + fsm->rx_buffer_offset) <= fsm->rx_buffer_size) {
-    	// either it was the last packet or a new packet will fit into the delivered buffer
+            (slave->sii.std_rx_mailbox_size - EC_MBOX_HEADER_SIZE
+             - EC_FOE_HEADER_SIZE + fsm->rx_buffer_offset) <= fsm->rx_buffer_size) {
+        // either it was the last packet or a new packet will fit into the delivered buffer
 #ifdef	myDEBUG
     	printk ("last_packet=true\n");
 #endif
@@ -811,7 +812,7 @@
     	printk ("       rx_buffer_size  = %d\n", fsm->rx_buffer_size);
     	printk ("       rx_buffer_offset= %d\n", fsm->rx_buffer_offset);
     	printk ("       rec_size        = %d\n", rec_size);
-    	printk ("       rx_mailbox_size = %d\n", slave->sii.rx_mailbox_size);
+    	printk ("       rx_mailbox_size = %d\n", slave->sii.std_rx_mailbox_size);
     	printk ("       rx_last_packet  = %d\n", fsm->rx_last_packet);
 //    	fsm->state = ec_fsm_state_wait_next_read;
     	fsm->request->result = FOE_READY;
--- a/master/fsm_master.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_master.c	Mon Jan 19 14:46:55 2009 +0000
@@ -199,7 +199,7 @@
         if (states != fsm->slave_states) { // slave states changed?
             char state_str[EC_STATE_STRING_SIZE];
             fsm->slave_states = states;
-            ec_state_string(fsm->slave_states, state_str);
+            ec_state_string(fsm->slave_states, state_str, 1);
             EC_INFO("Slave states: %s.\n", state_str);
         }
     } else {
@@ -560,8 +560,8 @@
             if (master->debug_level) {
                 char old_state[EC_STATE_STRING_SIZE],
                      new_state[EC_STATE_STRING_SIZE];
-                ec_state_string(slave->current_state, old_state);
-                ec_state_string(slave->requested_state, new_state);
+                ec_state_string(slave->current_state, old_state, 0);
+                ec_state_string(slave->requested_state, new_state, 0);
                 EC_DBG("Changing state of slave %u from %s to %s%s.\n",
                         slave->ring_position, old_state, new_state,
                         slave->force_config ? " (forced)" : "");
--- a/master/fsm_slave_config.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_slave_config.c	Mon Jan 19 14:46:55 2009 +0000
@@ -43,7 +43,7 @@
 void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_state_preop(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_pdo_sync(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *);
@@ -53,7 +53,7 @@
 
 void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_enter_preop(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_pdo_sync(ec_fsm_slave_config_t *);
@@ -289,7 +289,7 @@
         if (master->debug_level)
             EC_DBG("Slave %u does not support mailbox communication.\n",
                     slave->ring_position);
-        ec_fsm_slave_config_enter_preop(fsm);
+        ec_fsm_slave_config_enter_boot_preop(fsm);
         return;
     }
 
@@ -298,7 +298,29 @@
                slave->ring_position);
     }
 
-    if (slave->sii.sync_count >= 2) { // mailbox configuration provided
+    if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
+        ec_sync_t sync;
+
+        ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
+                EC_SYNC_PAGE_SIZE * 2);
+        memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
+
+        ec_sync_init(&sync, slave);
+        sync.physical_start_address = slave->sii.boot_rx_mailbox_offset;
+        sync.control_register = 0x26;
+        sync.enable = 1;
+        ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
+                EC_DIR_INVALID, // use default direction
+                datagram->data);
+
+        ec_sync_init(&sync, slave);
+        sync.physical_start_address = slave->sii.boot_tx_mailbox_offset;
+        sync.control_register = 0x22;
+        sync.enable = 1;
+        ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
+                EC_DIR_INVALID, // use default direction
+                datagram->data + EC_SYNC_PAGE_SIZE);
+    } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
         ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
                 EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
         memset(datagram->data, 0x00,
@@ -323,18 +345,18 @@
         memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
 
         ec_sync_init(&sync, slave);
-        sync.physical_start_address = slave->sii.rx_mailbox_offset;
+        sync.physical_start_address = slave->sii.std_rx_mailbox_offset;
         sync.control_register = 0x26;
         sync.enable = 1;
-        ec_sync_page(&sync, 0, slave->sii.rx_mailbox_size,
+        ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
                 EC_DIR_INVALID, // use default direction
                 datagram->data);
 
         ec_sync_init(&sync, slave);
-        sync.physical_start_address = slave->sii.tx_mailbox_offset;
+        sync.physical_start_address = slave->sii.std_tx_mailbox_offset;
         sync.control_register = 0x22;
         sync.enable = 1;
-        ec_sync_page(&sync, 1, slave->sii.tx_mailbox_size,
+        ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
                 EC_DIR_INVALID, // use default direction
                 datagram->data + EC_SYNC_PAGE_SIZE);
     }
@@ -374,27 +396,33 @@
         return;
     }
 
-    ec_fsm_slave_config_enter_preop(fsm);
+    ec_fsm_slave_config_enter_boot_preop(fsm);
 }
 
 /*****************************************************************************/
 
 /** Request PREOP state.
  */
-void ec_fsm_slave_config_enter_preop(
-        ec_fsm_slave_config_t *fsm /**< slave state machine */
-        )
-{
-    fsm->state = ec_fsm_slave_config_state_preop;
-    ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP);
+void ec_fsm_slave_config_enter_boot_preop(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
+    fsm->state = ec_fsm_slave_config_state_boot_preop;
+
+    if (fsm->slave->requested_state != EC_SLAVE_STATE_BOOT) {
+        ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP);
+    } else { // BOOT
+        ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_BOOT);
+    }
+
     ec_fsm_change_exec(fsm->fsm_change); // execute immediately
 }
 
 /*****************************************************************************/
 
-/** Slave configuration state: PREOP.
- */
-void ec_fsm_slave_config_state_preop(
+/** Slave configuration state: BOOT/PREOP.
+ */
+void ec_fsm_slave_config_state_boot_preop(
         ec_fsm_slave_config_t *fsm /**< slave state machine */
         )
 {
@@ -410,11 +438,13 @@
         return;
     }
 
-    // slave is now in PREOP
+    // slave is now in BOOT/PREOP
     slave->jiffies_preop = fsm->datagram->jiffies_received;
 
     if (master->debug_level) {
-        EC_DBG("Slave %u is now in PREOP.\n", slave->ring_position);
+        EC_DBG("Slave %u is now in %s.\n", slave->ring_position,
+                slave->requested_state != EC_SLAVE_STATE_BOOT
+                ? "PREOP" : "BOOT");
     }
 
     if (slave->current_state == slave->requested_state) {
--- a/master/fsm_slave_scan.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/fsm_slave_scan.c	Mon Jan 19 14:46:55 2009 +0000
@@ -236,7 +236,7 @@
     slave->current_state = EC_READ_U8(datagram->data);
     if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
         char state_str[EC_STATE_STRING_SIZE];
-        ec_state_string(slave->current_state, state_str);
+        ec_state_string(slave->current_state, state_str, 0);
         EC_WARN("Slave %u has state error bit set (%s)!\n",
                 slave->ring_position, state_str);
     }
@@ -466,13 +466,21 @@
         EC_READ_U32(slave->sii_words + 0x000C);
     slave->sii.serial_number =
         EC_READ_U32(slave->sii_words + 0x000E);
-    slave->sii.rx_mailbox_offset =
+    slave->sii.boot_rx_mailbox_offset =
+        EC_READ_U16(slave->sii_words + 0x0014);
+    slave->sii.boot_rx_mailbox_size =
+        EC_READ_U16(slave->sii_words + 0x0015);
+    slave->sii.boot_tx_mailbox_offset =
+        EC_READ_U16(slave->sii_words + 0x0016);
+    slave->sii.boot_tx_mailbox_size =
+        EC_READ_U16(slave->sii_words + 0x0017);
+    slave->sii.std_rx_mailbox_offset =
         EC_READ_U16(slave->sii_words + 0x0018);
-    slave->sii.rx_mailbox_size =
+    slave->sii.std_rx_mailbox_size =
         EC_READ_U16(slave->sii_words + 0x0019);
-    slave->sii.tx_mailbox_offset =
+    slave->sii.std_tx_mailbox_offset =
         EC_READ_U16(slave->sii_words + 0x001A);
-    slave->sii.tx_mailbox_size =
+    slave->sii.std_tx_mailbox_size =
         EC_READ_U16(slave->sii_words + 0x001B);
     slave->sii.mailbox_protocols =
         EC_READ_U16(slave->sii_words + 0x001C);
--- a/master/globals.h	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/globals.h	Mon Jan 19 14:46:55 2009 +0000
@@ -111,6 +111,8 @@
     /**< INIT state (no mailbox communication, no IO) */
     EC_SLAVE_STATE_PREOP = 0x02,
     /**< PREOP state (mailbox communication, no IO) */
+    EC_SLAVE_STATE_BOOT = 0x03,
+    /**< Bootstrap state (mailbox communication, firmware update) */
     EC_SLAVE_STATE_SAFEOP = 0x04,
     /**< SAFEOP (mailbox communication and input update) */
     EC_SLAVE_STATE_OP = 0x08,
@@ -222,7 +224,7 @@
 
 void ec_print_data(const uint8_t *, size_t);
 void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
-size_t ec_state_string(uint8_t, char *);
+size_t ec_state_string(uint8_t, char *, uint8_t);
 ssize_t ec_mac_print(const uint8_t *, char *);
 int ec_mac_is_zero(const uint8_t *);
 
--- a/master/ioctl.h	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/ioctl.h	Mon Jan 19 14:46:55 2009 +0000
@@ -101,10 +101,14 @@
     uint32_t revision_number;
     uint32_t serial_number;
     uint16_t alias;
-    uint16_t rx_mailbox_offset;
-    uint16_t rx_mailbox_size;
-    uint16_t tx_mailbox_offset;
-    uint16_t tx_mailbox_size;
+    uint16_t boot_rx_mailbox_offset;
+    uint16_t boot_rx_mailbox_size;
+    uint16_t boot_tx_mailbox_offset;
+    uint16_t boot_tx_mailbox_size;
+    uint16_t std_rx_mailbox_offset;
+    uint16_t std_rx_mailbox_size;
+    uint16_t std_tx_mailbox_offset;
+    uint16_t std_tx_mailbox_size;
     uint16_t mailbox_protocols;
     uint8_t has_general_category;
     ec_sii_coe_details_t coe_details;
--- a/master/mailbox.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/mailbox.c	Mon Jan 19 14:46:55 2009 +0000
@@ -52,6 +52,7 @@
                                     )
 {
     size_t total_size;
+    uint16_t mailbox_offset, mailbox_size;
 
     if (unlikely(!slave->sii.mailbox_protocols)) {
         EC_ERR("Slave %u does not support mailbox communication!\n",
@@ -60,14 +61,22 @@
     }
 
     total_size = size + 6;
-    if (unlikely(total_size > slave->sii.rx_mailbox_size)) {
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_rx_mailbox_offset;
+        mailbox_size = slave->sii.std_rx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_rx_mailbox_offset;
+        mailbox_size = slave->sii.boot_rx_mailbox_size;
+    }
+
+    if (unlikely(total_size > mailbox_size)) {
         EC_ERR("Data size does not fit in mailbox!\n");
         return NULL;
     }
 
     if (ec_datagram_fpwr(datagram, slave->station_address,
-                         slave->sii.rx_mailbox_offset,
-                         slave->sii.rx_mailbox_size))
+                         mailbox_offset, mailbox_size))
         return NULL;
 
     EC_WRITE_U16(datagram->data,     size); // mailbox service data length
@@ -119,9 +128,20 @@
                                 ec_datagram_t *datagram /**< datagram */
                                 )
 {
+    uint16_t mailbox_offset, mailbox_size;
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_tx_mailbox_offset;
+        mailbox_size = slave->sii.std_tx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+        mailbox_size = slave->sii.boot_tx_mailbox_size;
+    }
+
     if (ec_datagram_fprd(datagram, slave->station_address,
-                         slave->sii.tx_mailbox_offset,
-                         slave->sii.tx_mailbox_size)) return -1;
+                         mailbox_offset, mailbox_size))
+        return -1;
+
     return 0;
 }
 
@@ -157,13 +177,22 @@
                              )
 {
     size_t data_size;
+    uint16_t mailbox_offset, mailbox_size;
+
+    if (slave->current_state != EC_SLAVE_STATE_BOOT) {
+        mailbox_offset = slave->sii.std_tx_mailbox_offset;
+        mailbox_size = slave->sii.std_tx_mailbox_size;
+    } else {
+        mailbox_offset = slave->sii.boot_tx_mailbox_offset;
+        mailbox_size = slave->sii.boot_tx_mailbox_size;
+    }
 
     data_size = EC_READ_U16(datagram->data);
 
-    if (data_size > slave->sii.tx_mailbox_size - 6) {
+    if (data_size > mailbox_size - 6) {
         EC_ERR("Corrupt mailbox response received from slave %u!\n",
                slave->ring_position);
-        ec_print_data(datagram->data, slave->sii.tx_mailbox_size);
+        ec_print_data(datagram->data, mailbox_size);
         return NULL;
     }
 
@@ -172,15 +201,16 @@
 
     if (*type == 0x00) {
         const ec_code_msg_t *mbox_msg;
-	uint16_t code = EC_READ_U16(datagram->data + 8);
+        uint16_t code = EC_READ_U16(datagram->data + 8);
 
         EC_ERR("Mailbox error response received from slave %u - ",
-               slave->ring_position);
-
-	for (mbox_msg = mbox_error_messages; mbox_msg->code; mbox_msg++) {
-            if (mbox_msg->code != code) continue;
+                slave->ring_position);
+
+        for (mbox_msg = mbox_error_messages; mbox_msg->code; mbox_msg++) {
+            if (mbox_msg->code != code)
+                continue;
             printk("Code 0x%04X: \"%s\".\n",
-                   mbox_msg->code, mbox_msg->message);
+                    mbox_msg->code, mbox_msg->message);
             break;
         }
 
--- a/master/module.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/module.c	Mon Jan 19 14:46:55 2009 +0000
@@ -357,8 +357,9 @@
 /** Prints slave states in clear text.
  */
 size_t ec_state_string(uint8_t states, /**< slave states */
-                       char *buffer /**< target buffer
+                       char *buffer, /**< target buffer
                                        (min. EC_STATE_STRING_SIZE bytes) */
+                       uint8_t multi /**< Show multi-state mask. */
                        )
 {
     off_t off = 0;
@@ -369,24 +370,42 @@
         return off;
     }
 
-    if (states & EC_SLAVE_STATE_INIT) {
-        off += sprintf(buffer + off, "INIT");
+    if (multi) { // multiple slaves
+        if (states & EC_SLAVE_STATE_INIT) {
+            off += sprintf(buffer + off, "INIT");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_PREOP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "PREOP");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_SAFEOP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "SAFEOP");
+            first = 0;
+        }
+        if (states & EC_SLAVE_STATE_OP) {
+            if (!first) off += sprintf(buffer + off, ", ");
+            off += sprintf(buffer + off, "OP");
+        }
+    } else { // single slave
+        if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_INIT) {
+            off += sprintf(buffer + off, "INIT");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_PREOP) {
+            off += sprintf(buffer + off, "PREOP");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_BOOT) {
+            off += sprintf(buffer + off, "BOOT");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_SAFEOP) {
+            off += sprintf(buffer + off, "SAFEOP");
+        } else if ((states & EC_SLAVE_STATE_MASK) == EC_SLAVE_STATE_OP) {
+            off += sprintf(buffer + off, "OP");
+        } else {
+            off += sprintf(buffer + off, "(invalid)");
+        }
         first = 0;
     }
-    if (states & EC_SLAVE_STATE_PREOP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "PREOP");
-        first = 0;
-    }
-    if (states & EC_SLAVE_STATE_SAFEOP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "SAFEOP");
-        first = 0;
-    }
-    if (states & EC_SLAVE_STATE_OP) {
-        if (!first) off += sprintf(buffer + off, ", ");
-        off += sprintf(buffer + off, "OP");
-    }
+
     if (states & EC_SLAVE_STATE_ACK_ERR) {
         if (!first) off += sprintf(buffer + off, " + ");
         off += sprintf(buffer + off, "ERROR");
--- a/master/slave.c	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/slave.c	Mon Jan 19 14:46:55 2009 +0000
@@ -90,15 +90,19 @@
     slave->sii_words = NULL;
     slave->sii_nwords = 0;
 
-    slave->sii.alias = 0;
-    slave->sii.vendor_id = 0;
-    slave->sii.product_code = 0;
-    slave->sii.revision_number = 0;
-    slave->sii.serial_number = 0;
-    slave->sii.rx_mailbox_offset = 0;
-    slave->sii.rx_mailbox_size = 0;
-    slave->sii.tx_mailbox_offset = 0;
-    slave->sii.tx_mailbox_size = 0;
+    slave->sii.alias = 0x0000;
+    slave->sii.vendor_id = 0x00000000;
+    slave->sii.product_code = 0x00000000;
+    slave->sii.revision_number = 0x00000000;
+    slave->sii.serial_number = 0x00000000;
+    slave->sii.boot_rx_mailbox_offset = 0x0000;
+    slave->sii.boot_rx_mailbox_size = 0x0000;
+    slave->sii.boot_tx_mailbox_offset = 0x0000;
+    slave->sii.boot_tx_mailbox_size = 0x0000;
+    slave->sii.std_rx_mailbox_offset = 0x0000;
+    slave->sii.std_rx_mailbox_size = 0x0000;
+    slave->sii.std_tx_mailbox_offset = 0x0000;
+    slave->sii.std_tx_mailbox_size = 0x0000;
     slave->sii.mailbox_protocols = 0;
 
     slave->sii.strings = NULL;
@@ -199,8 +203,8 @@
         if (slave->master->debug_level) {
             char old_state[EC_STATE_STRING_SIZE],
                 cur_state[EC_STATE_STRING_SIZE];
-            ec_state_string(slave->current_state, old_state);
-            ec_state_string(new_state, cur_state);
+            ec_state_string(slave->current_state, old_state, 0);
+            ec_state_string(new_state, cur_state, 0);
             EC_DBG("Slave %u: %s -> %s.\n",
                    slave->ring_position, old_state, cur_state);
         }
--- a/master/slave.h	Mon Jan 19 12:36:18 2009 +0000
+++ b/master/slave.h	Mon Jan 19 14:46:55 2009 +0000
@@ -56,10 +56,14 @@
     uint32_t product_code; /**< Vendor-specific product code. */
     uint32_t revision_number; /**< Revision number. */
     uint32_t serial_number; /**< Serial number. */
-    uint16_t rx_mailbox_offset; /**< Mailbox address (master to slave). */
-    uint16_t rx_mailbox_size; /**< Mailbox size (master to slave). */
-    uint16_t tx_mailbox_offset; /**< Mailbox address (slave to master). */
-    uint16_t tx_mailbox_size; /**< Mailbox size (slave to master). */
+    uint16_t boot_rx_mailbox_offset; /**< Bootstrap receive mailbox address. */
+    uint16_t boot_rx_mailbox_size; /**< Bootstrap receive mailbox size. */
+    uint16_t boot_tx_mailbox_offset; /**< Bootstrap transmit mailbox address. */
+    uint16_t boot_tx_mailbox_size; /**< Bootstrap transmit mailbox size. */
+    uint16_t std_rx_mailbox_offset; /**< Standard receive mailbox address. */
+    uint16_t std_rx_mailbox_size; /**< Standard receive mailbox size. */
+    uint16_t std_tx_mailbox_offset; /**< Standard transmit mailbox address. */
+    uint16_t std_tx_mailbox_size; /**< Standard transmit mailbox size. */
     uint16_t mailbox_protocols; /**< Supported mailbox protocols. */
 
     // Strings
--- a/tool/Command.cpp	Mon Jan 19 12:36:18 2009 +0000
+++ b/tool/Command.cpp	Mon Jan 19 14:46:55 2009 +0000
@@ -284,6 +284,7 @@
     switch (state) {
         case 1: return "INIT";
         case 2: return "PREOP";
+        case 3: return "BOOT";
         case 4: return "SAFEOP";
         case 8: return "OP";
         default: return "???";
--- a/tool/CommandSlaves.cpp	Mon Jan 19 12:36:18 2009 +0000
+++ b/tool/CommandSlaves.cpp	Mon Jan 19 14:46:55 2009 +0000
@@ -216,12 +216,18 @@
             list<string>::const_iterator protoIter;
 
             cout << "Mailboxes:" << endl
-                << "  RX: 0x"
-                << hex << setw(4) << si->rx_mailbox_offset << "/"
-                << dec << si->rx_mailbox_size
+               << "  Bootstrap RX: 0x"
+                << hex << setw(4) << si->boot_rx_mailbox_offset << "/"
+                << dec << si->boot_rx_mailbox_size
                 << ", TX: 0x"
-                << hex << setw(4) << si->tx_mailbox_offset << "/"
-                << dec << si->tx_mailbox_size << endl
+                << hex << setw(4) << si->boot_tx_mailbox_offset << "/"
+                << dec << si->boot_tx_mailbox_size << endl
+                << "  Standard  RX: 0x"
+                << hex << setw(4) << si->std_rx_mailbox_offset << "/"
+                << dec << si->std_rx_mailbox_size
+                << ", TX: 0x"
+                << hex << setw(4) << si->std_tx_mailbox_offset << "/"
+                << dec << si->std_tx_mailbox_size << endl
                 << "  Supported protocols: ";
 
             if (si->mailbox_protocols & EC_MBOX_AOE) {
--- a/tool/CommandStates.cpp	Mon Jan 19 12:36:18 2009 +0000
+++ b/tool/CommandStates.cpp	Mon Jan 19 14:46:55 2009 +0000
@@ -28,7 +28,7 @@
         << getBriefDescription() << endl
         << endl
         << "Arguments:" << endl
-        << "  STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'." << endl
+        << "  STATE can be 'INIT', 'PREOP', 'BOOT', 'SAFEOP', or 'OP'." << endl
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
@@ -63,6 +63,8 @@
         state = 0x01;
     } else if (stateStr == "PREOP") {
         state = 0x02;
+    } else if (stateStr == "BOOT") {
+        state = 0x03;
     } else if (stateStr == "SAFEOP") {
         state = 0x04;
     } else if (stateStr == "OP") {