public void SendNoReply(int slaveAddress, BufferFrame message) { if (slaveAddress == linkLayer.GetBroadcastAddress()) { if (nextBroadcastMessage != null) { throw new LinkLayerBusyException("Broadcast message pending"); } else { nextBroadcastMessage = message; } } else { SlaveConnection slave = GetSlaveConnection(slaveAddress); if (slave != null) { if (slave.IsMessageWaitingToSend()) { throw new LinkLayerBusyException("Message pending"); } else { slave.nextMessage = message; slave.requireConfirmation = false; } } } }
private int SendIMessage(BufferFrame asdu) { byte[] buffer = asdu.GetBuffer(); int msgSize = asdu.GetMsgSize(); /* ASDU size + ACPI size */ buffer [0] = 0x68; /* set size field */ buffer [1] = (byte)(msgSize - 2); buffer [2] = (byte)((sendCount % 128) * 2); buffer [3] = (byte)(sendCount / 128); buffer [4] = (byte)((receiveCount % 128) * 2); buffer [5] = (byte)(receiveCount / 128); try { lock (socketStream) { socketStream.Write(buffer, 0, msgSize); DebugLog("SEND I (size = " + msgSize + ") : " + BitConverter.ToString(buffer, 0, msgSize)); sendCount = (sendCount + 1) % 32768; unconfirmedReceivedIMessages = 0; timeoutT2Triggered = false; } } catch (System.IO.IOException) { // socket error --> close connection running = false; } return(sendCount); }
private void EnqueueUserData(ASDU asdu) { //TODO problem -> buffer frame needs own buffer so that the message can be stored. BufferFrame bf = new BufferFrame(buffer, 0); asdu.Encode(bf, parameters); linkLayerUnbalanced.SendConfirmed(slaveAddress, bf); }
private void EnqueueUserData(ASDU asdu) { lock (userDataQueue) { BufferFrame frame = new BufferFrame(new byte[256], 0); asdu.Encode(frame, parameters); userDataQueue.Enqueue(frame); } }
BufferFrame ISecondaryApplicationLayer.GetCLass2Data() { BufferFrame asdu = DequeueUserDataClass2(); if (asdu == null) { asdu = DequeueUserDataClass1(); } return(asdu); }
/// <summary> /// Callback function forPrimaryLinkLayerBalanced /// </summary> /// <returns>The next ASDU to send</returns> private BufferFrame GetUserData() { BufferFrame asdu = null; if (IsUserDataAvailable()) { return(DequeueUserData()); } return(asdu); }
private void loadFrame(BufferFrame frame) { using var srcmeta = new ComPtr <IWICMetadataQueryReader>(((WicImageFrame)ctx.ImageFrame).WicMetadataReader); frame.Disposal = (GifDisposalMethod)srcmeta.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal) == GifDisposalMethod.RestoreBackground ? GifDisposalMethod.RestoreBackground : GifDisposalMethod.Preserve; frame.Delay = srcmeta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameDelay); frame.Trans = srcmeta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag); frame.Area = ctx.Source.Area; var buff = frame.Source; fixed(byte *pbuff = buff.Span) ctx.Source.CopyPixels(frame.Area, buff.Stride, buff.Span.Length, (IntPtr)pbuff); }
private void SendASDUInternal(ASDU asdu) { if (isActive) { lock (waitingASDUsHighPrio) { BufferFrame frame = new BufferFrame(new byte[256], 6); asdu.Encode(frame, alParameters); waitingASDUsHighPrio.Enqueue(frame); } SendWaitingASDUs(); } }
public void EnqueueUserDataClass2(ASDU asdu) { lock (userDataClass2Queue) { BufferFrame frame = new BufferFrame(new byte[256], 0); asdu.Encode(frame, parameters); userDataClass2Queue.Enqueue(frame); while (userDataClass2Queue.Count > userDataClass2QueueMaxSize) { userDataClass2Queue.Dequeue(); } } }
private void sendNextAvailableASDU() { lock (sentASDUs) { if (isSentBufferFull()) { return; } long timestamp; int index; asduQueue.LockASDUQueue(); BufferFrame asdu = asduQueue.GetNextWaitingASDU(out timestamp, out index); try { if (asdu != null) { int currentIndex = 0; if (oldestSentASDU == -1) { oldestSentASDU = 0; newestSentASDU = 0; } else { currentIndex = (newestSentASDU + 1) % maxSentASDUs; } sentASDUs[currentIndex].entryTime = timestamp; sentASDUs[currentIndex].queueIndex = index; sentASDUs[currentIndex].seqNo = SendIMessage(asdu); sentASDUs[currentIndex].sentTime = SystemUtils.currentTimeMillis(); newestSentASDU = currentIndex; PrintSendBuffer(); } } finally { asduQueue.UnlockASDUQueue(); } } }
public byte[] AsByteArray() { int expectedSize = parameters.MaxAsduLength - spaceLeft; BufferFrame frame = new BufferFrame(new byte[expectedSize], 0); Encode(frame, parameters); if (frame.GetMsgSize() == expectedSize) { return(frame.GetBuffer()); } else { return(null); } }
public void SendConfirmed(int slaveAddress, BufferFrame message) { SlaveConnection slave = GetSlaveConnection(slaveAddress); if (slave != null) { if (slave.nextMessage != null) { throw new LinkLayerBusyException("Message pending"); } else { slave.nextMessage = message.Clone(); slave.requireConfirmation = true; } } }
private void writeFrame(BufferFrame src) { using var quant = new OctreeQuantizer(); using var buffI = new FrameBufferSource(ctx.Source.Width, ctx.Source.Height, PixelFormat.Indexed8Bpp); var buffC = EncodeFrame.Source; quant.CreateHistorgram(buffC.Span, buffC.Width, buffC.Height, buffC.Stride); quant.Quantize(buffC.Span, buffI.Span, buffC.Width, buffC.Height, buffC.Stride, buffI.Stride); var palette = quant.Palette; using var pal = default(ComPtr <IWICPalette>); HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf())); fixed(uint *ppal = palette) HRESULT.Check(pal.Get()->InitializeCustom(ppal, (uint)palette.Length)); ctx.WicContext.DestPalette = pal; ctx.Source = buffI; using var frm = new WicImageEncoderFrame(ctx, encoder, src.Area); using var frmmeta = default(ComPtr <IWICMetadataQueryWriter>); HRESULT.Check(frm.WicEncoderFrame->GetMetadataQueryWriter(frmmeta.GetAddressOf())); frmmeta.SetValue(Wic.Metadata.Gif.FrameDisposal, (byte)src.Disposal); frmmeta.SetValue(Wic.Metadata.Gif.FrameDelay, (ushort)src.Delay); if (src.Area.X != 0) { frmmeta.SetValue(Wic.Metadata.Gif.FrameLeft, (ushort)src.Area.X); } if (src.Area.Y != 0) { frmmeta.SetValue(Wic.Metadata.Gif.FrameTop, (ushort)src.Area.Y); } frmmeta.SetValue(Wic.Metadata.Gif.TransparencyFlag, true); frmmeta.SetValue(Wic.Metadata.Gif.TransparentColorIndex, (byte)(palette.Length - 1)); frm.WriteSource(ctx, src.Area); ctx.WicContext.DestPalette = null; }
public WicAnimatedGifEncoder(PipelineContext ctx, WicImageEncoder enc) { this.ctx = ctx; encoder = enc; lastSource = ctx.Source; lastFrame = ctx.ImageContainer.FrameCount - 1; EncodeFrame = new BufferFrame(lastSource.Width, lastSource.Height, lastSource.Format); for (int i = 0; i < frames.Length; i++) { frames[i] = new BufferFrame(lastSource.Width, lastSource.Height, lastSource.Format); } loadFrame(Current); Current.Source.Span.CopyTo(EncodeFrame.Source.Span); moveToFrame(1); loadFrame(Next !); }
private bool sendNextHighPriorityASDU() { lock (sentASDUs) { if (isSentBufferFull()) { return(false); } BufferFrame asdu = waitingASDUsHighPrio.Dequeue(); if (asdu != null) { int currentIndex = 0; if (oldestSentASDU == -1) { oldestSentASDU = 0; newestSentASDU = 0; } else { currentIndex = (newestSentASDU + 1) % maxSentASDUs; } sentASDUs[currentIndex].queueIndex = -1; sentASDUs[currentIndex].seqNo = SendIMessage(asdu); sentASDUs[currentIndex].sentTime = SystemUtils.currentTimeMillis(); newestSentASDU = currentIndex; PrintSendBuffer(); } else { return(false); } } return(true); }
private void writeFrame(BufferFrame src) { var curFormat = ctx.Source.Format; var newFormat = PixelFormat.Indexed8Bpp; bool alpha = src.Trans || src.Disposal != GifDisposalMethod.RestoreBackground; using var pal = ComHandle.Wrap(Wic.Factory.CreatePalette()); pal.ComObject.InitializeFromBitmap(wicSource, 256u, alpha); ctx.WicContext.DestPalette = pal.ComObject; using var conv = ComHandle.Wrap(Wic.Factory.CreateFormatConverter()); conv.ComObject.Initialize(wicSource, newFormat.FormatGuid, WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion, pal.ComObject, 25.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom); ctx.Source = conv.ComObject.AsPixelSource($"{nameof(IWICFormatConverter)}: {curFormat.Name}->{newFormat.Name}", false); using var frm = new WicImageEncoderFrame(ctx, encoder, src.Area); using var frmmeta = ComHandle.Wrap(frm.WicEncoderFrame.GetMetadataQueryWriter()); var fm = frmmeta.ComObject; fm.SetMetadataByName(Wic.Metadata.Gif.FrameDisposal, new PropVariant((byte)src.Disposal)); fm.SetMetadataByName(Wic.Metadata.Gif.FrameDelay, new PropVariant((ushort)src.Delay)); if (src.Area.X != 0) { fm.SetMetadataByName(Wic.Metadata.Gif.FrameLeft, new PropVariant((ushort)src.Area.X)); } if (src.Area.Y != 0) { fm.SetMetadataByName(Wic.Metadata.Gif.FrameTop, new PropVariant((ushort)src.Area.Y)); } if (alpha) { fm.SetMetadataByName(Wic.Metadata.Gif.TransparencyFlag, new PropVariant(true)); fm.SetMetadataByName(Wic.Metadata.Gif.TransparentColorIndex, new PropVariant((byte)(pal.ComObject.GetColorCount() - 1))); } frm.WriteSource(ctx, src.Area); }
private void EnqueueUserData(ASDU asdu) { if (linkLayerUnbalanced != null) { //TODO problem -> buffer frame needs own buffer so that the message can be stored. BufferFrame frame = new BufferFrame(buffer, 0); asdu.Encode(frame, appLayerParameters); linkLayerUnbalanced.SendConfirmed(slaveAddress, frame); } else { lock (userDataQueue) { BufferFrame frame = new BufferFrame(new byte[256], 0); asdu.Encode(frame, appLayerParameters); userDataQueue.Enqueue(frame); } } }
internal void SendVariableLengthFrameSecondary(FunctionCodeSecondary fc, int address, bool acd, bool dfc, BufferFrame frame) { buffer [0] = 0x68; /* START */ buffer [3] = 0x68; /* START */ byte c = (byte)((int)fc & 0x1f); if (linkLayerMode == LinkLayerMode.BALANCED) { if (dir) { c += 0x80; } } if (acd) { c += 0x20; } if (dfc) { c += 0x10; } buffer [4] = c; int bufPos = 5; if (linkLayerParameters.AddressLength > 0) { buffer [bufPos++] = (byte)(address % 0x100); if (linkLayerParameters.AddressLength > 1) { buffer [bufPos++] = (byte)((address / 0x100) % 0x100); } } byte[] userData = frame.GetBuffer(); int userDataLength = frame.GetMsgSize(); int l = 1 + linkLayerParameters.AddressLength + userDataLength; if (l > 255) { return; } buffer [1] = (byte)l; buffer [2] = (byte)l; for (int i = 0; i < userDataLength; i++) { buffer [bufPos++] = userData[i]; } byte checksum = 0; for (int i = 4; i < bufPos; i++) { checksum += buffer[i]; } buffer [bufPos++] = checksum; buffer [bufPos++] = 0x16; /* END */ if (sentRawMessageHandler != null) { sentRawMessageHandler(sentRawMessageHandlerParameter, buffer, bufPos); } transceiver.SendMessage(buffer, bufPos); }
public void SendVariableLengthFramePrimary(FunctionCodePrimary fc, int address, bool fcb, bool fcv, BufferFrame frame) { buffer [0] = 0x68; /* START */ buffer [3] = 0x68; /* START */ byte c = (byte)fc; if (dir) { c += 0x80; } c += 0x40; // PRM = 1; if (fcv) { c += 0x10; } if (fcb) { c += 0x20; } buffer [4] = c; int bufPos = 5; if (linkLayerParameters.AddressLength > 0) { buffer [bufPos++] = (byte)(address % 0x100); if (linkLayerParameters.AddressLength > 1) { buffer [bufPos++] = (byte)((address / 0x100) % 0x100); } } byte[] userData = frame.GetBuffer(); int userDataLength = frame.GetMsgSize(); for (int i = 0; i < userDataLength; i++) { buffer [bufPos++] = userData[i]; } int l = 1 + linkLayerParameters.AddressLength + frame.GetMsgSize(); if (l > 255) { return; } buffer [1] = (byte)l; buffer [2] = (byte)l; byte checksum = 0; for (int i = 4; i < bufPos; i++) { checksum += buffer[i]; } buffer [bufPos++] = checksum; buffer [bufPos++] = 0x16; /* END */ if (sentRawMessageHandler != null) { sentRawMessageHandler(sentRawMessageHandlerParameter, buffer, bufPos); } transceiver.SendMessage(buffer, bufPos); }
public override void HandleMessage(FunctionCodePrimary fcp, bool isBroadcast, int address, bool fcb, bool fcv, byte[] msg, int userDataStart, int userDataLength) { // check frame count bit if fcv == true if (fcv) { if (CheckFCB(fcb) == false) { return; } } switch (fcp) { case FunctionCodePrimary.REQUEST_LINK_STATUS: DebugLog("SLL - REQUEST LINK STATUS"); { bool accessDemand = applicationLayer.IsClass1DataAvailable(); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.STATUS_OF_LINK_OR_ACCESS_DEMAND, linkLayerAddress, accessDemand, false); } break; case FunctionCodePrimary.RESET_REMOTE_LINK: DebugLog("SLL - RESET REMOTE LINK"); { expectedFcb = true; if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } applicationLayer.ResetCUReceived(false); } break; case FunctionCodePrimary.RESET_FCB: DebugLog("SLL - RESET FCB"); { expectedFcb = true; if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } applicationLayer.ResetCUReceived(true); } break; case FunctionCodePrimary.REQUEST_USER_DATA_CLASS_2: DebugLog("SLL - REQUEST USER DATA CLASS 2"); { BufferFrame asdu = applicationLayer.GetCLass2Data(); bool accessDemand = applicationLayer.IsClass1DataAvailable(); if (asdu != null) { linkLayer.SendVariableLengthFrameSecondary(FunctionCodeSecondary.RESP_USER_DATA, linkLayerAddress, accessDemand, false, asdu); } else { if (linkLayer.linkLayerParameters.UseSingleCharACK && (accessDemand == false)) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.RESP_NACK_NO_DATA, linkLayerAddress, accessDemand, false); } } } break; case FunctionCodePrimary.REQUEST_USER_DATA_CLASS_1: DebugLog("SLL - REQUEST USER DATA CLASS 1"); { BufferFrame asdu = applicationLayer.GetClass1Data(); bool accessDemand = applicationLayer.IsClass1DataAvailable(); if (asdu != null) { linkLayer.SendVariableLengthFrameSecondary(FunctionCodeSecondary.RESP_USER_DATA, linkLayerAddress, accessDemand, false, asdu); } else { if (linkLayer.linkLayerParameters.UseSingleCharACK && (accessDemand == false)) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.RESP_NACK_NO_DATA, linkLayerAddress, accessDemand, false); } } } break; case FunctionCodePrimary.USER_DATA_CONFIRMED: DebugLog("SLL - USER DATA CONFIRMED"); if (userDataLength > 0) { if (applicationLayer.HandleReceivedData(msg, isBroadcast, userDataStart, userDataLength)) { bool accessDemand = applicationLayer.IsClass1DataAvailable(); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, accessDemand, false); } } break; case FunctionCodePrimary.USER_DATA_NO_REPLY: DebugLog("SLL - USER DATA NO REPLY"); if (userDataLength > 0) { applicationLayer.HandleReceivedData(msg, isBroadcast, userDataStart, userDataLength); } break; default: DebugLog("SLL - UNEXPECTED LINK LAYER MESSAGE"); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.LINK_SERVICE_NOT_IMPLEMENTED, linkLayerAddress, false, false); break; } }
public void RunStateMachine() { PrimaryLinkLayerState newState = primaryState; long currentTime = SystemUtils.currentTimeMillis(); switch (primaryState) { case PrimaryLinkLayerState.IDLE: waitingForResponse = false; originalSendTime = 0; lastSendTime = 0; sendLinkLayerTestFunction = false; newState = PrimaryLinkLayerState.EXECUTE_REQUEST_STATUS_OF_LINK; break; case PrimaryLinkLayerState.EXECUTE_REQUEST_STATUS_OF_LINK: if (waitingForResponse) { if (currentTime > (lastSendTime + linkLayer.TimeoutForACK)) { linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_LINK_STATUS, address, false, false); lastSendTime = SystemUtils.currentTimeMillis(); } } else { DebugLog("[SLAVE " + address + "] PLL - SEND RESET REMOTE LINK"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.RESET_REMOTE_LINK, address, false, false); lastSendTime = currentTime; originalSendTime = lastSendTime; waitingForResponse = true; nextFcb = true; newState = PrimaryLinkLayerState.EXECUTE_RESET_REMOTE_LINK; } break; case PrimaryLinkLayerState.EXECUTE_RESET_REMOTE_LINK: if (waitingForResponse) { if (currentTime > (lastSendTime + linkLayer.TimeoutForACK)) { waitingForResponse = false; newState = PrimaryLinkLayerState.IDLE; SetState(LinkLayerState.ERROR); } } else { newState = PrimaryLinkLayerState.LINK_LAYERS_AVAILABLE; SetState(LinkLayerState.AVAILABLE); } break; case PrimaryLinkLayerState.LINK_LAYERS_AVAILABLE: if (sendLinkLayerTestFunction) { DebugLog("[SLAVE " + address + "] PLL - SEND TEST LINK"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.TEST_FUNCTION_FOR_LINK, address, nextFcb, true); nextFcb = !nextFcb; lastSendTime = currentTime; originalSendTime = lastSendTime; waitingForResponse = true; newState = PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM; } else if (requestClass1Data || requestClass2Data) { if (requestClass1Data) { DebugLog("[SLAVE " + address + "] PLL - SEND FC 10 - REQ UD 1"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_USER_DATA_CLASS_1, address, nextFcb, true); } else { DebugLog("[SLAVE " + address + "] PLL - SEND FC 11 - REQ UD 2"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_USER_DATA_CLASS_2, address, nextFcb, true); } nextFcb = !nextFcb; lastSendTime = currentTime; originalSendTime = lastSendTime; waitingForResponse = true; newState = PrimaryLinkLayerState.EXECUTE_SERVICE_REQUEST_RESPOND; } else { if (dontSendMessages == false) { BufferFrame asdu = nextMessage; if (asdu != null) { DebugLog("[SLAVE " + address + "] PLL - SEND FC 03 - USER DATA CONFIRMED"); linkLayer.SendVariableLengthFramePrimary(FunctionCodePrimary.USER_DATA_CONFIRMED, address, nextFcb, true, asdu); lastSentASDU = nextMessage; nextMessage = null; nextFcb = !nextFcb; lastSendTime = currentTime; originalSendTime = lastSendTime; waitingForResponse = true; newState = PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM; } } } break; case PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM: if (currentTime > (lastSendTime + linkLayer.TimeoutForACK)) { if (currentTime > (originalSendTime + linkLayer.TimeoutRepeat)) { DebugLog("[SLAVE " + address + "] TIMEOUT SC: ASDU not confirmed after repeated transmission"); newState = PrimaryLinkLayerState.IDLE; SetState(LinkLayerState.ERROR); } else { DebugLog("[SLAVE " + address + "] TIMEOUT SC: 1 ASDU not confirmed"); if (sendLinkLayerTestFunction) { DebugLog("[SLAVE " + address + "] PLL - SEND FC 02 - RESET REMOTE LINK [REPEAT]"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.TEST_FUNCTION_FOR_LINK, address, !nextFcb, true); } else { DebugLog("[SLAVE " + address + "] PLL - SEND FC 03 - USER DATA CONFIRMED [REPEAT]"); linkLayer.SendVariableLengthFramePrimary(FunctionCodePrimary.USER_DATA_CONFIRMED, address, !nextFcb, true, lastSentASDU); } lastSendTime = currentTime; } } break; case PrimaryLinkLayerState.EXECUTE_SERVICE_REQUEST_RESPOND: if (currentTime > (lastSendTime + linkLayer.TimeoutForACK)) { if (currentTime > (originalSendTime + linkLayer.TimeoutRepeat)) { DebugLog("[SLAVE " + address + "] TIMEOUT: ASDU not confirmed after repeated transmission"); newState = PrimaryLinkLayerState.IDLE; requestClass1Data = false; requestClass2Data = false; SetState(LinkLayerState.ERROR); } else { DebugLog("[SLAVE " + address + "] TIMEOUT: ASDU not confirmed"); if (requestClass1Data) { DebugLog("[SLAVE " + address + "] PLL - SEND FC 10 - REQ UD 1 [REPEAT]"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_USER_DATA_CLASS_1, address, !nextFcb, true); } else if (requestClass2Data) { DebugLog("[SLAVE " + address + "] PLL - SEND FC 11 - REQ UD 2 [REPEAT]"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_USER_DATA_CLASS_2, address, !nextFcb, true); } lastSendTime = currentTime; } } break; case PrimaryLinkLayerState.SECONDARY_LINK_LAYER_BUSY: //TODO - reject new requests from application layer? break; } if (primaryState != newState) { DebugLog("[SLAVE " + address + "] PLL - old state: " + primaryState.ToString() + " new state: " + newState.ToString()); } primaryState = newState; }
public override void RunStateMachine() { PrimaryLinkLayerState newState = primaryState; switch (primaryState) { case PrimaryLinkLayerState.IDLE: waitingForResponse = false; originalSendTime = 0; lastSendTime = 0; sendLinkLayerTestFunction = false; newState = PrimaryLinkLayerState.EXECUTE_REQUEST_STATUS_OF_LINK; break; case PrimaryLinkLayerState.EXECUTE_REQUEST_STATUS_OF_LINK: if (waitingForResponse) { if (SystemUtils.currentTimeMillis() > (lastSendTime + linkLayer.TimeoutForACK)) { linkLayer.SendFixedFramePrimary(FunctionCodePrimary.REQUEST_LINK_STATUS, linkLayerAddressOtherStation, false, false); lastSendTime = SystemUtils.currentTimeMillis(); } } else { DebugLog("PLL - SEND RESET REMOTE LINK to address " + linkLayerAddressOtherStation); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.RESET_REMOTE_LINK, linkLayerAddressOtherStation, false, false); lastSendTime = SystemUtils.currentTimeMillis(); waitingForResponse = true; newState = PrimaryLinkLayerState.EXECUTE_RESET_REMOTE_LINK; } break; case PrimaryLinkLayerState.EXECUTE_RESET_REMOTE_LINK: if (waitingForResponse) { if (SystemUtils.currentTimeMillis() > (lastSendTime + linkLayer.TimeoutForACK)) { waitingForResponse = false; newState = PrimaryLinkLayerState.IDLE; SetNewState(LinkLayerState.ERROR); } } else { newState = PrimaryLinkLayerState.LINK_LAYERS_AVAILABLE; SetNewState(LinkLayerState.AVAILABLE); } break; case PrimaryLinkLayerState.LINK_LAYERS_AVAILABLE: if (sendLinkLayerTestFunction) { DebugLog("PLL - SEND TEST LINK"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.TEST_FUNCTION_FOR_LINK, linkLayerAddressOtherStation, nextFcb, true); nextFcb = !nextFcb; lastSendTime = SystemUtils.currentTimeMillis(); originalSendTime = lastSendTime; newState = PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM; } else { BufferFrame asdu = GetUserData(); if (asdu != null) { linkLayer.SendVariableLengthFramePrimary(FunctionCodePrimary.USER_DATA_CONFIRMED, linkLayerAddressOtherStation, nextFcb, true, asdu); nextFcb = !nextFcb; lastSendASDU = asdu; lastSendTime = SystemUtils.currentTimeMillis(); originalSendTime = lastSendTime; waitingForResponse = true; newState = PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM; } } break; case PrimaryLinkLayerState.EXECUTE_SERVICE_SEND_CONFIRM: if (SystemUtils.currentTimeMillis() > (lastSendTime + linkLayer.TimeoutForACK)) { if (SystemUtils.currentTimeMillis() > (originalSendTime + linkLayer.TimeoutRepeat)) { DebugLog("TIMEOUT: ASDU not confirmed after repeated transmission"); newState = PrimaryLinkLayerState.IDLE; SetNewState(LinkLayerState.ERROR); } else { DebugLog("TIMEOUT: ASDU not confirmed"); if (sendLinkLayerTestFunction) { DebugLog("PLL - REPEAT SEND RESET REMOTE LINK"); linkLayer.SendFixedFramePrimary(FunctionCodePrimary.TEST_FUNCTION_FOR_LINK, linkLayerAddressOtherStation, !nextFcb, true); } else { DebugLog("PLL - repeat last ASDU"); linkLayer.SendVariableLengthFramePrimary(FunctionCodePrimary.USER_DATA_CONFIRMED, linkLayerAddressOtherStation, !nextFcb, true, lastSendASDU); } lastSendTime = SystemUtils.currentTimeMillis(); } } break; case PrimaryLinkLayerState.SECONDARY_LINK_LAYER_BUSY: //TODO - reject new requests from application layer? break; } if (primaryState != newState) { DebugLog("PLL - old state: " + primaryState.ToString() + " new state: " + newState.ToString()); } primaryState = newState; }