master/master.c
changeset 144 fdc24bf62f80
parent 140 b09658e50d6f
child 145 11a82e4fd31b
--- a/master/master.c	Sun Apr 02 09:26:56 2006 +0000
+++ b/master/master.c	Mon Apr 03 10:03:34 2006 +0000
@@ -33,9 +33,12 @@
     master->slaves = NULL;
     master->device = NULL;
 
-    INIT_LIST_HEAD(&master->commands);
+    INIT_LIST_HEAD(&master->command_queue);
     INIT_LIST_HEAD(&master->domains);
 
+    ec_command_init(&master->simple_command);
+    ec_command_init(&master->watch_command);
+
     ec_master_reset(master);
 }
 
@@ -56,6 +59,9 @@
         ec_device_clear(master->device);
         kfree(master->device);
     }
+
+    ec_command_clear(&master->simple_command);
+    ec_command_clear(&master->watch_command);
 }
 
 /*****************************************************************************/
@@ -72,8 +78,8 @@
                      )
 {
     unsigned int i;
-    ec_command_t *command, *next_command;
-    ec_domain_t *domain, *next_domain;
+    ec_command_t *command, *next_c;
+    ec_domain_t *domain, *next_d;
 
     // Alle Slaves entfernen
     if (master->slaves) {
@@ -86,13 +92,13 @@
     master->slave_count = 0;
 
     // Kommando-Warteschlange leeren
-    list_for_each_entry_safe(command, next_command, &master->commands, list) {
+    list_for_each_entry_safe(command, next_c, &master->command_queue, queue) {
         command->state = EC_CMD_ERROR;
-        list_del_init(&command->list);
+        list_del_init(&command->queue);
     }
 
     // Domain-Liste leeren
-    list_for_each_entry_safe(domain, next_domain, &master->domains, list) {
+    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
         list_del(&domain->list);
         ec_domain_clear(domain);
         kfree(domain);
@@ -166,7 +172,7 @@
     ec_command_t *queued_command;
 
     // Ist das Kommando schon in der Warteschlange?
-    list_for_each_entry(queued_command, &master->commands, list) {
+    list_for_each_entry(queued_command, &master->command_queue, queue) {
         if (queued_command == command) {
             command->state = EC_CMD_QUEUED;
             if (unlikely(master->debug_level))
@@ -175,7 +181,7 @@
         }
     }
 
-    list_add_tail(&command->list, &master->commands);
+    list_add_tail(&command->queue, &master->command_queue);
     command->state = EC_CMD_QUEUED;
 }
 
@@ -206,7 +212,7 @@
     follows_word = NULL;
 
     // Aktuellen Frame mit Kommandos füllen
-    list_for_each_entry(command, &master->commands, list) {
+    list_for_each_entry(command, &master->command_queue, queue) {
         if (command->state != EC_CMD_QUEUED) continue;
 
         // Passt das aktuelle Kommando noch in den aktuellen Rahmen?
@@ -238,7 +244,7 @@
         cur_data += command->data_size;
 
         // EtherCAT command footer
-        EC_WRITE_U16(cur_data, command->working_counter);
+        EC_WRITE_U16(cur_data, 0x0000); // Working counter
         cur_data += EC_COMMAND_FOOTER_SIZE;
     }
 
@@ -323,7 +329,7 @@
 
         // Suche passendes Kommando in der Liste
         matched = 0;
-        list_for_each_entry(command, &master->commands, list) {
+        list_for_each_entry(command, &master->command_queue, queue) {
             if (command->state == EC_CMD_SENT
                 && command->type == command_type
                 && command->index == command_index
@@ -349,9 +355,9 @@
         command->working_counter = EC_READ_U16(cur_data);
         cur_data += EC_COMMAND_FOOTER_SIZE;
 
-        // Kommando aus der Liste entfernen
+        // Kommando aus der Warteschlange entfernen
         command->state = EC_CMD_RECEIVED;
-        list_del_init(&command->list);
+        list_del_init(&command->queue);
     }
 }
 
@@ -366,13 +372,13 @@
    \return 0 bei Erfolg, sonst < 0
 */
 
-int ec_master_simple_io(ec_master_t *master, /**< EtherCAT-Master */
-                        ec_command_t *command /**< Kommando */
-                        )
+int ec_master_simple_io(ec_master_t *master /**< EtherCAT-Master */)
 {
     unsigned int response_tries_left;
+    ec_command_t *command;
 
     response_tries_left = 10;
+    command = &master->simple_command;
 
     while (1)
     {
@@ -415,21 +421,22 @@
 
 int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
 {
-    ec_command_t command;
     ec_slave_t *slave;
     ec_slave_ident_t *ident;
     unsigned int i;
-    uint8_t data[2];
+    ec_command_t *command;
 
     if (master->slaves || master->slave_count) {
         EC_ERR("Slave scan already done!\n");
         return -1;
     }
 
+    command = &master->simple_command;
+
     // Determine number of slaves on bus
-    ec_command_init_brd(&command, 0x0000, 4);
-    if (unlikely(ec_master_simple_io(master, &command))) return -1;
-    master->slave_count = command.working_counter;
+    if (ec_command_brd(command, 0x0000, 4)) return -1;
+    if (unlikely(ec_master_simple_io(master))) return -1;
+    master->slave_count = command->working_counter;
     EC_INFO("Found %i slaves on bus.\n", master->slave_count);
 
     if (!master->slave_count) return 0;
@@ -455,10 +462,10 @@
         slave = master->slaves + i;
 
         // Write station address
-        EC_WRITE_U16(data, slave->station_address);
-        ec_command_init_apwr(&command, slave->ring_position,
-                             0x0010, sizeof(uint16_t), data);
-        if (unlikely(ec_master_simple_io(master, &command))) {
+        if (ec_command_apwr(command, slave->ring_position,
+                            0x0010, sizeof(uint16_t))) return -1;
+        EC_WRITE_U16(command->data, slave->station_address);
+        if (unlikely(ec_master_simple_io(master))) {
             EC_ERR("Writing station address failed on slave %i!\n", i);
             return -1;
         }
@@ -713,6 +720,8 @@
 {
     unsigned int first;
 
+    if (unlikely(master->watch_command.state == EC_CMD_INIT)) return;
+
     first = 1;
 
     if (master->watch_command.working_counter != master->slaves_responding ||
@@ -789,15 +798,21 @@
 {
     unsigned int i, j;
     ec_slave_t *slave;
-    ec_command_t command;
+    ec_command_t *command;
     const ec_sync_t *sync;
     const ec_slave_type_t *type;
     const ec_fmmu_t *fmmu;
-    uint8_t data[256];
     uint32_t domain_offset;
     ec_domain_t *domain;
     ec_eeprom_sync_t *eeprom_sync;
 
+    command = &master->simple_command;
+
+    if (ec_command_brd(&master->watch_command, 0x130, 2)) {
+        EC_ERR("Failed to allocate watchdog command!\n");
+        return -1;
+    }
+
     // Domains erstellen
     domain_offset = 0;
     list_for_each_entry(domain, &master->domains, list) {
@@ -826,10 +841,11 @@
 
         // Resetting FMMUs
         if (slave->base_fmmu_count) {
-            memset(data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
-            ec_command_init_npwr(&command, slave->station_address, 0x0600,
-                                 EC_FMMU_SIZE * slave->base_fmmu_count, data);
-            if (unlikely(ec_master_simple_io(master, &command))) {
+            if (ec_command_npwr(command, slave->station_address, 0x0600,
+                                EC_FMMU_SIZE * slave->base_fmmu_count))
+                return -1;
+            memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
+            if (unlikely(ec_master_simple_io(master))) {
                 EC_ERR("Resetting FMMUs failed on slave %i!\n",
                        slave->ring_position);
                 return -1;
@@ -838,10 +854,11 @@
 
         // Resetting Sync Manager channels
         if (slave->base_sync_count) {
-            memset(data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
-            ec_command_init_npwr(&command, slave->station_address, 0x0800,
-                                 EC_SYNC_SIZE * slave->base_sync_count, data);
-            if (unlikely(ec_master_simple_io(master, &command))) {
+            if (ec_command_npwr(command, slave->station_address, 0x0800,
+                                EC_SYNC_SIZE * slave->base_sync_count))
+                return -1;
+            memset(command->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
+            if (unlikely(ec_master_simple_io(master))) {
                 EC_ERR("Resetting sync managers failed on slave %i!\n",
                        slave->ring_position);
                 return -1;
@@ -853,11 +870,11 @@
             for (j = 0; type->sync_managers[j] && j < EC_MAX_SYNC; j++)
             {
                 sync = type->sync_managers[j];
-                ec_sync_config(sync, data);
-                ec_command_init_npwr(&command, slave->station_address,
-                                     0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE,
-                                     data);
-                if (unlikely(ec_master_simple_io(master, &command))) {
+                if (ec_command_npwr(command, slave->station_address,
+                                    0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE))
+                    return -1;
+                ec_sync_config(sync, command->data);
+                if (unlikely(ec_master_simple_io(master))) {
                     EC_ERR("Setting sync manager %i failed on slave %i!\n",
                            j, slave->ring_position);
                     return -1;
@@ -866,11 +883,11 @@
         }
         else if (slave->sii_mailbox_protocols) { // Unknown slave, has mailbox
             list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) {
-                ec_eeprom_sync_config(eeprom_sync, data);
-                ec_command_init_npwr(&command, slave->station_address,
-                                     0x800 + eeprom_sync->index * EC_SYNC_SIZE,
-                                     EC_SYNC_SIZE, data);
-                if (unlikely(ec_master_simple_io(master, &command))) {
+                if (ec_command_npwr(command, slave->station_address,
+                                    0x800 + eeprom_sync->index * EC_SYNC_SIZE,
+                                    EC_SYNC_SIZE)) return -1;
+                ec_eeprom_sync_config(eeprom_sync, command->data);
+                if (unlikely(ec_master_simple_io(master))) {
                     EC_ERR("Setting sync manager %i failed on slave %i!\n",
                            eeprom_sync->index, slave->ring_position);
                     return -1;
@@ -896,12 +913,11 @@
         for (j = 0; j < slave->fmmu_count; j++)
         {
             fmmu = &slave->fmmus[j];
-
-            ec_fmmu_config(fmmu, data);
-            ec_command_init_npwr(&command, slave->station_address,
-                                 0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE,
-                                 data);
-            if (unlikely(ec_master_simple_io(master, &command))) {
+            if (ec_command_npwr(command, slave->station_address,
+                                0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE))
+                return -1;
+            ec_fmmu_config(fmmu, command->data);
+            if (unlikely(ec_master_simple_io(master))) {
                 EC_ERR("Setting FMMU %i failed on slave %i!\n",
                        j, slave->ring_position);
                 return -1;
@@ -980,31 +996,17 @@
 
 void ecrt_master_sync_io(ec_master_t *master)
 {
-    ec_command_t *command, *next;
+    ec_command_t *command, *n;
     unsigned int commands_sent;
     cycles_t t_start, t_end, t_timeout;
 
-    ec_master_output_stats(master);
-
-    if (unlikely(!master->device->link_state)) {
-        // Link DOWN, keines der Kommandos kann gesendet werden.
-        list_for_each_entry_safe(command, next, &master->commands, list) {
-            command->state = EC_CMD_ERROR;
-            list_del_init(&command->list);
-        }
-
-        // Device-Zustand abfragen
-        ec_device_call_isr(master->device);
-        return;
-    }
-
-    // Rahmen senden
-    ec_master_send_commands(master);
+    // Kommandos senden
+    ecrt_master_async_send(master);
 
     t_start = get_cycles(); // Sendezeit nehmen
     t_timeout = (cycles_t) master->timeout * (cpu_khz / 1000);
 
-    while (1)
+    while (1) // Aktiv auf Empfang warten
     {
         ec_device_call_isr(master->device);
 
@@ -1012,9 +1014,9 @@
         if (t_end - t_start >= t_timeout) break; // Timeout
 
         commands_sent = 0;
-        list_for_each_entry_safe(command, next, &master->commands, list) {
+        list_for_each_entry_safe(command, n, &master->command_queue, queue) {
             if (command->state == EC_CMD_RECEIVED)
-                list_del_init(&command->list);
+                list_del_init(&command->queue);
             else if (command->state == EC_CMD_SENT)
                 commands_sent++;
         }
@@ -1023,7 +1025,7 @@
     }
 
     // Zeit abgelaufen. Alle verbleibenden Kommandos entfernen.
-    list_for_each_entry_safe(command, next, &master->commands, list) {
+    list_for_each_entry_safe(command, n, &master->command_queue, queue) {
         switch (command->state) {
             case EC_CMD_SENT:
             case EC_CMD_QUEUED:
@@ -1038,7 +1040,7 @@
             default:
                 break;
         }
-        list_del_init(&command->list);
+        list_del_init(&command->queue);
     }
 }
 
@@ -1050,15 +1052,13 @@
 
 void ecrt_master_async_send(ec_master_t *master)
 {
-    ec_command_t *command, *next;
-
-    ec_master_output_stats(master);
+    ec_command_t *command, *n;
 
     if (unlikely(!master->device->link_state)) {
         // Link DOWN, keines der Kommandos kann gesendet werden.
-        list_for_each_entry_safe(command, next, &master->commands, list) {
+        list_for_each_entry_safe(command, n, &master->command_queue, queue) {
             command->state = EC_CMD_ERROR;
-            list_del_init(&command->list);
+            list_del_init(&command->queue);
         }
 
         // Device-Zustand abfragen
@@ -1066,10 +1066,6 @@
         return;
     }
 
-    // Watch-Kommando hinzufügen
-    ec_command_init_brd(&master->watch_command, 0x130, 2);
-    ec_master_queue_command(master, &master->watch_command);
-
     // Rahmen senden
     ec_master_send_commands(master);
 }
@@ -1087,12 +1083,11 @@
     ec_device_call_isr(master->device);
 
     // Alle empfangenen Kommandos aus der Liste entfernen
-    list_for_each_entry_safe(command, next, &master->commands, list)
-        if (command->state == EC_CMD_RECEIVED)
-            list_del_init(&command->list);
+    list_for_each_entry_safe(command, next, &master->command_queue, queue)
+        if (command->state == EC_CMD_RECEIVED) list_del_init(&command->queue);
 
     // Alle verbleibenden Kommandos entfernen.
-    list_for_each_entry_safe(command, next, &master->commands, list) {
+    list_for_each_entry_safe(command, next, &master->command_queue, queue) {
         switch (command->state) {
             case EC_CMD_SENT:
             case EC_CMD_QUEUED:
@@ -1103,14 +1098,8 @@
             default:
                 break;
         }
-        list_del_init(&command->list);
-    }
-
-    // Watch-Kommando verarbeiten
-    ec_master_process_watch_command(master);
-
-    // Statistiken ausgeben
-    ec_master_output_stats(master);
+        list_del_init(&command->queue);
+    }
 }
 
 /*****************************************************************************/
@@ -1128,7 +1117,7 @@
     ec_domain_t *domain;
     cycles_t t_start, t_end, t_timeout;
 
-    // Alle empfangenen Kommandos aus der Liste entfernen
+    // Kommandos aller Domains in die Warteschlange setzen
     list_for_each_entry(domain, &master->domains, list)
         ecrt_domain_queue(domain);
 
@@ -1147,6 +1136,22 @@
 /*****************************************************************************/
 
 /**
+   Führt Routinen im zyklischen Betrieb aus.
+*/
+
+void ecrt_master_run(ec_master_t *master /**< EtherCAT-Master */)
+{
+    // Statistiken ausgeben
+    ec_master_output_stats(master);
+
+    // Watchdog-Kommando
+    ec_master_process_watch_command(master);
+    ec_master_queue_command(master, &master->watch_command);
+}
+
+/*****************************************************************************/
+
+/**
    Setzt die Debug-Ebene des Masters.
 
    Folgende Debug-Level sind definiert:
@@ -1198,6 +1203,7 @@
 EXPORT_SYMBOL(ecrt_master_sync_io);
 EXPORT_SYMBOL(ecrt_master_async_send);
 EXPORT_SYMBOL(ecrt_master_async_receive);
+EXPORT_SYMBOL(ecrt_master_run);
 EXPORT_SYMBOL(ecrt_master_debug);
 EXPORT_SYMBOL(ecrt_master_print);
 EXPORT_SYMBOL(ecrt_master_get_slave);