private void ProcessReceivedFrame() { Frame frame = null; Exception frameError = null; try { var decodedString = Encoding.ASCII.GetString(_buf.ToArray(), 0, _buf.Count); _log.LogInformation("[receive]{0}", ControlCodesUtility.ReplaceControlCodesToLoggingCodes(decodedString)); frame = Frame.Parse(decodedString, _lowLevelSettings); var expectedFN = (_previousFN + 1) % 8; if (frame.FN != expectedFN) { frameError = new FrameNumberException("Expected frame number {0} but was {1}", expectedFN, frame.FN); } _previousFN = frame.FN; } catch (FrameParseException frameParseException) { _log.LogError(frameParseException.Message); frameError = frameParseException; } _buf.Clear(); if (frameError == null) { // Ok _currentRecord += frame.Body; if (frame.FrameType == FrameTypes.TerminationFrame) { _message += _currentRecord + "\r\n"; _currentRecord = ""; } if (!_completed) { _stream.WriteByte((byte)DataLinkControlCodes.ACK); _log.LogInformation("[send]{0}", ControlCodesUtility.ToControlCode((byte)DataLinkControlCodes.ACK)); } } else { if (_completed) { // Frame error _stream.WriteByte((byte)DataLinkControlCodes.NAK); _log.LogInformation("[send]{0}", ControlCodesUtility.ToControlCode((byte)DataLinkControlCodes.NAK)); } } }
/// <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; } }