public int Send(Iec61850State iecs) { // Make COTP data telegramm int offs = IsoTpkt.TPKT_SIZEOF; int maxLen = 1 << options.tpduSize; // max COTP len int maxDataLen = maxLen - COTP_HDR_DT_SIZEOF; // max DATA len if (iecs.sendBytes <= maxDataLen) { // Original handling, same as before / short datagram without fragmenting iecs.sendBuffer[offs++] = COTP_HDR_DT_SIZEOF - 1; // cotp.hdrlen wihout this field iecs.sendBuffer[offs++] = COTP_CODE_DT; // code iecs.sendBuffer[offs++] = COTP_PACKET_COMPLETE; // number "complete" for "short" datagrams iecs.sendBytes += offs; IsoTpkt.Send(iecs); } else { // Long data, need to fragment to TPKT + COTP fragments // Technique: allocate a new buffer. Keep the original data. // Copy original data "per partes" to the new buffer, adding TPKT and COTP headers // and sending the fragments via TCP. // Last COTP fragments must be marked 0x80, others 0x00 // Possible optimization: for the first fragment use the original buffer (spare 1 copy operation) NOT IMPLEMENTED int dLen = iecs.sendBytes; // Actual data length int sLen = 0; // Actual sent data length byte[] originalData = iecs.sendBuffer; iecs.sendBuffer = dataReserveBuffer; // Use saved / recycled buffer dataReserveBuffer = originalData; // Save original buffer to reserve for future use / recycling saves allocation oper. const int dOffs = IsoTpkt.TPKT_SIZEOF + COTP_HDR_DT_SIZEOF; while (dLen > 0) { iecs.sendBytes = Math.Min(dLen, maxDataLen); Array.Copy(originalData, dOffs + sLen, iecs.sendBuffer, dOffs, iecs.sendBytes); dLen -= iecs.sendBytes; sLen += iecs.sendBytes; offs = IsoTpkt.TPKT_SIZEOF; // reinit offset iecs.sendBuffer[offs++] = COTP_HDR_DT_SIZEOF - 1; // cotp.hdrlen wihout this field iecs.sendBuffer[offs++] = COTP_CODE_DT; // code iecs.sendBuffer[offs++] = (byte)((dLen > 0) ? COTP_PACKET_FRAGMENT : COTP_PACKET_COMPLETE); // number "fragment" or "complete" iecs.sendBytes += offs; IsoTpkt.Send(iecs); } } return(0); }
public int SendInit(Iec61850State iecs) { //Reset dstref Reset(iecs.cp); // Make COTP init telegramm int offs = IsoTpkt.TPKT_SIZEOF; int optof = COTP_HDR_IDX_OPTION; iecs.sendBuffer[offs + COTP_HDR_IDX_HDRLEN] = (byte)(COTP_HDR_CR_SIZEOF + options.getSize()); iecs.sendBuffer[offs + COTP_HDR_IDX_CODE] = COTP_CODE_CR; Array.Copy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(m_COTP_dstref)), 0, iecs.sendBuffer, offs + COTP_HDR_IDX_DSTREF, 2); Array.Copy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(m_COTP_srcref)), 0, iecs.sendBuffer, offs + COTP_HDR_IDX_SRCREF, 2); iecs.sendBuffer[offs + optof++] = m_COTP_option; // Parameters iecs.sendBuffer[offs + optof++] = COTP_PCODE_TSIZ; iecs.sendBuffer[offs + optof++] = 1; iecs.sendBuffer[offs + optof++] = options.tpduSize; if (options.tSelDst.size > 0) { iecs.sendBuffer[offs + optof++] = COTP_PCODE_DSAP; iecs.sendBuffer[offs + optof++] = options.tSelDst.size; byte[] bt = options.tSelDst.GetBytes(); Array.Copy(bt, 0, iecs.sendBuffer, offs + optof, options.tSelDst.size); optof += options.tSelDst.size; } if (options.tSelSrc.size > 0) { iecs.sendBuffer[offs + optof++] = COTP_PCODE_SSAP; iecs.sendBuffer[offs + optof++] = options.tSelSrc.size; Array.Copy(options.tSelSrc.GetBytes(), 0, iecs.sendBuffer, offs + optof, options.tSelSrc.size); } iecs.sendBytes = offs + COTP_HDR_CR_SIZEOF + 1 + options.getSize(); IsoTpkt.Send(iecs); return(0); }
int fastSend(Iec61850State iecs) { // Make COTP data telegramm directly int offs = IsoTpkt.TPKT_SIZEOF; // MMS already encoded in iecs.msMMSout iecs.sendBytes = (int)iecs.msMMSout.Length; iecs.sendBuffer[offs++] = 0x02; // cotp.hdrlen iecs.sendBuffer[offs++] = IsoCotp.COTP_CODE_DT; // code iecs.sendBuffer[offs++] = 0x80; // number "complete" iecs.sendBuffer[offs++] = 0x01; // giveTokensPDU.type iecs.sendBuffer[offs++] = 0x00; // giveTokensPDU.hdrlen iecs.sendBuffer[offs++] = 0x01; // dataTransferPDU.type iecs.sendBuffer[offs++] = 0x00; // dataTransferPDU.hdrlen iecs.sendBuffer[offs++] = 0x61; // pres.dtpdu_tag iecs.sendBuffer[offs++] = 0x82; // pres.dtpdu_len_code Array.Copy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(iecs.sendBytes + 15 - 4))), 0, iecs.sendBuffer, offs, 2); // pres.dtpdu_len offs += 2; iecs.sendBuffer[offs++] = 0x30; // pres.sequ_tag iecs.sendBuffer[offs++] = 0x82; // pres.sequ_len_code Array.Copy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(iecs.sendBytes + 15 - 8))), 0, iecs.sendBuffer, offs, 2); // pres.sequ_len offs += 2; iecs.sendBuffer[offs++] = 0x02; // pres.context_tag iecs.sendBuffer[offs++] = 0x01; // pres.context_len iecs.sendBuffer[offs++] = 0x03; // pres.context_val iecs.sendBuffer[offs++] = 0xa0; // pres.data_tag iecs.sendBuffer[offs++] = 0x82; // pres.data_len_code Array.Copy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(iecs.sendBytes))), 0, iecs.sendBuffer, offs, 2); // pres.sequ_len offs += 2; iecs.msMMSout.Seek(0, SeekOrigin.Begin); iecs.msMMSout.Read(iecs.sendBuffer, offs, iecs.sendBytes); iecs.sendBytes += offs; IsoTpkt.Send(iecs); return(0); }