예제 #1
0
 /// <summary>
 /// Leaves the load mode. Stops the device that plays EAR pulses
 /// </summary>
 private void LeaveLoadMode()
 {
     _currentMode = TapeOperationMode.Passive;
     _tapePlayer  = null;
     TapeSaveProvider?.Reset();
     HostVm.BeeperDevice.SetTapeOverride(false);
     LeftLoadMode?.Invoke(this, EventArgs.Empty);
 }
예제 #2
0
 /// <summary>
 /// Resets the tape device
 /// </summary>
 public void Reset()
 {
     TapeSaveProvider?.Reset();
     _tapePlayer  = null;
     _currentMode = TapeOperationMode.Passive;
     _savePhase   = SavePhase.None;
     _micBitState = true;
 }
예제 #3
0
 /// <summary>
 /// Puts the device in save mode. From now on, every MIC pulse is recorded
 /// </summary>
 private void EnterSaveMode()
 {
     _currentMode            = TapeOperationMode.Save;
     _savePhase              = SavePhase.None;
     _micBitState            = true;
     _lastMicBitActivityTact = _cpu.Tacts;
     _pilotPulseCount        = 0;
     _prevDataPulse          = MicPulseType.None;
     _dataBlockCount         = 0;
     TapeSaveProvider?.CreateTapeFile();
     EnteredSaveMode?.Invoke(this, EventArgs.Empty);
 }
예제 #4
0
        /// <summary>
        /// Processes the the change of the MIC bit
        /// </summary>
        /// <param name="micBit">MIC bit to process</param>
        public void ProcessMicBit(bool micBit)
        {
            if (_currentMode != TapeOperationMode.Save ||
                _micBitState == micBit)
            {
                return;
            }

            var length = _cpu.Tacts - _lastMicBitActivityTact;

            // --- Classify the pulse by its width
            var pulse = MicPulseType.None;

            if (length >= TapeDataBlockPlayer.BIT_0_PL - SAVE_PULSE_TOLERANCE &&
                length <= TapeDataBlockPlayer.BIT_0_PL + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.Bit0;
            }
            else if (length >= TapeDataBlockPlayer.BIT_1_PL - SAVE_PULSE_TOLERANCE &&
                     length <= TapeDataBlockPlayer.BIT_1_PL + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.Bit1;
            }
            if (length >= TapeDataBlockPlayer.PILOT_PL - SAVE_PULSE_TOLERANCE &&
                length <= TapeDataBlockPlayer.PILOT_PL + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.Pilot;
            }
            else if (length >= TapeDataBlockPlayer.SYNC_1_PL - SAVE_PULSE_TOLERANCE &&
                     length <= TapeDataBlockPlayer.SYNC_1_PL + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.Sync1;
            }
            else if (length >= TapeDataBlockPlayer.SYNC_2_PL - SAVE_PULSE_TOLERANCE &&
                     length <= TapeDataBlockPlayer.SYNC_2_PL + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.Sync2;
            }
            else if (length >= TapeDataBlockPlayer.TERM_SYNC - SAVE_PULSE_TOLERANCE &&
                     length <= TapeDataBlockPlayer.TERM_SYNC + SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.TermSync;
            }
            else if (length < TapeDataBlockPlayer.SYNC_1_PL - SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.TooShort;
            }
            else if (length > TapeDataBlockPlayer.PILOT_PL + 2 * SAVE_PULSE_TOLERANCE)
            {
                pulse = MicPulseType.TooLong;
            }

            _micBitState            = micBit;
            _lastMicBitActivityTact = _cpu.Tacts;

            // --- Lets process the pulse according to the current SAVE phase and pulse width
            var nextPhase = SavePhase.Error;

            switch (_savePhase)
            {
            case SavePhase.None:
                if (pulse == MicPulseType.TooShort || pulse == MicPulseType.TooLong)
                {
                    nextPhase = SavePhase.None;
                }
                else if (pulse == MicPulseType.Pilot)
                {
                    _pilotPulseCount = 1;
                    nextPhase        = SavePhase.Pilot;
                }
                break;

            case SavePhase.Pilot:
                if (pulse == MicPulseType.Pilot)
                {
                    _pilotPulseCount++;
                    nextPhase = SavePhase.Pilot;
                }
                else if (pulse == MicPulseType.Sync1 && _pilotPulseCount >= MIN_PILOT_PULSE_COUNT)
                {
                    nextPhase = SavePhase.Sync1;
                }
                break;

            case SavePhase.Sync1:
                if (pulse == MicPulseType.Sync2)
                {
                    nextPhase = SavePhase.Sync2;
                }
                break;

            case SavePhase.Sync2:
                if (pulse == MicPulseType.Bit0 || pulse == MicPulseType.Bit1)
                {
                    // --- Next pulse starts data, prepare for receiving it
                    _prevDataPulse = pulse;
                    nextPhase      = SavePhase.Data;
                    _bitOffset     = 0;
                    _dataByte      = 0;
                    _dataLength    = 0;
                    _dataBuffer    = new byte[DATA_BUFFER_LENGTH];
                }
                break;

            case SavePhase.Data:
                if (pulse == MicPulseType.Bit0 || pulse == MicPulseType.Bit1)
                {
                    if (_prevDataPulse == MicPulseType.None)
                    {
                        // --- We are waiting for the second half of the bit pulse
                        _prevDataPulse = pulse;
                        nextPhase      = SavePhase.Data;
                    }
                    else if (_prevDataPulse == pulse)
                    {
                        // --- We received a full valid bit pulse
                        nextPhase      = SavePhase.Data;
                        _prevDataPulse = MicPulseType.None;

                        // --- Add this bit to the received data
                        _bitOffset++;
                        _dataByte = (byte)(_dataByte * 2 + (pulse == MicPulseType.Bit0 ? 0 : 1));
                        if (_bitOffset == 8)
                        {
                            // --- We received a full byte
                            _dataBuffer[_dataLength++] = _dataByte;
                            _dataByte  = 0;
                            _bitOffset = 0;
                        }
                    }
                }
                else if (pulse == MicPulseType.TermSync)
                {
                    // --- We received the terminating pulse, the data block has been completed
                    nextPhase = SavePhase.None;
                    _dataBlockCount++;

                    // --- Create and save the data block
                    var dataBlock = new TzxStandardSpeedDataBlock
                    {
                        Data       = _dataBuffer,
                        DataLength = (ushort)_dataLength
                    };

                    // --- If this is the first data block, extract the name from the header
                    if (_dataBlockCount == 1 && _dataLength == 0x13)
                    {
                        // --- It's a header!
                        var sb = new StringBuilder(16);
                        for (var i = 2; i <= 11; i++)
                        {
                            sb.Append((char)_dataBuffer[i]);
                        }
                        var name = sb.ToString().TrimEnd();
                        TapeSaveProvider?.SetName(name);
                    }
                    TapeSaveProvider?.SaveTapeBlock(dataBlock);
                }
                break;
            }
            _savePhase = nextPhase;
        }
예제 #5
0
 /// <summary>
 /// Leaves the save mode. Stops recording MIC pulses
 /// </summary>
 private void LeaveSaveMode()
 {
     _currentMode = TapeOperationMode.Passive;
     LeftSaveMode?.Invoke(this, new SaveModeEventArgs(TapeSaveProvider?.GetFullFileName()));
 }