/// <summary> /// Читает максимум один фрейм и возвращает управление. При этом сохраняет свое состояние и ждет повторного вызова /// чтобы выкачать все сообщение. /// </summary> /// <exception cref="ASTMIOException">Любая ошибка упаковывается в этот класс как InnerException</exception> /// <exception cref="TimeoutException">Тихо в лесу</exception> public void ExecuteDownloadStep() { if (Completed) { throw new InvalidOperationException("Download has been completed already"); } switch (_state) { case States.WaitEstablishmentPhase: _stream.ReadTimeout = 100; var b = (byte)_stream.ReadByte(); if (b == (byte)DataLinkControlCodes.ENQ) { _log.LogInformation($"[receive]{ControlCodesUtility.ToControlCode(b)}"); _stream.WriteByte((byte)DataLinkControlCodes.ACK); _log.LogInformation($"[send]{ControlCodesUtility.ToControlCode((byte) DataLinkControlCodes.ACK)}"); _state = States.ReceiveFrame; } else { _log.LogDebug($"[receive]{(char) b}"); } break; case States.ReceiveFrame: if (!_timersManager.IsTimerInStartedState(WAIT_FRAME_TIMER_NAME)) { _timersManager.StartTimer(WAIT_FRAME_TIMER_NAME, _lowLevelSettings.WaitFrameTimeout); } try { _stream.ReadTimeout = 100; b = (byte)_stream.ReadByte(); if (b == (byte)DataLinkControlCodes.EOT) { _timersManager.StopTimer(WAIT_FRAME_TIMER_NAME); _log.LogInformation("[receive]{0}", ControlCodesUtility.ToControlCode(b)); _state = States.Completed; _completed = true; break; } _buf.Add(b); if (b == (byte)DataLinkControlCodes.LF) { ProcessReceivedFrame(); _timersManager.StopTimer(WAIT_FRAME_TIMER_NAME); } _state = States.ReceiveFrame; } catch (TimeoutException timeoutException) { if (_timersManager.CheckTimerTimeout(WAIT_FRAME_TIMER_NAME)) { throw new DataLinkLayerException(timeoutException, "Wait frame timeout"); } } break; case States.Completed: throw new InvalidOperationException("Download has been completed already"); } }
/// <summary> /// Закачивает максимум один фрейм и возвращает управление. При этом сохраняет свое состояние и ждет повторного вызова, /// для того что бы закончить upload. /// </summary> /// <exception cref="UploadException">Выгрузка прервана из-за ошибок</exception> /// <exception cref="InvalidOperationException">Выгрузка уже закончена</exception> public void ExecuteUploadStep() { byte[] buf = null; if (Completed) { throw new InvalidOperationException("Upload has been completed already"); } if (!_timersManager.CheckTimerTimeout(WAIT_DELAY_TIMER_NAME)) { return; } switch (_state) { case States.EstablishmentPhaseBegin: _stream.WriteByte((byte)DataLinkControlCodes.ENQ); _log.LogInformation("[send]{0}", ControlCodesUtility.ToControlCode((byte)DataLinkControlCodes.ENQ)); _timersManager.StartTimer(WAIT_ANSWER_TIMER_NAME, _lowLevelSettings.EnqWaitTimeout); _state = States.EstablishmentPhaseWaitAnswer; break; case States.EstablishmentPhaseWaitAnswer: try { _stream.ReadTimeout = 100; var b = (byte)_stream.ReadByte(); _timersManager.StopTimer(WAIT_ANSWER_TIMER_NAME); _log.LogInformation("[receive]{0}", ControlCodesUtility.ToControlCode(b)); if (b == (byte)DataLinkControlCodes.ACK) { _state = States.TransferPhaseSendFrame; } else if (b == (byte)DataLinkControlCodes.ENQ) { if (_havePriority) { _errorCounterENQ++; if (_errorCounterENQ >= 2) { throw new DataLinkLayerException(new UnexpectedENQException(), "Remote system is stupid cow"); } _timersManager.StartTimer(WAIT_DELAY_TIMER_NAME, 1000); _state = States.EstablishmentPhaseBegin; } else { throw new DataLinkLayerException(new ContentionErrorException(), "Contention error occured"); } } else if (b == (byte)DataLinkControlCodes.NAK) { _errorCounterNAK++; if (_errorCounterNAK >= 6) { _exceptionOccured = new DataLinkLayerException(new BusyException(), "Remote system busy while Establishment Phase"); _state = States.TerminationPhase; } else { _state = States.EstablishmentPhaseBegin; _timersManager.StartTimer(WAIT_DELAY_TIMER_NAME, 1000); } } else { _exceptionOccured = new DataLinkLayerException(new DefectiveResponseException(), "Defective response error occured while Establishment Phase"); _state = States.TerminationPhase; } } catch (TimeoutException timeoutException) { if (_timersManager.CheckTimerTimeout(WAIT_ANSWER_TIMER_NAME)) { _exceptionOccured = new DataLinkLayerException(timeoutException, "Remote device doesn't response while Establishment Phase"); _state = States.TerminationPhase; } } break; case States.TransferPhaseSendFrame: _errorCounterDefective = 0; _errorCounterNAK = 0; _frameCounter++; if (_frameCounter >= _frames.Length) { _state = States.TerminationPhase; break; } _currentFrame = _frames[_frameCounter]; buf = Encoding.ASCII.GetBytes(_currentFrame.ToString()); _stream.Write(buf, 0, buf.Length); _log.LogInformation("[send]{0}", ControlCodesUtility.ReplaceControlCodesToLoggingCodes(_currentFrame.ToString())); _timersManager.StartTimer(WAIT_ANSWER_TIMER_NAME, 15000); _state = States.TransferPhaseWaitAnswer; break; case States.TransferPhaseResendFrame: buf = Encoding.ASCII.GetBytes(_currentFrame.ToString()); _stream.Write(buf, 0, buf.Length); _log.LogInformation("[send]{0}", ControlCodesUtility.ReplaceControlCodesToLoggingCodes(_currentFrame.ToString())); _timersManager.StartTimer(WAIT_ANSWER_TIMER_NAME, 15000); _state = States.TransferPhaseWaitAnswer; break; case States.TransferPhaseWaitAnswer: try { _stream.ReadTimeout = 100; var b = (byte)_stream.ReadByte(); _timersManager.StopTimer(WAIT_ANSWER_TIMER_NAME); _log.LogInformation("[receive]{0}", ControlCodesUtility.ToControlCode(b)); if (b == (byte)DataLinkControlCodes.ACK) { _state = States.TransferPhaseSendFrame; } else if (b == (byte)DataLinkControlCodes.NAK || b == (byte)DataLinkControlCodes.EOT) { _errorCounterNAK++; if (_errorCounterNAK >= 6) { _state = States.TerminationPhase; _exceptionOccured = new DataLinkLayerException(new BusyException(), "Remote system busy while Transfer Phase"); } else { _state = States.TransferPhaseResendFrame; _timersManager.StartTimer(WAIT_DELAY_TIMER_NAME, 10000); } } else { _errorCounterDefective++; if (_errorCounterDefective >= 6) { _state = States.TerminationPhase; _exceptionOccured = new DataLinkLayerException(new DefectiveResponseException(), "Remote system response defective while Transfer Phase"); } else { _state = States.TransferPhaseResendFrame; } } } catch (TimeoutException timeoutException) { if (_timersManager.CheckTimerTimeout(WAIT_ANSWER_TIMER_NAME)) { _state = States.TerminationPhase; _exceptionOccured = new DataLinkLayerException(timeoutException, "Remote device doesn't response while Transfer Phase"); } } break; case States.TerminationPhase: _stream.WriteByte((byte)DataLinkControlCodes.EOT); _log.LogInformation("[send]{0}", ControlCodesUtility.ToControlCode((byte)DataLinkControlCodes.EOT)); if (_exceptionOccured != null) { throw _exceptionOccured; } else { _uploadCompleted = true; } break; } }