--- a/master/domain.c Fri Mar 16 16:04:26 2012 +0100
+++ b/master/domain.c Fri Mar 16 18:24:29 2012 +0100
@@ -67,9 +67,11 @@
domain->data_origin = EC_ORIG_INTERNAL;
domain->logical_base_address = 0x00000000;
INIT_LIST_HEAD(&domain->datagram_pairs);
- domain->working_counter = 0x0000;
+ domain->working_counter[EC_DEVICE_MAIN] = 0x0000;
+ domain->working_counter[EC_DEVICE_BACKUP] = 0x0000;
domain->expected_working_counter = 0x0000;
domain->working_counter_changes = 0;
+ domain->redundancy_active = 0;
domain->notify_jiffies = 0;
}
@@ -351,6 +353,30 @@
return NULL;
}
+/*****************************************************************************/
+
+/** Process received data.
+ */
+int data_changed(
+ uint8_t *send_buffer,
+ const ec_datagram_t *datagram,
+ size_t offset,
+ size_t size
+ )
+{
+ uint8_t *sent = send_buffer + offset;
+ uint8_t *recv = datagram->data + offset;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (recv[i] != sent[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/******************************************************************************
* Application interface
*****************************************************************************/
@@ -417,98 +443,118 @@
void ecrt_domain_process(ec_domain_t *domain)
{
- uint16_t working_counter_sum;
- ec_datagram_pair_t *datagram_pair = NULL;
- ec_fmmu_config_t *fmmu;
+ uint16_t wc_sum[EC_NUM_DEVICES] = {};
+ ec_datagram_pair_t *pair;
+ ec_datagram_t *main_datagram, *backup_datagram;
uint32_t logical_datagram_address;
- unsigned int datagram_offset, datagram_pair_wc = 0;
size_t datagram_size;
- ec_datagram_t *main_datagram;
+ uint16_t datagram_pair_wc;
+ unsigned int datagram_offset;
+ ec_fmmu_config_t *fmmu =
+ list_first_entry(&domain->fmmu_configs, ec_fmmu_config_t, list);
+ unsigned int redundancy;
#if DEBUG_REDUNDANCY
EC_MASTER_DBG(domain->master, 1, "domain %u process\n", domain->index);
#endif
- working_counter_sum = 0;
-
- if (!list_empty(&domain->datagram_pairs)) {
- datagram_pair =
- list_entry(domain->datagram_pairs.next, ec_datagram_pair_t, list);
- main_datagram = &datagram_pair->datagrams[EC_DEVICE_MAIN];
-
+ list_for_each_entry(pair, &domain->datagram_pairs, list) {
+
+ main_datagram = &pair->datagrams[EC_DEVICE_MAIN];
+ backup_datagram = &pair->datagrams[EC_DEVICE_BACKUP];
logical_datagram_address = EC_READ_U32(main_datagram->address);
datagram_size = main_datagram->data_size;
- datagram_offset =
- fmmu->logical_start_address - logical_datagram_address;
- datagram_pair_wc = ec_datagram_pair_process(datagram_pair);
- working_counter_sum += datagram_pair_wc;
+
#if DEBUG_REDUNDANCY
EC_MASTER_DBG(domain->master, 1, "dgram %s log=%u\n",
main_datagram->name, logical_datagram_address);
#endif
- }
-
- /* Go through all FMMU configs to detect data changes. */
- list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
-#if DEBUG_REDUNDANCY
- EC_MASTER_DBG(domain->master, 1, "fmmu log=%u size=%u dir=%u\n",
- fmmu->logical_start_address, fmmu->data_size, fmmu->dir);
-#endif
- if (fmmu->dir != EC_DIR_INPUT) {
- continue;
- }
-
- logical_datagram_address =
- EC_READ_U32(datagram_pair->datagrams[EC_DEVICE_MAIN].address);
- datagram_size = datagram_pair->datagrams[EC_DEVICE_MAIN].data_size;
- datagram_offset =
- fmmu->logical_start_address - logical_datagram_address;
- while (datagram_offset >= datagram_size) {
-
- datagram_pair = list_entry(datagram_pair->list.next,
- ec_datagram_pair_t, list);
- main_datagram = &datagram_pair->datagrams[EC_DEVICE_MAIN];
-
- logical_datagram_address = EC_READ_U32(main_datagram->address);
- datagram_size = main_datagram->data_size;
+
+ datagram_pair_wc = ec_datagram_pair_process(pair, wc_sum);
+
+ /* Go through all FMMU configs to detect data changes. */
+ list_for_each_entry_from(fmmu, &domain->fmmu_configs, list) {
+
+ if (fmmu->dir != EC_DIR_INPUT) {
+ continue;
+ }
+
+ if (fmmu->logical_start_address >=
+ logical_datagram_address + datagram_size) {
+ // fmmu data contained in next datagram pair
+ break;
+ }
+
datagram_offset =
fmmu->logical_start_address - logical_datagram_address;
- datagram_pair_wc = ec_datagram_pair_process(datagram_pair);
- working_counter_sum += datagram_pair_wc;
+
#if DEBUG_REDUNDANCY
- EC_MASTER_DBG(domain->master, 1, "dgram %s log=%u\n",
- main_datagram->name, logical_datagram_address);
+ EC_MASTER_DBG(domain->master, 1,
+ "input fmmu log=%u size=%u offset=%u\n",
+ fmmu->logical_start_address, fmmu->data_size,
+ datagram_offset);
+ if (domain->master->debug_level > 0) {
+ ec_print_data(pair->send_buffer + datagram_offset,
+ fmmu->data_size);
+ ec_print_data(main_datagram->data + datagram_offset,
+ fmmu->data_size);
+ ec_print_data(backup_datagram->data + datagram_offset,
+ fmmu->data_size);
+ }
#endif
- }
-
+
+ if (data_changed(pair->send_buffer, main_datagram,
+ datagram_offset, fmmu->data_size)) {
+ /* data changed on main link: no copying necessary. */
#if DEBUG_REDUNDANCY
- EC_MASTER_DBG(domain->master, 1, "input fmmu log=%u size=%u"
- " using datagram %s offset=%u\n",
- fmmu->logical_start_address, fmmu->data_size,
- datagram_pair->datagrams[EC_DEVICE_MAIN].name,
- datagram_offset);
+ EC_MASTER_DBG(domain->master, 1, "main changed\n");
#endif
-
- if (ec_datagram_pair_data_changed(datagram_pair,
- datagram_offset, fmmu->data_size, EC_DEVICE_MAIN)) {
- /* data changed on main link. no copying necessary. */
- } else if (ec_datagram_pair_data_changed(datagram_pair,
- datagram_offset, fmmu->data_size, EC_DEVICE_BACKUP)
- || (datagram_pair_wc
- == datagram_pair->expected_working_counter)) {
- /* data changed on backup link or no change and complete WC.
- * copy to main memory. */
- uint8_t *target = datagram_pair->datagrams[EC_DEVICE_MAIN].data +
- datagram_offset;
- uint8_t *source = datagram_pair->datagrams[EC_DEVICE_BACKUP].data +
- datagram_offset;
- memcpy(target, source, fmmu->data_size);
- }
- }
-
- if (working_counter_sum != domain->working_counter) {
+ } else if (data_changed(pair->send_buffer, backup_datagram,
+ datagram_offset, fmmu->data_size)) {
+ /* data changed on backup link: copy to main memory. */
+#if DEBUG_REDUNDANCY
+ EC_MASTER_DBG(domain->master, 1, "backup changed\n");
+#endif
+ memcpy(main_datagram->data + datagram_offset,
+ backup_datagram->data + datagram_offset,
+ fmmu->data_size);
+ } else if (datagram_pair_wc == pair->expected_working_counter) {
+ /* no change, but WC complete: use main data. */
+#if DEBUG_REDUNDANCY
+ EC_MASTER_DBG(domain->master, 1, "no change but complete\n");
+#endif
+ } else {
+ /* no change and WC incomplete: mark WC as zero to avoid
+ * data.dependent WC flickering. */
+ datagram_pair_wc = 0;
+#if DEBUG_REDUNDANCY
+ EC_MASTER_DBG(domain->master, 1,
+ "no change and incomplete\n");
+#endif
+ }
+ }
+ }
+
+ redundancy = wc_sum[EC_DEVICE_BACKUP] > 0;
+ if (redundancy != domain->redundancy_active) {
+ if (redundancy) {
+ EC_MASTER_WARN(domain->master,
+ "Domain %u: Redundant link in use!\n",
+ domain->index);
+ } else {
+ EC_MASTER_INFO(domain->master,
+ "Domain %u: Redundant link unused again.\n",
+ domain->index);
+ }
+ domain->redundancy_active = redundancy;
+ }
+
+ if ((wc_sum[EC_DEVICE_MAIN] != domain->working_counter[EC_DEVICE_MAIN])
+ || (wc_sum[EC_DEVICE_BACKUP]
+ != domain->working_counter[EC_DEVICE_BACKUP])) {
domain->working_counter_changes++;
- domain->working_counter = working_counter_sum;
+ domain->working_counter[EC_DEVICE_MAIN] = wc_sum[EC_DEVICE_MAIN];
+ domain->working_counter[EC_DEVICE_BACKUP] = wc_sum[EC_DEVICE_BACKUP];
}
if (domain->working_counter_changes &&
@@ -516,14 +562,19 @@
domain->notify_jiffies = jiffies;
if (domain->working_counter_changes == 1) {
EC_MASTER_INFO(domain->master, "Domain %u: Working counter"
- " changed to %u/%u.\n", domain->index,
- domain->working_counter,
- domain->expected_working_counter);
+ " changed to %u/%u (%u+%u).\n", domain->index,
+ domain->working_counter[EC_DEVICE_MAIN] +
+ domain->working_counter[EC_DEVICE_BACKUP],
+ domain->expected_working_counter,
+ wc_sum[EC_DEVICE_MAIN], wc_sum[EC_DEVICE_BACKUP]);
} else {
EC_MASTER_INFO(domain->master, "Domain %u: %u working counter"
- " changes - now %u/%u.\n", domain->index,
- domain->working_counter_changes, domain->working_counter,
- domain->expected_working_counter);
+ " changes - now %u/%u (%u+%u).\n", domain->index,
+ domain->working_counter_changes,
+ domain->working_counter[EC_DEVICE_MAIN] +
+ domain->working_counter[EC_DEVICE_BACKUP],
+ domain->expected_working_counter,
+ wc_sum[EC_DEVICE_MAIN], wc_sum[EC_DEVICE_BACKUP]);
}
domain->working_counter_changes = 0;
}
@@ -559,10 +610,12 @@
void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
{
- state->working_counter = domain->working_counter;
-
- if (domain->working_counter) {
- if (domain->working_counter == domain->expected_working_counter) {
+ state->working_counter =
+ domain->working_counter[EC_DEVICE_MAIN]
+ + domain->working_counter[EC_DEVICE_BACKUP];
+
+ if (state->working_counter) {
+ if (state->working_counter == domain->expected_working_counter) {
state->wc_state = EC_WC_COMPLETE;
} else {
state->wc_state = EC_WC_INCOMPLETE;
@@ -570,6 +623,8 @@
} else {
state->wc_state = EC_WC_ZERO;
}
+
+ state->redundancy_active = domain->redundancy_active;
}
/*****************************************************************************/