/** LRW "logical memory read / write" primitive plus Clock Distribution. Blocking.
 * Frame consists of two datagrams, one LRW and one FPRMW.
 *
 * @param[in] LogAdr		= Logical memory address
 * @param[in] length		= length of databuffer
 * @param[in,out] data		= databuffer to write to and read from slave.
 * @param[in] DCrs			= Distributed Clock reference slave address.
 * @param[out] DCtime		= DC time read from reference slave.
 * @param[in] timeout		= timeout in us, standard is EC_TIMEOUTRET
 * @return Workcounter or EC_NOFRAME
 */
int ec_LRWDC(uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
{
    uint16 DCtO;
    uint8 idx;
	int wkc;
	uint64 DCtE;

    idx = ec_getindex();
	/* LRW in first datagram */
    ec_setupdatagram(&ec_txbuf[idx], EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);
	/* FPRMW in second datagram */
	DCtE = htoell(*DCtime);
    DCtO = ec_adddatagram(&ec_txbuf[idx], EC_CMD_FRMW, idx, FALSE, DCrs, ECT_REG_DCSYSTIME, sizeof(DCtime), &DCtE);
    wkc = ec_srconfirm(idx, timeout);
    if ((wkc > 0) && (ec_rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW))
    {
        memcpy(data, &ec_rxbuf[idx][EC_HEADERSIZE], length);
		memcpy(&wkc, &ec_rxbuf[idx][EC_HEADERSIZE + length], EC_WKCSIZE);
		memcpy(&DCtE, &ec_rxbuf[idx][DCtO], sizeof(*DCtime));
		*DCtime = etohll(DCtE);
    }
    ec_setbufstat(idx, EC_BUF_EMPTY);

    return wkc;
}
 uint8 PrepareCycPacket(uint8 FrameIndex)
 {
    boolean more=TRUE;
    uint8 idx,cmd,i;
   
   uint8 *data;
   uint16 ADP, ADO;
   uint16 Datalength;
   uint16 IOoffset;
   
   CycFrame[FrameIndex].nInfo=ec_Frame[FrameIndex].NumCmd;
   CycFrame[FrameIndex].timeout=EC_TIMEOUTRET;
   //index
	  idx=ec_getindex();
	  CycFrame[FrameIndex].nIdx=idx;
	  
   //buffer
      CycFrame[FrameIndex].FrameBuffer=&ec_txbuf[idx];
	  CycFrame[FrameIndex].FrameStatus=&ec_rxbufstat[idx];
	  
    for (i=0;i<CycFrame[FrameIndex].nInfo;i++)
	    {
		  if (i==(CycFrame[FrameIndex].nInfo-1))//is the last command?
		      more=FALSE;
			  
			//cmd
		 if (ec_Frame[FrameIndex].FrameCmds[i].state& ec_slave[0].state)
		     cmd=ec_Frame[FrameIndex].FrameCmds[i].cmd;
			 else cmd=EC_CMD_NOP;
			 
		 //length	 
		 Datalength=ec_Frame[FrameIndex].FrameCmds[i].DataLength;
		 CycFrame[FrameIndex].length[i]=Datalength;
		 
		 //data default
		 data=(uint8 *)malloc(Datalength);
		 memset(data, 0, Datalength);
		 
		 //IO map offset
		 IOoffset=ec_Frame[FrameIndex].FrameCmds[i].Offs+DATAOFFS+FrameIndex*PROCOFFS; //(offset of the command in the frame) + (offset of data in the command) + (Number of Frame * 1536)
		 
		 //address & data
		 switch (cmd)
		 { case EC_CMD_LRD:
		      ADP=LO_WORD(ec_Frame[FrameIndex].FrameCmds[i].laddr);
		      ADO=HI_WORD(ec_Frame[FrameIndex].FrameCmds[i].laddr);
			 
			  CycFrame[FrameIndex].RXdatabuffer[i]=&InProc[IOoffset];
		      break;
			  
			case EC_CMD_NOP:
			   ADP=0x0000;
			   ADO=0x0100;
			  break;
			  
			case EC_CMD_LRW:
            case EC_CMD_LWR:
			    ADP=LO_WORD(ec_Frame[FrameIndex].FrameCmds[i].laddr);
		        ADO=HI_WORD(ec_Frame[FrameIndex].FrameCmds[i].laddr);
			    if (ec_slave[0].state==EC_STATE_OPERATIONAL)
			        memcpy(data, &OutProc[IOoffset], Datalength);
				CycFrame[FrameIndex].TXdatabuffer[i]=&OutProc[IOoffset];
                CycFrame[FrameIndex].RXdatabuffer[i]=&InProc[IOoffset];				
				break;
			default:
		    ADP=ec_Frame[FrameIndex].FrameCmds[i].ADP;
			ADO=ec_Frame[FrameIndex].FrameCmds[i].ADO;
		     break;
		 } 
		 //expected wkc
		 CycFrame[FrameIndex].ExpectedWKC[i]=ec_Frame[FrameIndex].FrameCmds[i].cnt;
		 
		 //build frame
		 if (i==0) //the frame is empty?
		      {ec_setupdatagram(&ec_txbuf[idx], cmd, idx, ADP, ADO, Datalength, data);
			  CycFrame[FrameIndex].DataOffset[i]=DATAOFFS+2;} //in ec_rxbuf is stored the frame without Ethernet header (12 byte),
			                                                  //so data of first datagram are located after EtherCAT header(2 byte)
															  //and datagram header (10 byte)
          else
            CycFrame[FrameIndex].DataOffset[i]=ec_adddatagram(&ec_txbuf[idx], cmd, idx, more, ADP, ADO, Datalength, data);
             
    	free(data);	 
		}
	   
	return idx;
}