fp@73: /****************************************************************************** fp@73: * fp@73: * f r a m e . c fp@73: * fp@73: * Methoden für einen EtherCAT-Frame. fp@73: * fp@73: * $Id$ fp@73: * fp@73: *****************************************************************************/ fp@73: fp@73: #include fp@73: #include fp@73: fp@77: #include "../include/EtherCAT_si.h" fp@73: #include "frame.h" fp@73: #include "master.h" fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: #define EC_FUNC_HEADER \ fp@73: frame->master = master; \ fp@73: frame->index = 0; \ fp@73: frame->working_counter = 0; fp@73: fp@73: #define EC_FUNC_WRITE_FOOTER \ fp@73: frame->data_length = length; \ fp@73: memcpy(frame->data, data, length); fp@73: fp@73: #define EC_FUNC_READ_FOOTER \ fp@77: frame->data_length = length; \ fp@77: memset(frame->data, 0x00, length); fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-NPRD-Kommando. fp@73: fp@73: Node-adressed physical read. fp@73: */ fp@73: fp@73: void ec_frame_init_nprd(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t node_address, fp@73: /**< Adresse des Knotens (Slaves) */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length fp@73: /**< Länge der zu lesenden Daten */ fp@73: ) fp@73: { fp@73: if (unlikely(node_address == 0x0000)) fp@84: EC_WARN("Using node address 0x0000!\n"); fp@73: fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_nprd; fp@73: frame->address.physical.slave = node_address; fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_READ_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-NPWR-Kommando. fp@73: fp@73: Node-adressed physical write. fp@73: */ fp@73: fp@73: void ec_frame_init_npwr(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t node_address, fp@73: /**< Adresse des Knotens (Slaves) */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length, fp@73: /**< Länge der zu schreibenden Daten */ fp@73: const uint8_t *data fp@73: /**< Zeiger auf Speicher mit zu schreibenden Daten */ fp@73: ) fp@73: { fp@73: if (unlikely(node_address == 0x0000)) fp@84: EC_WARN("Using node address 0x0000!\n"); fp@73: fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_npwr; fp@73: frame->address.physical.slave = node_address; fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_WRITE_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-APRD-Kommando. fp@73: fp@73: Autoincrement physical read. fp@73: */ fp@73: fp@73: void ec_frame_init_aprd(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t ring_position, fp@73: /**< Position des Slaves im Bus */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length fp@73: /**< Länge der zu lesenden Daten */ fp@73: ) fp@73: { fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_aprd; fp@73: frame->address.physical.slave = (int16_t) ring_position * (-1); fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_READ_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-APWR-Kommando. fp@73: fp@73: Autoincrement physical write. fp@73: */ fp@73: fp@73: void ec_frame_init_apwr(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t ring_position, fp@73: /**< Position des Slaves im Bus */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length, fp@73: /**< Länge der zu schreibenden Daten */ fp@73: const uint8_t *data fp@73: /**< Zeiger auf Speicher mit zu schreibenden Daten */ fp@73: ) fp@73: { fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_apwr; fp@73: frame->address.physical.slave = (int16_t) ring_position * (-1); fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_WRITE_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-BRD-Kommando. fp@73: fp@73: Broadcast read. fp@73: */ fp@73: fp@73: void ec_frame_init_brd(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length fp@73: /**< Länge der zu lesenden Daten */ fp@73: ) fp@73: { fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_brd; fp@73: frame->address.physical.slave = 0x0000; fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_READ_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-BWR-Kommando. fp@73: fp@73: Broadcast write. fp@73: */ fp@73: fp@73: void ec_frame_init_bwr(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint16_t offset, fp@73: /**< Physikalische Speicheradresse im Slave */ fp@73: unsigned int length, fp@73: /**< Länge der zu schreibenden Daten */ fp@73: const uint8_t *data fp@73: /**< Zeiger auf Speicher mit zu schreibenden Daten */ fp@73: ) fp@73: { fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_bwr; fp@73: frame->address.physical.slave = 0x0000; fp@73: frame->address.physical.mem = offset; fp@73: fp@73: EC_FUNC_WRITE_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Initialisiert ein EtherCAT-LRW-Kommando. fp@73: fp@73: Logical read write. fp@73: */ fp@73: fp@73: void ec_frame_init_lrw(ec_frame_t *frame, fp@73: /**< EtherCAT-Rahmen */ fp@73: ec_master_t *master, fp@73: /**< EtherCAT-Master */ fp@73: uint32_t offset, fp@73: /**< Logische Startadresse */ fp@73: unsigned int length, fp@73: /**< Länge der zu lesenden/schreibenden Daten */ fp@73: uint8_t *data fp@73: /**< Zeiger auf die Daten */ fp@73: ) fp@73: { fp@73: EC_FUNC_HEADER; fp@73: fp@73: frame->type = ec_frame_type_lrw; fp@73: frame->address.logical = offset; fp@73: fp@73: EC_FUNC_WRITE_FOOTER; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Sendet einen einzelnen EtherCAT-Rahmen. fp@73: fp@73: \return 0 bei Erfolg, sonst < 0 fp@73: */ fp@73: fp@73: int ec_frame_send(ec_frame_t *frame /**< Rahmen zum Senden */) fp@73: { fp@73: unsigned int command_size, frame_size, i; fp@73: uint8_t *data; fp@73: fp@73: if (unlikely(frame->master->debug_level > 0)) { fp@84: EC_DBG("ec_frame_send\n"); fp@73: } fp@73: fp@73: command_size = frame->data_length + EC_COMMAND_HEADER_SIZE fp@73: + EC_COMMAND_FOOTER_SIZE; fp@73: frame_size = command_size + EC_FRAME_HEADER_SIZE; fp@73: fp@73: if (unlikely(frame_size > EC_MAX_FRAME_SIZE)) { fp@84: EC_ERR("Frame too long (%i)!\n", frame_size); fp@73: return -1; fp@73: } fp@73: fp@73: if (frame_size < EC_MIN_FRAME_SIZE) frame_size = EC_MIN_FRAME_SIZE; fp@73: fp@73: if (unlikely(frame->master->debug_level > 0)) { fp@84: EC_DBG("Frame length: %i\n", frame_size); fp@73: } fp@73: fp@73: frame->index = frame->master->command_index; fp@73: frame->master->command_index = (frame->master->command_index + 1) % 0x0100; fp@73: fp@73: if (unlikely(frame->master->debug_level > 0)) { fp@84: EC_DBG("Sending command index 0x%X\n", frame->index); fp@73: } fp@73: fp@73: // Zeiger auf Socket-Buffer holen fp@73: data = ec_device_prepare(&frame->master->device); fp@73: fp@73: // EtherCAT frame header fp@77: EC_WRITE_U16(data, (command_size & 0x7FF) | 0x1000); fp@73: data += EC_FRAME_HEADER_SIZE; fp@73: fp@73: // EtherCAT command header fp@77: EC_WRITE_U8 (data, frame->type); fp@77: EC_WRITE_U8 (data + 1, frame->index); fp@77: EC_WRITE_U32(data + 2, frame->address.logical); fp@77: EC_WRITE_U16(data + 6, frame->data_length & 0x7FF); fp@77: EC_WRITE_U16(data + 8, 0x0000); fp@73: data += EC_COMMAND_HEADER_SIZE; fp@73: fp@77: // EtherCAT command data fp@77: memcpy(data, frame->data, frame->data_length); fp@77: data += frame->data_length; fp@73: fp@73: // EtherCAT command footer fp@77: EC_WRITE_U16(data, frame->working_counter); fp@73: data += EC_COMMAND_FOOTER_SIZE; fp@73: fp@73: // Pad with zeros fp@73: for (i = EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE fp@73: + frame->data_length + EC_COMMAND_FOOTER_SIZE; fp@77: i < EC_MIN_FRAME_SIZE; i++) fp@77: EC_WRITE_U8(data++, 0x00); fp@73: fp@73: // Send frame fp@73: ec_device_send(&frame->master->device, frame_size); fp@73: fp@73: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@91: Wertet empfangene Daten zu einem Rahmen aus. fp@73: fp@73: \return 0 bei Erfolg, sonst < 0 fp@73: */ fp@73: fp@73: int ec_frame_receive(ec_frame_t *frame /**< Gesendeter Rahmen */) fp@73: { fp@73: unsigned int received_length, frame_length, data_length; fp@73: uint8_t *data; fp@73: uint8_t command_type, command_index; fp@73: ec_device_t *device; fp@73: fp@73: device = &frame->master->device; fp@73: fp@73: if (!(received_length = ec_device_received(device))) return -1; fp@73: fp@73: device->state = EC_DEVICE_STATE_READY; fp@73: fp@73: if (unlikely(received_length < EC_FRAME_HEADER_SIZE)) { fp@84: EC_ERR("Received frame with incomplete EtherCAT frame header!\n"); fp@78: ec_device_debug(device); fp@73: return -1; fp@73: } fp@73: fp@73: data = ec_device_data(device); fp@73: fp@73: // Länge des gesamten Frames prüfen fp@77: frame_length = EC_READ_U16(data) & 0x07FF; fp@77: data += EC_FRAME_HEADER_SIZE; fp@73: fp@73: if (unlikely(frame_length > received_length)) { fp@84: EC_ERR("Received corrupted frame (length does not match)!\n"); fp@78: ec_device_debug(device); fp@73: return -1; fp@73: } fp@73: fp@73: // Command header fp@77: command_type = EC_READ_U8(data); fp@77: command_index = EC_READ_U8(data + 1); fp@77: data_length = EC_READ_U16(data + 6) & 0x07FF; fp@77: data += EC_COMMAND_HEADER_SIZE; fp@73: fp@73: if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE fp@73: + data_length + EC_COMMAND_FOOTER_SIZE > received_length)) { fp@84: EC_ERR("Received frame with incomplete command data!\n"); fp@78: ec_device_debug(device); fp@73: return -1; fp@73: } fp@73: fp@73: if (unlikely(frame->type != command_type fp@73: || frame->index != command_index fp@73: || frame->data_length != data_length)) fp@73: { fp@84: EC_WARN("WARNING - Send/Receive anomaly!\n"); fp@78: ec_device_debug(device); fp@73: ec_device_call_isr(device); // Empfangenes "vergessen" fp@73: return -1; fp@73: } fp@73: fp@73: // Empfangene Daten in Kommandodatenspeicher kopieren fp@73: memcpy(frame->data, data, data_length); fp@73: data += data_length; fp@73: fp@73: // Working-Counter setzen fp@77: frame->working_counter = EC_READ_U16(data); fp@73: fp@73: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Sendet einen einzeln Rahmen und wartet auf dessen Empfang. fp@73: fp@89: Wenn der Working-Counter nicht gesetzt wurde, wird der Rahmen fp@89: nochmals gesendet. fp@89: fp@89: \todo Das ist noch nicht schön, da hier zwei Protokollschichten fp@89: vermischt werden. fp@89: fp@73: \return 0 bei Erfolg, sonst < 0 fp@73: */ fp@73: fp@73: int ec_frame_send_receive(ec_frame_t *frame fp@73: /**< Rahmen zum Senden/Empfangen */ fp@73: ) fp@73: { fp@89: unsigned int timeout_tries_left, response_tries_left; fp@89: unsigned int tries; fp@89: fp@89: tries = 0; fp@89: response_tries_left = 10; fp@73: do fp@73: { fp@89: tries++; fp@89: if (unlikely(ec_frame_send(frame) < 0)) { fp@89: EC_ERR("Frame sending failed!\n"); fp@89: return -1; fp@89: } fp@89: fp@89: timeout_tries_left = 20; fp@89: do fp@89: { fp@89: udelay(1); fp@89: ec_device_call_isr(&frame->master->device); fp@89: timeout_tries_left--; fp@89: } fp@89: while (unlikely(!ec_device_received(&frame->master->device) fp@89: && timeout_tries_left)); fp@89: fp@89: if (unlikely(!timeout_tries_left)) { fp@89: EC_ERR("Frame timeout!\n"); fp@89: return -1; fp@89: } fp@89: fp@89: if (unlikely(ec_frame_receive(frame) < 0)) { fp@89: EC_ERR("Frame receiving failed!\n"); fp@89: return -1; fp@89: } fp@89: fp@89: response_tries_left--; fp@89: } fp@89: while (unlikely(!frame->working_counter && response_tries_left)); fp@89: fp@89: if (unlikely(!response_tries_left)) { fp@89: EC_ERR("No response!"); fp@89: return -1; fp@89: } fp@89: fp@89: if (tries > 1) EC_WARN("%i tries necessary...\n", tries); fp@73: fp@73: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /* Emacs-Konfiguration fp@73: ;;; Local Variables: *** fp@73: ;;; c-basic-offset:4 *** fp@73: ;;; End: *** fp@73: */