AB&T / SOEM

Dependents:   EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethercatbase.c Source File

ethercatbase.c

Go to the documentation of this file.
00001 /*
00002  * Licensed under the GNU General Public License version 2 with exceptions. See
00003  * LICENSE file in the project root for full license information
00004  */
00005 
00006 /** \file
00007  * \brief
00008  * Base EtherCAT functions.
00009  *
00010  * Setting up a datagram in an ethernet frame.
00011  * EtherCAT datagram primitives, broadcast, auto increment, configured and
00012  * logical addressed data transfers. All base transfers are blocking, so
00013  * wait for the frame to be returned to the master or timeout. If this is
00014  * not acceptable build your own datagrams and use the functions from nicdrv.c.
00015  */
00016 
00017 #include <stdio.h>
00018 #include <string.h>
00019 #include "oshw.h"
00020 #include "osal.h"
00021 #include "ethercattype.h"
00022 #include "ethercatbase.h"
00023 
00024 /** Write data to EtherCAT datagram.
00025  *
00026  * @param[out] datagramdata   = data part of datagram
00027  * @param[in]  com            = command
00028  * @param[in]  length         = length of databuffer
00029  * @param[in]  data           = databuffer to be copied into datagram
00030  */
00031 static void ecx_writedatagramdata(void *datagramdata, ec_cmdtype com, uint16 length, const void * data)
00032 {
00033    if (length > 0)
00034    {
00035       switch (com)
00036       {
00037          case EC_CMD_NOP:
00038             /* Fall-through */
00039          case EC_CMD_APRD:
00040             /* Fall-through */
00041          case EC_CMD_FPRD:
00042             /* Fall-through */
00043          case EC_CMD_BRD:
00044             /* Fall-through */
00045          case EC_CMD_LRD:
00046             /* no data to write. initialise data so frame is in a known state */
00047             memset(datagramdata, 0, length);
00048             break;
00049          default:
00050             memcpy(datagramdata, data, length);
00051             break;
00052       }
00053    }
00054 }
00055 
00056 /** Generate and set EtherCAT datagram in a standard ethernet frame.
00057  *
00058  * @param[in] port        = port context struct
00059  * @param[out] frame       = framebuffer
00060  * @param[in]  com         = command
00061  * @param[in]  idx         = index used for TX and RX buffers
00062  * @param[in]  ADP         = Address Position
00063  * @param[in]  ADO         = Address Offset
00064  * @param[in]  length      = length of datagram excluding EtherCAT header
00065  * @param[in]  data        = databuffer to be copied in datagram
00066  * @return always 0
00067  */
00068 int ecx_setupdatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
00069 {
00070    ec_comt *datagramP;
00071    uint8 *frameP;
00072 
00073    frameP = frame;
00074    /* Ethernet header is preset and fixed in frame buffers
00075       EtherCAT header needs to be added after that */
00076    datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE];
00077    datagramP->elength = htoes(EC_ECATTYPE + EC_HEADERSIZE + length);
00078    datagramP->command = com;
00079    datagramP->index = idx;
00080    datagramP->ADP = htoes(ADP);
00081    datagramP->ADO = htoes(ADO);
00082    datagramP->dlength = htoes(length);
00083    ecx_writedatagramdata(&frameP[ETH_HEADERSIZE + EC_HEADERSIZE], com, length, data);
00084    /* set WKC to zero */
00085    frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length] = 0x00;
00086    frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length + 1] = 0x00;
00087    /* set size of frame in buffer array */
00088    port->txbuflength[idx] = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + length;
00089 
00090    return 0;
00091 }
00092 
00093 /** Add EtherCAT datagram to a standard ethernet frame with existing datagram(s).
00094  *
00095  * @param[in] port        = port context struct
00096  * @param[out] frame      = framebuffer
00097  * @param[in]  com        = command
00098  * @param[in]  idx        = index used for TX and RX buffers
00099  * @param[in]  more       = TRUE if still more datagrams to follow
00100  * @param[in]  ADP        = Address Position
00101  * @param[in]  ADO        = Address Offset
00102  * @param[in]  length     = length of datagram excluding EtherCAT header
00103  * @param[in]  data       = databuffer to be copied in datagram
00104  * @return Offset to data in rx frame, usefull to retrieve data after RX.
00105  */
00106 int ecx_adddatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
00107 {
00108    ec_comt *datagramP;
00109    uint8 *frameP;
00110    uint16 prevlength;
00111 
00112    frameP = frame;
00113    /* copy previous frame size */
00114    prevlength = port->txbuflength[idx];
00115    datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE];
00116    /* add new datagram to ethernet frame size */
00117    datagramP->elength = htoes( etohs(datagramP->elength) + EC_HEADERSIZE + length );
00118    /* add "datagram follows" flag to previous subframe dlength */
00119    datagramP->dlength = htoes( etohs(datagramP->dlength) | EC_DATAGRAMFOLLOWS );
00120    /* set new EtherCAT header position */
00121    datagramP = (ec_comt*)&frameP[prevlength - EC_ELENGTHSIZE];
00122    datagramP->command = com;
00123    datagramP->index = idx;
00124    datagramP->ADP = htoes(ADP);
00125    datagramP->ADO = htoes(ADO);
00126    if (more)
00127    {
00128       /* this is not the last datagram to add */
00129       datagramP->dlength = htoes(length | EC_DATAGRAMFOLLOWS);
00130    }
00131    else
00132    {
00133       /* this is the last datagram in the frame */
00134       datagramP->dlength = htoes(length);
00135    }
00136    ecx_writedatagramdata(&frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE], com, length, data);
00137    /* set WKC to zero */
00138    frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length] = 0x00;
00139    frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length + 1] = 0x00;
00140    /* set size of frame in buffer array */
00141    port->txbuflength[idx] = prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + EC_WKCSIZE + length;
00142 
00143    /* return offset to data in rx frame
00144       14 bytes smaller than tx frame due to stripping of ethernet header */
00145    return prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE - ETH_HEADERSIZE;
00146 }
00147 
00148 /** BRW "broadcast write" primitive. Blocking.
00149  *
00150  * @param[in] port        = port context struct
00151  * @param[in] ADP         = Address Position, normally 0
00152  * @param[in] ADO         = Address Offset, slave memory address
00153  * @param[in] length      = length of databuffer
00154  * @param[in] data        = databuffer to be written to slaves
00155  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00156  * @return Workcounter or EC_NOFRAME
00157  */
00158 int ecx_BWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00159 {
00160    uint8 idx;
00161    int wkc;
00162 
00163    /* get fresh index */
00164    idx = ecx_getindex (port);
00165    /* setup datagram */
00166    ecx_setupdatagram (port, &(port->txbuf[idx]), EC_CMD_BWR, idx, ADP, ADO, length, data);
00167    /* send data and wait for answer */
00168    wkc = ecx_srconfirm (port, idx, timeout);
00169    /* clear buffer status */
00170    ecx_setbufstat (port, idx, EC_BUF_EMPTY);
00171 
00172    return wkc;
00173 }
00174 
00175 /** BRD "broadcast read" primitive. Blocking.
00176  *
00177  * @param[in] port        = port context struct
00178  * @param[in]  ADP        = Address Position, normally 0
00179  * @param[in]  ADO        = Address Offset, slave memory address
00180  * @param[in]  length     = length of databuffer
00181  * @param[out] data       = databuffer to put slave data in
00182  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00183  * @return Workcounter or EC_NOFRAME
00184  */
00185 int ecx_BRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00186 {
00187    uint8 idx;
00188    int wkc;
00189 
00190    /* get fresh index */
00191    idx = ecx_getindex(port);
00192    /* setup datagram */
00193    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_BRD, idx, ADP, ADO, length, data);
00194    /* send data and wait for answer */
00195    wkc = ecx_srconfirm (port, idx, timeout);
00196    if (wkc > 0)
00197    {
00198       /* copy datagram to data buffer */
00199       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00200    }
00201    /* clear buffer status */
00202    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00203 
00204    return wkc;
00205 }
00206 
00207 /** APRD "auto increment address read" primitive. Blocking.
00208  *
00209  * @param[in] port        = port context struct
00210  * @param[in]  ADP        = Address Position, each slave ++, slave that has 0 executes
00211  * @param[in]  ADO        = Address Offset, slave memory address
00212  * @param[in]  length     = length of databuffer
00213  * @param[out] data       = databuffer to put slave data in
00214  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00215  * @return Workcounter or EC_NOFRAME
00216  */
00217 int ecx_APRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00218 {
00219    int wkc;
00220    uint8 idx;
00221 
00222    idx = ecx_getindex(port);
00223    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APRD, idx, ADP, ADO, length, data);
00224    wkc = ecx_srconfirm(port, idx, timeout);
00225    if (wkc > 0)
00226    {
00227       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00228    }
00229    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00230 
00231    return wkc;
00232 }
00233 
00234 /** APRMW "auto increment address read, multiple write" primitive. Blocking.
00235  *
00236  * @param[in] port        = port context struct
00237  * @param[in]  ADP        = Address Position, each slave ++, slave that has 0 reads,
00238  *                          following slaves write.
00239  * @param[in]  ADO        = Address Offset, slave memory address
00240  * @param[in]  length     = length of databuffer
00241  * @param[out] data       = databuffer to put slave data in
00242  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00243  * @return Workcounter or EC_NOFRAME
00244  */
00245 int ecx_ARMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00246 {
00247    int wkc;
00248    uint8 idx;
00249 
00250    idx = ecx_getindex(port);
00251    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_ARMW, idx, ADP, ADO, length, data);
00252    wkc = ecx_srconfirm(port, idx, timeout);
00253    if (wkc > 0)
00254    {
00255       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00256    }
00257    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00258 
00259    return wkc;
00260 }
00261 
00262 /** FPRMW "configured address read, multiple write" primitive. Blocking.
00263  *
00264  * @param[in] port        = port context struct
00265  * @param[in]  ADP        = Address Position, slave that has address reads,
00266  *                          following slaves write.
00267  * @param[in]  ADO        = Address Offset, slave memory address
00268  * @param[in]  length     = length of databuffer
00269  * @param[out] data       = databuffer to put slave data in
00270  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00271  * @return Workcounter or EC_NOFRAME
00272  */
00273 int ecx_FRMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00274 {
00275    int wkc;
00276    uint8 idx;
00277 
00278    idx = ecx_getindex(port);
00279    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, ADP, ADO, length, data);
00280    wkc = ecx_srconfirm(port, idx, timeout);
00281    if (wkc > 0)
00282    {
00283       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00284    }
00285    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00286 
00287    return wkc;
00288 }
00289 
00290 /** APRDw "auto increment address read" word return primitive. Blocking.
00291  *
00292  * @param[in] port        = port context struct
00293  * @param[in] ADP         = Address Position, each slave ++, slave that has 0 reads.
00294  * @param[in] ADO         = Address Offset, slave memory address
00295  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00296  * @return word data from slave
00297  */
00298 uint16 ecx_APRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
00299 {
00300    uint16 w;
00301 
00302    w = 0;
00303    ecx_APRD(port, ADP, ADO, sizeof(w), &w, timeout);
00304 
00305    return w;
00306 }
00307 
00308 /** FPRD "configured address read" primitive. Blocking.
00309  *
00310  * @param[in] port        = port context struct
00311  * @param[in]  ADP        = Address Position, slave that has address reads.
00312  * @param[in]  ADO        = Address Offset, slave memory address
00313  * @param[in]  length     = length of databuffer
00314  * @param[out] data       = databuffer to put slave data in
00315  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00316  * @return Workcounter or EC_NOFRAME
00317  */
00318 int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00319 {
00320    int wkc;
00321    uint8 idx;
00322 
00323    idx = ecx_getindex(port);
00324    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, ADP, ADO, length, data);
00325    wkc = ecx_srconfirm(port, idx, timeout);
00326    if (wkc > 0)
00327    {
00328       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00329    }
00330    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00331 
00332    return wkc;
00333 }
00334 
00335 /** FPRDw "configured address read" word return primitive. Blocking.
00336  *
00337  * @param[in] port        = port context struct
00338  * @param[in] ADP         = Address Position, slave that has address reads.
00339  * @param[in] ADO         = Address Offset, slave memory address
00340  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00341  * @return word data from slave
00342  */
00343 uint16 ecx_FPRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
00344 {
00345    uint16 w;
00346 
00347    w = 0;
00348    ecx_FPRD(port, ADP, ADO, sizeof(w), &w, timeout);
00349    return w;
00350 }
00351 
00352 /** APWR "auto increment address write" primitive. Blocking.
00353  *
00354  * @param[in] port        = port context struct
00355  * @param[in] ADP         = Address Position, each slave ++, slave that has 0 writes.
00356  * @param[in] ADO         = Address Offset, slave memory address
00357  * @param[in] length      = length of databuffer
00358  * @param[in] data        = databuffer to write to slave.
00359  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00360  * @return Workcounter or EC_NOFRAME
00361  */
00362 int ecx_APWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00363 {
00364    uint8 idx;
00365    int wkc;
00366 
00367    idx = ecx_getindex(port);
00368    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APWR, idx, ADP, ADO, length, data);
00369    wkc = ecx_srconfirm(port, idx, timeout);
00370    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00371 
00372    return wkc;
00373 }
00374 
00375 /** APWRw "auto increment address write" word primitive. Blocking.
00376  *
00377  * @param[in] port        = port context struct
00378  * @param[in] ADP         = Address Position, each slave ++, slave that has 0 writes.
00379  * @param[in] ADO         = Address Offset, slave memory address
00380  * @param[in] data        = word data to write to slave.
00381  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00382  * @return Workcounter or EC_NOFRAME
00383  */
00384 int ecx_APWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
00385 {
00386    return ecx_APWR(port, ADP, ADO, sizeof(data), &data, timeout);
00387 }
00388 
00389 /** FPWR "configured address write" primitive. Blocking.
00390  *
00391  * @param[in] port        = port context struct
00392  * @param[in] ADP         = Address Position, slave that has address writes.
00393  * @param[in] ADO         = Address Offset, slave memory address
00394  * @param[in] length      = length of databuffer
00395  * @param[in] data        = databuffer to write to slave.
00396  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00397  * @return Workcounter or EC_NOFRAME
00398  */
00399 int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00400 {
00401    int wkc;
00402    uint8 idx;
00403 
00404    idx = ecx_getindex(port);
00405    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPWR, idx, ADP, ADO, length, data);
00406    wkc = ecx_srconfirm(port, idx, timeout);
00407    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00408 
00409    return wkc;
00410 }
00411 
00412 /** FPWR "configured address write" primitive. Blocking.
00413  *
00414  * @param[in] port        = port context struct
00415  * @param[in] ADP         = Address Position, slave that has address writes.
00416  * @param[in] ADO         = Address Offset, slave memory address
00417  * @param[in] data        = word to write to slave.
00418  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00419  * @return Workcounter or EC_NOFRAME
00420  */
00421 int ecx_FPWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
00422 {
00423    return ecx_FPWR(port, ADP, ADO, sizeof(data), &data, timeout);
00424 }
00425 
00426 /** LRW "logical memory read / write" primitive. Blocking.
00427  *
00428  * @param[in] port        = port context struct
00429  * @param[in]     LogAdr  = Logical memory address
00430  * @param[in]     length  = length of databuffer
00431  * @param[in,out] data    = databuffer to write to and read from slave.
00432  * @param[in]     timeout = timeout in us, standard is EC_TIMEOUTRET
00433  * @return Workcounter or EC_NOFRAME
00434  */
00435 int ecx_LRW(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
00436 {
00437    uint8 idx;
00438    int wkc;
00439 
00440    idx = ecx_getindex(port);
00441    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);
00442    wkc = ecx_srconfirm(port, idx, timeout);
00443    if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW))
00444    {
00445       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00446    }
00447    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00448 
00449    return wkc;
00450 }
00451 
00452 /** LRD "logical memory read" primitive. Blocking.
00453  *
00454  * @param[in] port        = port context struct
00455  * @param[in]  LogAdr     = Logical memory address
00456  * @param[in]  length     = length of bytes to read from slave.
00457  * @param[out] data       = databuffer to read from slave.
00458  * @param[in]  timeout    = timeout in us, standard is EC_TIMEOUTRET
00459  * @return Workcounter or EC_NOFRAME
00460  */
00461 int ecx_LRD(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
00462 {
00463    uint8 idx;
00464    int wkc;
00465 
00466    idx = ecx_getindex(port);
00467    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRD, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);
00468    wkc = ecx_srconfirm(port, idx, timeout);
00469    if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRD))
00470    {
00471       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00472    }
00473    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00474 
00475    return wkc;
00476 }
00477 
00478 /** LWR "logical memory write" primitive. Blocking.
00479  *
00480  * @param[in] port        = port context struct
00481  * @param[in] LogAdr      = Logical memory address
00482  * @param[in] length      = length of databuffer
00483  * @param[in] data        = databuffer to write to slave.
00484  * @param[in] timeout     = timeout in us, standard is EC_TIMEOUTRET
00485  * @return Workcounter or EC_NOFRAME
00486  */
00487 int ecx_LWR(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
00488 {
00489    uint8 idx;
00490    int wkc;
00491 
00492    idx = ecx_getindex(port);
00493    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LWR, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);
00494    wkc = ecx_srconfirm(port, idx, timeout);
00495    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00496 
00497    return wkc;
00498 }
00499 
00500 /** LRW "logical memory read / write" primitive plus Clock Distribution. Blocking.
00501  * Frame consists of two datagrams, one LRW and one FPRMW.
00502  *
00503  * @param[in] port        = port context struct
00504  * @param[in]     LogAdr  = Logical memory address
00505  * @param[in]     length  = length of databuffer
00506  * @param[in,out] data    = databuffer to write to and read from slave.
00507  * @param[in]     DCrs    = Distributed Clock reference slave address.
00508  * @param[out]    DCtime  = DC time read from reference slave.
00509  * @param[in]     timeout = timeout in us, standard is EC_TIMEOUTRET
00510  * @return Workcounter or EC_NOFRAME
00511  */
00512 int ecx_LRWDC(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
00513 {
00514    uint16 DCtO;
00515    uint8 idx;
00516    int wkc;
00517    uint64 DCtE;
00518 
00519    idx = ecx_getindex(port);
00520    /* LRW in first datagram */
00521    ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);
00522    /* FPRMW in second datagram */
00523    DCtE = htoell(*DCtime);
00524    DCtO = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, DCrs, ECT_REG_DCSYSTIME, sizeof(DCtime), &DCtE);
00525    wkc = ecx_srconfirm(port, idx, timeout);
00526    if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW))
00527    {
00528       memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
00529       memcpy(&wkc, &(port->rxbuf[idx][EC_HEADERSIZE + length]), EC_WKCSIZE);
00530       memcpy(&DCtE, &(port->rxbuf[idx][DCtO]), sizeof(*DCtime));
00531       *DCtime = etohll(DCtE);
00532    }
00533    ecx_setbufstat(port, idx, EC_BUF_EMPTY);
00534 
00535    return wkc;
00536 }
00537 
00538 #ifdef EC_VER1
00539 int ec_setupdatagram(void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
00540 {
00541    return ecx_setupdatagram (&ecx_port, frame, com, idx, ADP, ADO, length, data);
00542 }
00543 
00544 int ec_adddatagram (void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
00545 {
00546    return ecx_adddatagram (&ecx_port, frame, com, idx, more, ADP, ADO, length, data);
00547 }
00548 
00549 int ec_BWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00550 {
00551    return ecx_BWR (&ecx_port, ADP, ADO, length, data, timeout);
00552 }
00553 
00554 int ec_BRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00555 {
00556    return ecx_BRD(&ecx_port, ADP, ADO, length, data, timeout);
00557 }
00558 
00559 int ec_APRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00560 {
00561    return ecx_APRD(&ecx_port, ADP, ADO, length, data, timeout);
00562 }
00563 
00564 int ec_ARMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00565 {
00566    return ecx_ARMW(&ecx_port, ADP, ADO, length, data, timeout);
00567 }
00568 
00569 int ec_FRMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00570 {
00571    return ecx_FRMW(&ecx_port, ADP, ADO, length, data, timeout);
00572 }
00573 
00574 uint16 ec_APRDw(uint16 ADP, uint16 ADO, int timeout)
00575 {
00576    uint16 w;
00577 
00578    w = 0;
00579    ec_APRD(ADP, ADO, sizeof(w), &w, timeout);
00580 
00581    return w;
00582 }
00583 
00584 int ec_FPRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00585 {
00586    return ecx_FPRD(&ecx_port, ADP, ADO, length, data, timeout);
00587 }
00588 
00589 uint16 ec_FPRDw(uint16 ADP, uint16 ADO, int timeout)
00590 {
00591    uint16 w;
00592 
00593    w = 0;
00594    ec_FPRD(ADP, ADO, sizeof(w), &w, timeout);
00595    return w;
00596 }
00597 
00598 int ec_APWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00599 {
00600    return ecx_APWR(&ecx_port, ADP, ADO, length, data, timeout);
00601 }
00602 
00603 int ec_APWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout)
00604 {
00605    return ec_APWR(ADP, ADO, sizeof(data), &data, timeout);
00606 }
00607 
00608 int ec_FPWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
00609 {
00610    return ecx_FPWR(&ecx_port, ADP, ADO, length, data, timeout);
00611 }
00612 
00613 int ec_FPWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout)
00614 {
00615    return ec_FPWR(ADP, ADO, sizeof(data), &data, timeout);
00616 }
00617 
00618 int ec_LRW(uint32 LogAdr, uint16 length, void *data, int timeout)
00619 {
00620    return ecx_LRW(&ecx_port, LogAdr, length, data, timeout);
00621 }
00622 
00623 int ec_LRD(uint32 LogAdr, uint16 length, void *data, int timeout)
00624 {
00625    return ecx_LRD(&ecx_port, LogAdr, length, data, timeout);
00626 }
00627 
00628 int ec_LWR(uint32 LogAdr, uint16 length, void *data, int timeout)
00629 {
00630    return ecx_LWR(&ecx_port, LogAdr, length, data, timeout);
00631 }
00632 
00633 int ec_LRWDC(uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
00634 {
00635    return ecx_LRWDC(&ecx_port, LogAdr, length, data, DCrs, DCtime, timeout);
00636 }
00637 #endif