//--------------------------------------------------------------- // // e c _ m a s t e r . c // // $LastChangedDate$ // $Author$ // //--------------------------------------------------------------- #include "ec_globals.h" #include "ec_master.h" #define DEBUG_SEND_RECEIVE //--------------------------------------------------------------- int EtherCAT_master_init(EtherCAT_master_t *master, char *eth_dev) { char errbuf_libpcap[PCAP_ERRBUF_SIZE]; char errbuf_libnet[LIBNET_ERRBUF_SIZE]; master->slaves = NULL; master->slave_count = 0; master->first_command = NULL; master->command_index = 0x00; master->process_data = NULL; master->pre_cb = NULL; master->post_cb = NULL; master->thread_continue = 0; master->cycle_time = 0; // Init Libpcap master->pcap_handle = pcap_open_live(eth_dev, BUFSIZ, 1, 0, errbuf_libpcap); if (master->pcap_handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", eth_dev, errbuf_libpcap); return 1; } // Init Libnet if (!(master->net_handle = libnet_init(LIBNET_LINK, eth_dev, errbuf_libnet))) { fprintf(stderr, "Could not init %s: %s!\n", eth_dev, errbuf_libnet); pcap_close(master->pcap_handle); return 1; } return 0; } //--------------------------------------------------------------- void EtherCAT_master_clear(EtherCAT_master_t *master) { libnet_destroy(master->net_handle); pcap_close(master->pcap_handle); // Remove all pending commands while (master->first_command) { EtherCAT_remove_command(master, master->first_command); } // Remove all slaves EtherCAT_clear_slaves(master); } //--------------------------------------------------------------- int EtherCAT_check_slaves(EtherCAT_master_t *master, EtherCAT_slave_t *slaves, unsigned int slave_count) { EtherCAT_command_t *cmd; EtherCAT_slave_t *cur; unsigned int i, j, found; unsigned char data[2]; // EtherCAT_clear_slaves() must be called before! if (master->slave_count) return -1; // Determine number of slaves if ((cmd = EtherCAT_broadcast_read(master, 0x0000, 4)) == NULL) { return -1; } if (EtherCAT_send_receive(master) != 0) { return -1; } master->slave_count = cmd->working_counter; EtherCAT_remove_command(master, cmd); if (master->slave_count < slave_count) { fprintf(stderr, "ERROR: Too few slaves on EtherCAT bus!\n"); return -1; } // No slaves. Stop further processing... if (master->slave_count == 0) return 0; // For every slave in the list for (i = 0; i < master->slave_count; i++) { cur = &slaves[i]; if (!cur->desc) { fprintf(stderr, "ERROR: Slave has no description (list position %i)!\n", i); return -1; } // Set ring position cur->ring_position = -i; cur->station_address = i + 1; // Write station address data[0] = cur->station_address & 0x00FF; data[1] = (cur->station_address & 0xFF00) >> 8; if ((cmd = EtherCAT_position_write(master, cur->ring_position, 0x0010, 2, data)) == NULL) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not create command!\n"); return -1; } if (EtherCAT_send_receive(master) != 0) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not send command!\n"); return -1; } if (cmd->working_counter != 1) { master->slave_count = 0; fprintf(stderr, "ERROR: Slave %i did not repond while writing station address!\n", i); return -1; } EtherCAT_remove_command(master, cmd); // Read base data if ((cmd = EtherCAT_read(master, cur->station_address, 0x0000, 4)) == NULL) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not create command!\n"); return -1; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); master->slave_count = 0; fprintf(stderr, "ERROR: Could not send command!\n"); return -4; } if (cmd->working_counter != 1) { EtherCAT_remove_command(master, cmd); master->slave_count = 0; fprintf(stderr, "ERROR: Slave %i did not respond while reading base data!\n", i); return -5; } // Get base data cur->type = cmd->data[0]; cur->revision = cmd->data[1]; cur->build = cmd->data[2] | (cmd->data[3] << 8); EtherCAT_remove_command(master, cmd); // Read identification from "Slave Information Interface" (SII) if (EtherCAT_read_slave_information(master, cur->station_address, 0x0008, &cur->vendor_id) != 0) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not read SII!\n", i); return -1; } if (EtherCAT_read_slave_information(master, cur->station_address, 0x000A, &cur->product_code) != 0) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not read SII!\n", i); return -1; } if (EtherCAT_read_slave_information(master, cur->station_address, 0x000E, &cur->revision_number) != 0) { master->slave_count = 0; fprintf(stderr, "ERROR: Could not read SII!\n", i); return -1; } // Search for identification in "database" found = 0; for (j = 0; j < slave_idents_count; j++) { if (slave_idents[j].vendor_id == cur->vendor_id && slave_idents[j].product_code == cur->product_code) { found = 1; if (cur->desc != slave_idents[j].desc) { fprintf(stderr, "ERROR: Unexpected slave device at position %i:" "%s %s. Expected: %s %s\n", i, slave_idents[j].desc->vendor_name, slave_idents[j].desc->product_name, cur->desc->vendor_name, cur->desc->product_name); return -1; } break; } } if (!found) { fprintf(stderr, "ERROR: Unknown slave device at position %i: Vendor %X, Code %X", i, cur->vendor_id, cur->product_code); return -1; } } return 0; } //--------------------------------------------------------------- void EtherCAT_clear_slaves(EtherCAT_master_t *master) { unsigned int i; if (master->slave_count == 0) return; for (i = 0; i < master->slave_count; i++) { EtherCAT_slave_clear(&master->slaves[i]); } free(master->slaves); master->slaves = NULL; } //--------------------------------------------------------------- int EtherCAT_read_slave_information(EtherCAT_master_t *master, unsigned short int node_address, unsigned short int offset, unsigned int *target) { EtherCAT_command_t *cmd; unsigned char data[10]; unsigned int tries; // Initiate read operation data[0] = 0x00; data[1] = 0x01; data[2] = offset & 0xFF; data[3] = (offset & 0xFF00) >> 8; data[4] = 0x00; data[5] = 0x00; if ((cmd = EtherCAT_write(master, node_address, 0x502, 6, data)) == NULL) { fprintf(stderr, "ERROR: Could not allocate command!\n"); return -2; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); fprintf(stderr, "ERROR: Could not write to slave!\n"); return -3; } if (cmd->working_counter != 1) { EtherCAT_remove_command(master, cmd); fprintf(stderr, "ERROR: Command not processed by slave!\n"); return -4; } EtherCAT_remove_command(master, cmd); // Get status of read operation tries = 0; while (tries < 10) { if ((cmd = EtherCAT_read(master, node_address, 0x502, 10)) == NULL) { fprintf(stderr, "ERROR: Could not allocate command!\n"); return -2; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); fprintf(stderr, "ERROR: Could not read from slave!\n"); return -3; } if (cmd->working_counter != 1) { EtherCAT_remove_command(master, cmd); fprintf(stderr, "ERROR: Command not processed by slave!\n"); return -4; } if ((cmd->data[1] & 0x81) == 0) { #if 0 printf("SLI status data: %02X %02X Address: %02X %02X\n", cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]); printf("Data: %02X %02X %02X %02X\n", cmd->data[6], cmd->data[7], cmd->data[8], cmd->data[9]); #endif memcpy(target, cmd->data + 6, 4); EtherCAT_remove_command(master, cmd); break; } EtherCAT_remove_command(master, cmd); tries++; } if (tries == 10) fprintf(stderr, "ERROR: Timeout while reading SII!\n"); return 0; } //--------------------------------------------------------------- int EtherCAT_send_receive(EtherCAT_master_t *master) { libnet_ptag_t ptag; struct pcap_pkthdr header; const unsigned char *packet; unsigned char dst[6], src[6]; unsigned int i, length, framelength, pos, command_type, command_index; EtherCAT_command_t *cmd; unsigned char *data; int bytes, command_follows, found; #ifdef DEBUG_SEND_RECEIVE found = 0; #endif length = 0; for (cmd = master->first_command; cmd != NULL; cmd = cmd->next) { //if (cmd->status != Waiting) continue; length += cmd->data_length + 12; #ifdef DEBUG_SEND_RECEIVE found++; #endif } #ifdef DEBUG_SEND_RECEIVE printf("Sending %i commands with length %i...\n", found, length); #endif if (length == 0) return 0; framelength = length + 2; if (framelength < 46) framelength = 46; data = (unsigned char *) malloc(sizeof(unsigned char) * framelength); if (!data) return -1; data[0] = length & 0xFF; data[1] = ((length & 0x700) >> 8) | 0x10; pos = 2; for (cmd = master->first_command; cmd != NULL; cmd = cmd->next) { if (cmd->status != Waiting) { printf("Old command: %02X\n", cmd->command_type); continue; } cmd->command_index = master->command_index; master->command_index = (master->command_index + 1) % 0x0100; cmd->status = Sent; data[pos + 0] = cmd->command_type; data[pos + 1] = cmd->command_index; switch (cmd->command_type) { case EC_CMD_APRD: case EC_CMD_APWR: data[pos + 2] = cmd->ring_position & 0xFF; data[pos + 3] = (cmd->ring_position & 0xFF00) >> 8; data[pos + 4] = cmd->mem_address & 0xFF; data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8; break; case EC_CMD_NPRD: case EC_CMD_NPWR: data[pos + 2] = cmd->node_address & 0xFF; data[pos + 3] = (cmd->node_address & 0xFF00) >> 8; data[pos + 4] = cmd->mem_address & 0xFF; data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8; break; case EC_CMD_BRD: case EC_CMD_BWR: data[pos + 2] = 0x00; data[pos + 3] = 0x00; data[pos + 4] = cmd->mem_address & 0xFF; data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8; break; case EC_CMD_LRW: data[pos + 2] = cmd->logical_address & 0x000000FF; data[pos + 3] = (cmd->logical_address & 0x0000FF00) >> 8; data[pos + 4] = (cmd->logical_address & 0x00FF0000) >> 16; data[pos + 5] = (cmd->logical_address & 0xFF000000) >> 24; break; default: data[pos + 2] = 0x00; data[pos + 3] = 0x00; data[pos + 4] = 0x00; data[pos + 5] = 0x00; fprintf(stderr, "WARNING: Default adress while frame construction...\n"); break; } data[pos + 6] = cmd->data_length & 0xFF; data[pos + 7] = (cmd->data_length & 0x700) >> 8; if (cmd->next) data[pos + 7] |= 0x80; data[pos + 8] = 0x00; data[pos + 9] = 0x00; if (cmd->command_type == EC_CMD_APWR || cmd->command_type == EC_CMD_NPWR || cmd->command_type == EC_CMD_BWR || cmd->command_type == EC_CMD_LRW) // Write { for (i = 0; i < cmd->data_length; i++) data[pos + 10 + i] = cmd->data[i]; } else // Read { for (i = 0; i < cmd->data_length; i++) data[pos + 10 + i] = 0x00; } data[pos + 10 + cmd->data_length] = 0x00; data[pos + 11 + cmd->data_length] = 0x00; pos += 12 + cmd->data_length; } // Pad with zeros while (pos < 46) data[pos++] = 0x00; #ifdef DEBUG_SEND_RECEIVE printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); for (i = 0; i < framelength; i++) { printf("%02X ", data[i]); if ((i + 1) % 16 == 0) printf("\n"); } printf("\n-----------------------------------------------\n"); #endif dst[0] = 0xFF; dst[1] = 0xFF; dst[2] = 0xFF; dst[3] = 0xFF; dst[4] = 0xFF; dst[5] = 0xFF; src[0] = 0x00; src[1] = 0x00; src[2] = 0x00; src[3] = 0x00; src[4] = 0x00; src[5] = 0x00; // Send frame ptag = libnet_build_ethernet(dst, src, 0x88A4, data, framelength, master->net_handle, 0); bytes = libnet_write(master->net_handle); libnet_clear_packet(master->net_handle); if (bytes == -1) { free(data); fprintf(stderr, "Could not write!\n"); return -1; } packet = pcap_next(master->pcap_handle, &header); // LibPCap receives sent frame first packet = pcap_next(master->pcap_handle, &header); #ifdef DEBUG_SEND_RECEIVE for (i = 0; i < header.len - 14; i++) { if (packet[i + 14] == data[i]) printf(" "); else printf("%02X ", packet[i + 14]); if ((i + 1) % 16 == 0) printf("\n"); } printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n"); #endif // Free sent data free(data); pos = 16; command_follows = 1; while (command_follows) { command_type = packet[pos]; command_index = packet[pos + 1]; length = (packet[pos + 6] & 0xFF) | ((packet[pos + 7] & 0x07) << 8); command_follows = packet[pos + 7] & 0x80; #if 0 printf("Command %02X received!\n", command_index); #endif found = 0; for (cmd = master->first_command; cmd != NULL; cmd = cmd->next) { if (cmd->status == Sent && cmd->command_type == command_type && cmd->command_index == command_index && cmd->data_length == length) { found = 1; cmd->status = Received; cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length); memcpy(cmd->data, packet + pos + 10, length); cmd->working_counter = (packet[pos + length + 10] & 0xFF) | ((packet[pos + length + 11] & 0xFF) << 8); } } if (!found) { fprintf(stderr, "WARNING: Command not assigned!\n"); } pos += length + 12; } for (cmd = master->first_command; cmd != NULL; cmd = cmd->next) { if (cmd->status == Sent) { fprintf(stderr, "WARNING: Command not sent!\n"); } } return 0; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_read(EtherCAT_master_t *master, unsigned short node_address, unsigned short offset, unsigned int length) { EtherCAT_command_t *cmd; if (node_address == 0x0000) fprintf(stderr, "WARNING: Using node address 0x0000!\n"); cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_NPRD; cmd->node_address = node_address; cmd->mem_address = offset; cmd->data_length = length; // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_write(EtherCAT_master_t *master, unsigned short node_address, unsigned short offset, unsigned int length, const unsigned char *data) { EtherCAT_command_t *cmd; if (node_address == 0x0000) fprintf(stderr, "WARNING: Using node address 0x0000!\n"); cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_NPWR; cmd->node_address = node_address; cmd->mem_address = offset; cmd->data_length = length; cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length); if (cmd->data == NULL) { free(cmd); return NULL; } memcpy(cmd->data, data, length); // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_position_read(EtherCAT_master_t *master, short ring_position, unsigned short offset, unsigned int length) { EtherCAT_command_t *cmd; cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_APRD; cmd->ring_position = ring_position; cmd->mem_address = offset; cmd->data_length = length; // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_position_write(EtherCAT_master_t *master, short ring_position, unsigned short offset, unsigned int length, const unsigned char *data) { EtherCAT_command_t *cmd; cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_APWR; cmd->ring_position = ring_position; cmd->mem_address = offset; cmd->data_length = length; cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length); if (cmd->data == NULL) { free(cmd); return NULL; } memcpy(cmd->data, data, length); // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_broadcast_read(EtherCAT_master_t *master, unsigned short offset, unsigned int length) { EtherCAT_command_t *cmd; cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_BRD; cmd->mem_address = offset; cmd->data_length = length; // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_broadcast_write(EtherCAT_master_t *master, unsigned short offset, unsigned int length, const unsigned char *data) { EtherCAT_command_t *cmd; cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_BWR; cmd->mem_address = offset; cmd->data_length = length; cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length); if (cmd->data == NULL) { free(cmd); return NULL; } memcpy(cmd->data, data, length); // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- EtherCAT_command_t *EtherCAT_logical_read_write(EtherCAT_master_t *master, unsigned int offset, unsigned int length, unsigned char *data) { EtherCAT_command_t *cmd; cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t)); if (cmd == NULL) { return NULL; } EtherCAT_command_init(cmd); cmd->command_type = EC_CMD_LRW; cmd->mem_address = offset; cmd->data_length = length; cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length); if (cmd->data == NULL) { free(cmd); return NULL; } memcpy(cmd->data, data, length); // Add command to master's list add_command(master, cmd); return cmd; } //--------------------------------------------------------------- void add_command(EtherCAT_master_t *master, EtherCAT_command_t *cmd) { EtherCAT_command_t **last_cmd; // Find last position in the list last_cmd = &(master->first_command); while (*last_cmd) last_cmd = &(*last_cmd)->next; *last_cmd = cmd; } //--------------------------------------------------------------- void EtherCAT_remove_command(EtherCAT_master_t *master, EtherCAT_command_t *rem_cmd) { EtherCAT_command_t **last_cmd; last_cmd = &(master->first_command); while (*last_cmd) { if (*last_cmd == rem_cmd) { *last_cmd = rem_cmd->next; EtherCAT_command_clear(rem_cmd); return; } last_cmd = &(*last_cmd)->next; } } //--------------------------------------------------------------- int EtherCAT_state_change(EtherCAT_master_t *master, EtherCAT_slave_t *slave, unsigned char state_and_ack) { EtherCAT_command_t *cmd; unsigned char data[2]; unsigned int tries_left; data[0] = state_and_ack; data[1] = 0x00; if ((cmd = EtherCAT_write(master, slave->station_address, 0x0120, 2, data)) == NULL) { return -1; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); return -2; } if (cmd->working_counter != 1) { EtherCAT_remove_command(master, cmd); return -3; } EtherCAT_remove_command(master, cmd); slave->requested_state = state_and_ack & 0x0F; tries_left = 10; while (tries_left) { if ((cmd = EtherCAT_read(master, slave->station_address, 0x0130, 2)) == NULL) { return -1; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); return -2; } if (cmd->working_counter != 1) { EtherCAT_remove_command(master, cmd); return -3; } if (cmd->data[0] & 0x10) // State change error { EtherCAT_remove_command(master, cmd); return -4; } if (cmd->data[0] == state_and_ack & 0x0F) // State change successful { EtherCAT_remove_command(master, cmd); break; } EtherCAT_remove_command(master, cmd); //printf("Trying again...\n"); tries_left--; } if (!tries_left) { return -5; } slave->current_state = state_and_ack & 0x0F; return 0; } //--------------------------------------------------------------- int EtherCAT_broadcast_state_change(EtherCAT_master_t *master, unsigned char state) { EtherCAT_command_t *cmd; unsigned char data[2]; unsigned int tries_left; data[0] = state; data[1] = 0x00; if ((cmd = EtherCAT_broadcast_write(master, 0x0120, 2, data)) == NULL) { return -1; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); return -2; } if (cmd->working_counter != master->slave_count) { EtherCAT_remove_command(master, cmd); return -3; } EtherCAT_remove_command(master, cmd); tries_left = 10; while (tries_left) { if ((cmd = EtherCAT_broadcast_read(master, 0x0130, 2)) == NULL) { return -1; } if (EtherCAT_send_receive(master) != 0) { EtherCAT_remove_command(master, cmd); return -2; } if (cmd->working_counter != master->slave_count) { EtherCAT_remove_command(master, cmd); return -3; } if (cmd->data[0] & 0x10) // State change error { EtherCAT_remove_command(master, cmd); return -4; } if (cmd->data[0] == state) // State change successful { EtherCAT_remove_command(master, cmd); break; } EtherCAT_remove_command(master, cmd); //printf("Trying again...\n"); tries_left--; } if (!tries_left) { return -5; } return 0; } //--------------------------------------------------------------- int EtherCAT_start(EtherCAT_master_t *master, unsigned int length, void (*pre_cb)(unsigned char *), void (*post_cb)(unsigned char *), unsigned int cycle_time) { if (master->process_data) { fprintf(stderr, "ERROR: Process data already allocated!\n"); return -1; } if ((master->process_data = (unsigned char *) malloc(length)) == NULL) { fprintf(stderr, "ERROR: Could not allocate process data block!\n"); return -2; } memset(master->process_data, 0x00, length); master->process_data_length = length; master->pre_cb = pre_cb; master->post_cb = post_cb; master->cycle_time = cycle_time; master->thread_continue = 1; if (pthread_create(&master->thread, NULL, thread_function, (void *) master) != 0) { fprintf(stderr, "ERROR: Could not create thread!\n"); return -3; } return 0; } //--------------------------------------------------------------- int EtherCAT_stop(EtherCAT_master_t *master) { if (!master->thread_continue) { fprintf(stderr, "ERROR: Thread not running!\n"); return -1; } master->thread_continue = 0; pthread_join(master->thread, NULL); if (master->process_data) { free(master->process_data); master->process_data = NULL; } master->pre_cb = NULL; master->post_cb = NULL; return 0; } //--------------------------------------------------------------- double current_timestamp() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double) tv.tv_usec / 1000000.0; } //--------------------------------------------------------------- void *thread_function(void *data) { EtherCAT_master_t *master; EtherCAT_command_t *cmd; double bus_start_time, bus_end_time; double cycle_start_time, cycle_end_time, last_cycle_start_time; unsigned int wait_usecs; master = (EtherCAT_master_t *) data; last_cycle_start_time = 0.0; while (master->thread_continue) { cycle_start_time = current_timestamp(); if (last_cycle_start_time != 0.0) { master->last_cycle_time = cycle_start_time - last_cycle_start_time; master->last_jitter = (master->last_cycle_time - (master->cycle_time / 1000000.0)) / (master->cycle_time / 1000000.0) * 100.0; } last_cycle_start_time = cycle_start_time; if (master->pre_cb) master->pre_cb(master->process_data); cmd = EtherCAT_logical_read_write(master, 0x00000000, master->process_data_length, master->process_data); bus_start_time = current_timestamp(); EtherCAT_send_receive(master); bus_end_time = current_timestamp(); master->bus_time = bus_end_time - bus_start_time; #if 0 printf("Working counter: %i\n", cmd->working_counter); #endif memcpy(master->process_data, cmd->data, master->process_data_length); EtherCAT_remove_command(master, cmd); if (master->post_cb) master->post_cb(master->process_data); // Calculate working time cycle_end_time = current_timestamp(); master->last_cycle_work_time = cycle_end_time - cycle_start_time; master->last_cycle_busy_rate = master->last_cycle_work_time / ((double) master->cycle_time / 1000000.0) * 100.0; wait_usecs = master->cycle_time - (unsigned int) (master->last_cycle_work_time * 1000000.0); //printf("USECS to wait: %i\n", wait_usecs); usleep(wait_usecs); //printf("waited: %lf\n", current_timestamp() - cycle_end_time); } return (void *) 0; } //--------------------------------------------------------------- int EtherCAT_activate_slave(EtherCAT_master_t *master, EtherCAT_slave_t *slave) { EtherCAT_command_t *cmd; const EtherCAT_slave_desc_t *desc; unsigned char fmmu[16]; unsigned char data[256]; if (EtherCAT_state_change(master, slave, EC_STATE_INIT) != 0) { return -1; } // Resetting FMMU's memset(data, 0x00, 256); cmd = EtherCAT_write(master, slave->station_address, 0x0600, 256, data); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Slave did not respond!\n"); return -2; } EtherCAT_remove_command(master, cmd); // Resetting Sync Manager channels memset(data, 0x00, 256); cmd = EtherCAT_write(master, slave->station_address, 0x0800, 256, data); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Slave did not respond!\n"); return -2; } EtherCAT_remove_command(master, cmd); desc = slave->desc; // Init Mailbox communication if (desc->type == MAILBOX) { if (desc->sm0) { cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -3; } EtherCAT_remove_command(master, cmd); } if (desc->sm1) { cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -4; } EtherCAT_remove_command(master, cmd); } } // Change state to PREOP if (EtherCAT_state_change(master, slave, EC_STATE_PREOP) != 0) { fprintf(stderr, "ERROR: Could not set state!\n"); return -5; } // Set FMMU's if (desc->fmmu0) { memcpy(fmmu, desc->fmmu0, 16); fmmu[0] = slave->logical_address0 & 0x000000FF; fmmu[1] = (slave->logical_address0 & 0x0000FF00) >> 8; fmmu[2] = (slave->logical_address0 & 0x00FF0000) >> 16; fmmu[3] = (slave->logical_address0 & 0xFF000000) >> 24; cmd = EtherCAT_write(master, slave->station_address, 0x0600, 16, fmmu); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded (%i of 1)!\n", cmd->working_counter); return -6; } EtherCAT_remove_command(master, cmd); } // Set Sync Managers if (desc->type != MAILBOX) { if (desc->sm0) { cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -8; } EtherCAT_remove_command(master, cmd); } if (desc->sm1) { cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -9; } EtherCAT_remove_command(master, cmd); } } if (desc->sm2) { cmd = EtherCAT_write(master, slave->station_address, 0x0810, 8, desc->sm2); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -10; } EtherCAT_remove_command(master, cmd); } if (desc->sm3) { cmd = EtherCAT_write(master, slave->station_address, 0x0818, 8, desc->sm3); EtherCAT_send_receive(master); if (cmd->working_counter != 1) { fprintf(stderr, "ERROR: Not all slaves responded!\n"); return -11; } EtherCAT_remove_command(master, cmd); } // Change state to SAVEOP if (EtherCAT_state_change(master, slave, EC_STATE_SAVEOP) != 0) { fprintf(stderr, "ERROR: Could not set state!\n"); return -12; } // Change state to OP if (EtherCAT_state_change(master, slave, EC_STATE_OP) != 0) { fprintf(stderr, "ERROR: Could not set state!\n"); return -13; } return 0; } //--------------------------------------------------------------- int EtherCAT_deactivate_slave(EtherCAT_master_t *master, EtherCAT_slave_t *slave) { if (EtherCAT_state_change(master, slave, EC_STATE_INIT) != 0) { return -1; } return 0; } //--------------------------------------------------------------- void set_byte(unsigned char *data, unsigned int offset, unsigned char value) { data[offset] = value; } //--------------------------------------------------------------- void set_word(unsigned char *data, unsigned int offset, unsigned int value) { data[offset] = value & 0xFF; data[offset + 1] = (value & 0xFF00) >> 8; } //---------------------------------------------------------------