Exemplo n.º 1
0
        /// <summary>
        /// Save data blocks
        /// </summary>
        /// <param name="vm">Export parameters</param>
        /// <param name="blocksToSave">Collection of data blocks to save</param>
        private static void SaveDataBlocks(ExportZ80ProgramViewModel vm, IEnumerable <byte[]> blocksToSave)
        {
            try
            {
                // --- Create directory
                var dirName = Path.GetDirectoryName(vm.Filename);
                if (dirName != null && !Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }

                // --- Save data blocks
                if (vm.Format == ExportFormat.Tzx)
                {
                    using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                    {
                        var header = new TzxHeader();
                        header.WriteTo(writer);

                        foreach (var block in blocksToSave)
                        {
                            var tzxBlock = new TzxStandardSpeedDataBlock
                            {
                                Data       = block,
                                DataLength = (ushort)block.Length
                            };
                            tzxBlock.WriteTo(writer);
                        }
                    }
                }
                else
                {
                    using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                    {
                        foreach (var block in blocksToSave)
                        {
                            writer.Write((ushort)block.Length);
                            writer.Write(block);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VsxDialogs.Show($"An error has been raised while exporting a program: {ex.Message}",
                                "Errorr when exporting file");
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Playes back a standard speed data block entirely
        /// </summary>
        /// <param name="block">Data block to play back</param>
        public static void CompleteBlock(this TzxStandardSpeedDataBlock block)
        {
            const int  PILOT_PL           = TapeDataBlockPlayer.PILOT_PL;
            const int  HEADER_PILOT_COUNT = TapeDataBlockPlayer.HEADER_PILOT_COUNT;
            const int  SYNC_1_PL          = TapeDataBlockPlayer.SYNC_1_PL;
            const int  SYNC_2_PL          = TapeDataBlockPlayer.SYNC_2_PL;
            const long PILOT_END          = PILOT_PL * HEADER_PILOT_COUNT;
            const int  TERM_SYNC          = TapeDataBlockPlayer.TERM_SYNC;
            const int  PAUSE_MS           = TapeDataBlockPlayer.PAUSE_MS;

            var start = block.StartTact;

            // --- Skip all pilot pulses + the first sync pulse
            for (long pos = 0; pos < PILOT_END + SYNC_1_PL; pos += 50)
            {
                block.GetEarBit(start + pos);
            }

            // --- Skip the second sync pulse
            for (var pos = PILOT_END + SYNC_1_PL + 50; pos < PILOT_END + SYNC_1_PL + SYNC_2_PL; pos += 50)
            {
                block.GetEarBit(start + pos);
            }

            // --- Play back the data
            for (var i = 0; i < block.DataLength; i++)
            {
                block.ReadNextByte();
            }

            // --- Play back the terminating sync
            var nextTact = block.LastTact;

            for (var pos = nextTact; pos < nextTact + TERM_SYNC + 50; pos += 50)
            {
                block.GetEarBit(pos);
            }

            // --- Play back the pause
            nextTact = block.LastTact;
            for (var pos = nextTact; pos < nextTact + PAUSE_MS * block.PauseAfter + 100; pos += 50)
            {
                block.GetEarBit(pos);
            }
        }
        /// <summary>
        /// Save data blocks
        /// </summary>
        /// <param name="vm">Export parameters</param>
        /// <param name="blocksToSave">Collection of data blocks to save</param>
        private static void SaveDataBlocks(ExportZ80ProgramViewModel vm, IEnumerable <byte[]> blocksToSave)
        {
            // --- Create directory
            var dirName = Path.GetDirectoryName(vm.Filename);

            if (dirName != null && !Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }

            // --- Save data blocks
            if (vm.Format == ExportFormat.Tzx)
            {
                using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                {
                    var header = new TzxHeader();
                    header.WriteTo(writer);

                    foreach (var block in blocksToSave)
                    {
                        var tzxBlock = new TzxStandardSpeedDataBlock
                        {
                            Data       = block,
                            DataLength = (ushort)block.Length
                        };
                        tzxBlock.WriteTo(writer);
                    }
                }
            }
            else
            {
                using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                {
                    foreach (var block in blocksToSave)
                    {
                        writer.Write((ushort)block.Length);
                        writer.Write(block);
                    }
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Reads the data byte from the current playback position
        /// </summary>
        /// <param name="block">Block to play back</param>
        /// <returns>Byte read</returns>
        public static byte ReadNextByte(this TzxStandardSpeedDataBlock block)
        {
            const int BIT_0_PL = TapeDataBlockPlayer.BIT_0_PL;
            const int BIT_1_PL = TapeDataBlockPlayer.BIT_1_PL;
            const int STEP     = 50;

            var  nextTact = block.LastTact + STEP;
            byte bits     = 0x00;

            for (var i = 0; i < 8; i++)
            {
                // --- Wait for the high EAR bit
                var samplesLow = 0;
                while (!block.GetEarBit(nextTact))
                {
                    samplesLow++;
                    nextTact += STEP;
                }

                // --- Wait for the low EAR bit
                var samplesHigh = 0;
                while (block.GetEarBit(nextTact) && samplesHigh < BIT_1_PL / STEP + 2)
                {
                    samplesHigh++;
                    nextTact += STEP;
                }

                bits <<= 1;
                if (samplesLow > (BIT_0_PL + BIT_1_PL) / 2 / STEP &&
                    samplesHigh > (BIT_0_PL + BIT_1_PL) / 2 / STEP)
                {
                    bits++;
                }
            }
            return(bits);
        }
Exemplo n.º 5
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 datablock 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();
                        TapeProvider?.SetName(name);
                    }
                    TapeProvider?.SaveTapeBlock(dataBlock);
                }
                break;
            }
            _savePhase = nextPhase;
        }