master/frame.c
changeset 98 f564d0929292
parent 97 e6264685dd7b
child 99 72e375b0b308
equal deleted inserted replaced
97:e6264685dd7b 98:f564d0929292
     1 /******************************************************************************
       
     2  *
       
     3  *  f r a m e . c
       
     4  *
       
     5  *  Methoden für einen EtherCAT-Frame.
       
     6  *
       
     7  *  $Id$
       
     8  *
       
     9  *****************************************************************************/
       
    10 
       
    11 #include <linux/slab.h>
       
    12 #include <linux/delay.h>
       
    13 
       
    14 #include "../include/EtherCAT_si.h"
       
    15 #include "frame.h"
       
    16 #include "master.h"
       
    17 
       
    18 /*****************************************************************************/
       
    19 
       
    20 #define EC_FUNC_HEADER \
       
    21     frame->master = master; \
       
    22     frame->index = 0; \
       
    23     frame->working_counter = 0;
       
    24 
       
    25 #define EC_FUNC_WRITE_FOOTER \
       
    26     frame->data_length = length; \
       
    27     memcpy(frame->data, data, length);
       
    28 
       
    29 #define EC_FUNC_READ_FOOTER \
       
    30     frame->data_length = length; \
       
    31     memset(frame->data, 0x00, length);
       
    32 
       
    33 /*****************************************************************************/
       
    34 
       
    35 /**
       
    36    Initialisiert ein EtherCAT-NPRD-Kommando.
       
    37 
       
    38    Node-adressed physical read.
       
    39 */
       
    40 
       
    41 void ec_frame_init_nprd(ec_frame_t *frame,
       
    42                         /**< EtherCAT-Rahmen */
       
    43                         ec_master_t *master,
       
    44                         /**< EtherCAT-Master */
       
    45                         uint16_t node_address,
       
    46                         /**< Adresse des Knotens (Slaves) */
       
    47                         uint16_t offset,
       
    48                         /**< Physikalische Speicheradresse im Slave */
       
    49                         unsigned int length
       
    50                         /**< Länge der zu lesenden Daten */
       
    51                         )
       
    52 {
       
    53     if (unlikely(node_address == 0x0000))
       
    54         EC_WARN("Using node address 0x0000!\n");
       
    55 
       
    56     EC_FUNC_HEADER;
       
    57 
       
    58     frame->type = ec_frame_type_nprd;
       
    59     frame->address.physical.slave = node_address;
       
    60     frame->address.physical.mem = offset;
       
    61 
       
    62     EC_FUNC_READ_FOOTER;
       
    63 }
       
    64 
       
    65 /*****************************************************************************/
       
    66 
       
    67 /**
       
    68    Initialisiert ein EtherCAT-NPWR-Kommando.
       
    69 
       
    70    Node-adressed physical write.
       
    71 */
       
    72 
       
    73 void ec_frame_init_npwr(ec_frame_t *frame,
       
    74                         /**< EtherCAT-Rahmen */
       
    75                         ec_master_t *master,
       
    76                         /**< EtherCAT-Master */
       
    77                         uint16_t node_address,
       
    78                         /**< Adresse des Knotens (Slaves) */
       
    79                         uint16_t offset,
       
    80                         /**< Physikalische Speicheradresse im Slave */
       
    81                         unsigned int length,
       
    82                         /**< Länge der zu schreibenden Daten */
       
    83                         const uint8_t *data
       
    84                         /**< Zeiger auf Speicher mit zu schreibenden Daten */
       
    85                         )
       
    86 {
       
    87     if (unlikely(node_address == 0x0000))
       
    88         EC_WARN("Using node address 0x0000!\n");
       
    89 
       
    90     EC_FUNC_HEADER;
       
    91 
       
    92     frame->type = ec_frame_type_npwr;
       
    93     frame->address.physical.slave = node_address;
       
    94     frame->address.physical.mem = offset;
       
    95 
       
    96     EC_FUNC_WRITE_FOOTER;
       
    97 }
       
    98 
       
    99 /*****************************************************************************/
       
   100 
       
   101 /**
       
   102    Initialisiert ein EtherCAT-APRD-Kommando.
       
   103 
       
   104    Autoincrement physical read.
       
   105 */
       
   106 
       
   107 void ec_frame_init_aprd(ec_frame_t *frame,
       
   108                         /**< EtherCAT-Rahmen */
       
   109                         ec_master_t *master,
       
   110                         /**< EtherCAT-Master */
       
   111                         uint16_t ring_position,
       
   112                         /**< Position des Slaves im Bus */
       
   113                         uint16_t offset,
       
   114                         /**< Physikalische Speicheradresse im Slave */
       
   115                         unsigned int length
       
   116                         /**< Länge der zu lesenden Daten */
       
   117                         )
       
   118 {
       
   119     EC_FUNC_HEADER;
       
   120 
       
   121     frame->type = ec_frame_type_aprd;
       
   122     frame->address.physical.slave = (int16_t) ring_position * (-1);
       
   123     frame->address.physical.mem = offset;
       
   124 
       
   125     EC_FUNC_READ_FOOTER;
       
   126 }
       
   127 
       
   128 /*****************************************************************************/
       
   129 
       
   130 /**
       
   131    Initialisiert ein EtherCAT-APWR-Kommando.
       
   132 
       
   133    Autoincrement physical write.
       
   134 */
       
   135 
       
   136 void ec_frame_init_apwr(ec_frame_t *frame,
       
   137                         /**< EtherCAT-Rahmen */
       
   138                         ec_master_t *master,
       
   139                         /**< EtherCAT-Master */
       
   140                         uint16_t ring_position,
       
   141                         /**< Position des Slaves im Bus */
       
   142                         uint16_t offset,
       
   143                         /**< Physikalische Speicheradresse im Slave */
       
   144                         unsigned int length,
       
   145                         /**< Länge der zu schreibenden Daten */
       
   146                         const uint8_t *data
       
   147                         /**< Zeiger auf Speicher mit zu schreibenden Daten */
       
   148                         )
       
   149 {
       
   150     EC_FUNC_HEADER;
       
   151 
       
   152     frame->type = ec_frame_type_apwr;
       
   153     frame->address.physical.slave = (int16_t) ring_position * (-1);
       
   154     frame->address.physical.mem = offset;
       
   155 
       
   156     EC_FUNC_WRITE_FOOTER;
       
   157 }
       
   158 
       
   159 /*****************************************************************************/
       
   160 
       
   161 /**
       
   162    Initialisiert ein EtherCAT-BRD-Kommando.
       
   163 
       
   164    Broadcast read.
       
   165 */
       
   166 
       
   167 void ec_frame_init_brd(ec_frame_t *frame,
       
   168                        /**< EtherCAT-Rahmen */
       
   169                        ec_master_t *master,
       
   170                        /**< EtherCAT-Master */
       
   171                        uint16_t offset,
       
   172                        /**< Physikalische Speicheradresse im Slave */
       
   173                        unsigned int length
       
   174                        /**< Länge der zu lesenden Daten */
       
   175                        )
       
   176 {
       
   177     EC_FUNC_HEADER;
       
   178 
       
   179     frame->type = ec_frame_type_brd;
       
   180     frame->address.physical.slave = 0x0000;
       
   181     frame->address.physical.mem = offset;
       
   182 
       
   183     EC_FUNC_READ_FOOTER;
       
   184 }
       
   185 
       
   186 /*****************************************************************************/
       
   187 
       
   188 /**
       
   189    Initialisiert ein EtherCAT-BWR-Kommando.
       
   190 
       
   191    Broadcast write.
       
   192 */
       
   193 
       
   194 void ec_frame_init_bwr(ec_frame_t *frame,
       
   195                        /**< EtherCAT-Rahmen */
       
   196                        ec_master_t *master,
       
   197                        /**< EtherCAT-Master */
       
   198                        uint16_t offset,
       
   199                        /**< Physikalische Speicheradresse im Slave */
       
   200                        unsigned int length,
       
   201                        /**< Länge der zu schreibenden Daten */
       
   202                        const uint8_t *data
       
   203                        /**< Zeiger auf Speicher mit zu schreibenden Daten */
       
   204                        )
       
   205 {
       
   206     EC_FUNC_HEADER;
       
   207 
       
   208     frame->type = ec_frame_type_bwr;
       
   209     frame->address.physical.slave = 0x0000;
       
   210     frame->address.physical.mem = offset;
       
   211 
       
   212     EC_FUNC_WRITE_FOOTER;
       
   213 }
       
   214 
       
   215 /*****************************************************************************/
       
   216 
       
   217 /**
       
   218    Initialisiert ein EtherCAT-LRW-Kommando.
       
   219 
       
   220    Logical read write.
       
   221 */
       
   222 
       
   223 void ec_frame_init_lrw(ec_frame_t *frame,
       
   224                        /**< EtherCAT-Rahmen */
       
   225                        ec_master_t *master,
       
   226                        /**< EtherCAT-Master */
       
   227                        uint32_t offset,
       
   228                        /**< Logische Startadresse */
       
   229                        unsigned int length,
       
   230                        /**< Länge der zu lesenden/schreibenden Daten */
       
   231                        uint8_t *data
       
   232                        /**< Zeiger auf die Daten */
       
   233                        )
       
   234 {
       
   235     EC_FUNC_HEADER;
       
   236 
       
   237     frame->type = ec_frame_type_lrw;
       
   238     frame->address.logical = offset;
       
   239 
       
   240     EC_FUNC_WRITE_FOOTER;
       
   241 }
       
   242 
       
   243 /*****************************************************************************/
       
   244 
       
   245 /**
       
   246    Sendet einen einzelnen EtherCAT-Rahmen.
       
   247 
       
   248    \return 0 bei Erfolg, sonst < 0
       
   249 */
       
   250 
       
   251 int ec_frame_send(ec_frame_t *frame /**< Rahmen zum Senden */)
       
   252 {
       
   253     unsigned int command_size, frame_size, i;
       
   254     uint8_t *data;
       
   255 
       
   256     if (unlikely(!frame->master->device.link_state))
       
   257         return -1;
       
   258 
       
   259     if (unlikely(frame->master->debug_level > 0)) {
       
   260         EC_DBG("ec_frame_send\n");
       
   261     }
       
   262 
       
   263     command_size = frame->data_length + EC_COMMAND_HEADER_SIZE
       
   264         + EC_COMMAND_FOOTER_SIZE;
       
   265     frame_size = command_size + EC_FRAME_HEADER_SIZE;
       
   266 
       
   267     if (unlikely(frame_size > EC_MAX_FRAME_SIZE)) {
       
   268         EC_ERR("Frame too long (%i)!\n", frame_size);
       
   269         return -1;
       
   270     }
       
   271 
       
   272     if (frame_size < EC_MIN_FRAME_SIZE) frame_size = EC_MIN_FRAME_SIZE;
       
   273 
       
   274     if (unlikely(frame->master->debug_level > 0)) {
       
   275         EC_DBG("Frame length: %i\n", frame_size);
       
   276     }
       
   277 
       
   278     frame->index = frame->master->command_index;
       
   279     frame->master->command_index = (frame->master->command_index + 1) % 0x0100;
       
   280 
       
   281     if (unlikely(frame->master->debug_level > 0)) {
       
   282         EC_DBG("Sending command index 0x%X\n", frame->index);
       
   283     }
       
   284 
       
   285     // Zeiger auf Socket-Buffer holen
       
   286     data = ec_device_prepare(&frame->master->device);
       
   287 
       
   288     // EtherCAT frame header
       
   289     EC_WRITE_U16(data, (command_size & 0x7FF) | 0x1000);
       
   290     data += EC_FRAME_HEADER_SIZE;
       
   291 
       
   292     // EtherCAT command header
       
   293     EC_WRITE_U8 (data,     frame->type);
       
   294     EC_WRITE_U8 (data + 1, frame->index);
       
   295     EC_WRITE_U32(data + 2, frame->address.logical);
       
   296     EC_WRITE_U16(data + 6, frame->data_length & 0x7FF);
       
   297     EC_WRITE_U16(data + 8, 0x0000);
       
   298     data += EC_COMMAND_HEADER_SIZE;
       
   299 
       
   300     // EtherCAT command data
       
   301     memcpy(data, frame->data, frame->data_length);
       
   302     data += frame->data_length;
       
   303 
       
   304     // EtherCAT command footer
       
   305     EC_WRITE_U16(data, frame->working_counter);
       
   306     data += EC_COMMAND_FOOTER_SIZE;
       
   307 
       
   308     // Pad with zeros
       
   309     for (i = EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
       
   310              + frame->data_length + EC_COMMAND_FOOTER_SIZE;
       
   311          i < EC_MIN_FRAME_SIZE; i++)
       
   312         EC_WRITE_U8(data++, 0x00);
       
   313 
       
   314     // Send frame
       
   315     ec_device_send(&frame->master->device, frame_size);
       
   316 
       
   317     return 0;
       
   318 }
       
   319 
       
   320 /*****************************************************************************/
       
   321 
       
   322 /**
       
   323    Wertet empfangene Daten zu einem Rahmen aus.
       
   324 
       
   325    \return 0 bei Erfolg, sonst < 0
       
   326 */
       
   327 
       
   328 int ec_frame_receive(ec_frame_t *frame /**< Gesendeter Rahmen */)
       
   329 {
       
   330     unsigned int received_length, frame_length, data_length;
       
   331     uint8_t *data;
       
   332     uint8_t command_type, command_index;
       
   333     ec_device_t *device;
       
   334 
       
   335     device = &frame->master->device;
       
   336 
       
   337     if (!(received_length = ec_device_received(device))) return -1;
       
   338 
       
   339     device->state = EC_DEVICE_STATE_READY;
       
   340 
       
   341     if (unlikely(received_length < EC_FRAME_HEADER_SIZE)) {
       
   342         EC_ERR("Received frame with incomplete EtherCAT frame header!\n");
       
   343         ec_device_debug(device);
       
   344         return -1;
       
   345     }
       
   346 
       
   347     data = ec_device_data(device);
       
   348 
       
   349     // Länge des gesamten Frames prüfen
       
   350     frame_length = EC_READ_U16(data) & 0x07FF;
       
   351     data += EC_FRAME_HEADER_SIZE;
       
   352 
       
   353     if (unlikely(frame_length > received_length)) {
       
   354         EC_ERR("Received corrupted frame (length does not match)!\n");
       
   355         ec_device_debug(device);
       
   356         return -1;
       
   357     }
       
   358 
       
   359     // Command header
       
   360     command_type =  EC_READ_U8(data);
       
   361     command_index = EC_READ_U8(data + 1);
       
   362     data_length =   EC_READ_U16(data + 6) & 0x07FF;
       
   363     data += EC_COMMAND_HEADER_SIZE;
       
   364 
       
   365     if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
       
   366                  + data_length + EC_COMMAND_FOOTER_SIZE > received_length)) {
       
   367         EC_ERR("Received frame with incomplete command data!\n");
       
   368         ec_device_debug(device);
       
   369         return -1;
       
   370     }
       
   371 
       
   372     if (unlikely(frame->type != command_type
       
   373                  || frame->index != command_index
       
   374                  || frame->data_length != data_length))
       
   375     {
       
   376         EC_WARN("WARNING - Send/Receive anomaly!\n");
       
   377         ec_device_debug(device);
       
   378         ec_device_call_isr(device); // Empfangenes "vergessen"
       
   379         return -1;
       
   380     }
       
   381 
       
   382     // Empfangene Daten in Kommandodatenspeicher kopieren
       
   383     memcpy(frame->data, data, data_length);
       
   384     data += data_length;
       
   385 
       
   386     // Working-Counter setzen
       
   387     frame->working_counter = EC_READ_U16(data);
       
   388 
       
   389     return 0;
       
   390 }
       
   391 
       
   392 /*****************************************************************************/
       
   393 
       
   394 /**
       
   395    Sendet einen einzeln Rahmen und wartet auf dessen Empfang.
       
   396 
       
   397    Wenn der Working-Counter nicht gesetzt wurde, wird der Rahmen
       
   398    nochmals gesendet.
       
   399 
       
   400    \todo Das ist noch nicht schön, da hier zwei Protokollschichten
       
   401    vermischt werden.
       
   402 
       
   403    \return 0 bei Erfolg, sonst < 0
       
   404 */
       
   405 
       
   406 int ec_frame_send_receive(ec_frame_t *frame
       
   407                           /**< Rahmen zum Senden/Empfangen */
       
   408                           )
       
   409 {
       
   410     unsigned int timeout_tries_left, response_tries_left;
       
   411     unsigned int tries;
       
   412 
       
   413     tries = 0;
       
   414     response_tries_left = 10;
       
   415     do
       
   416     {
       
   417         tries++;
       
   418         if (unlikely(ec_frame_send(frame) < 0)) {
       
   419             EC_ERR("Frame sending failed!\n");
       
   420             return -1;
       
   421         }
       
   422 
       
   423         timeout_tries_left = 20;
       
   424         do
       
   425         {
       
   426             udelay(1);
       
   427             ec_device_call_isr(&frame->master->device);
       
   428             timeout_tries_left--;
       
   429         }
       
   430         while (unlikely(!ec_device_received(&frame->master->device)
       
   431                         && timeout_tries_left));
       
   432 
       
   433         if (unlikely(!timeout_tries_left)) {
       
   434             EC_ERR("Frame timeout!\n");
       
   435             return -1;
       
   436         }
       
   437 
       
   438         if (unlikely(ec_frame_receive(frame) < 0)) {
       
   439             EC_ERR("Frame receiving failed!\n");
       
   440             return -1;
       
   441         }
       
   442 
       
   443         response_tries_left--;
       
   444     }
       
   445     while (unlikely(!frame->working_counter && response_tries_left));
       
   446 
       
   447     if (unlikely(!response_tries_left)) {
       
   448         EC_ERR("No response!");
       
   449         return -1;
       
   450     }
       
   451 
       
   452     if (tries > 1) EC_WARN("%i tries necessary...\n", tries);
       
   453 
       
   454     return 0;
       
   455 }
       
   456 
       
   457 /*****************************************************************************/
       
   458 
       
   459 /* Emacs-Konfiguration
       
   460 ;;; Local Variables: ***
       
   461 ;;; c-basic-offset:4 ***
       
   462 ;;; End: ***
       
   463 */