Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CpuCoreBase" /> class.
        /// </summary>
        /// <param name="registers">The registers.</param>
        /// <param name="interruptManager">The interrupt manager.</param>
        /// <param name="peripheralManager">The peripheral manager.</param>
        /// <param name="mmu">The mmu.</param>
        /// <param name="instructionTimer">The instruction timer.</param>
        /// <param name="alu">The alu.</param>
        /// <param name="opCodeDecoder">The opcode decoder.</param>
        /// <param name="instructionBlockFactory">The instruction block decoder.</param>
        /// <param name="dmaController">The dma controller.</param>
        /// <param name="messageBus">The message bus.</param>
        /// <param name="requireInstructionBlockCaching">if set to <c>true</c> [require instruction block caching].</param>
        /// <exception cref="ArgumentException">Instruction block decoder must support caching</exception>
        protected CpuCoreBase(IRegisters registers,
                              IInterruptManager interruptManager,
                              IPeripheralManager peripheralManager,
                              IMmu mmu,
                              IInstructionTimer instructionTimer,
                              IAlu alu,
                              IOpCodeDecoder opCodeDecoder,
                              IInstructionBlockFactory instructionBlockFactory,
                              IDmaController dmaController,
                              IMessageBus messageBus,
                              bool requireInstructionBlockCaching)
        {
            CoreId             = Guid.NewGuid();
            _registers         = registers;
            _interruptManager  = interruptManager;
            _peripheralManager = peripheralManager;
            _mmu = mmu;
            _instructionTimer = instructionTimer;
            _alu                     = alu;
            _opCodeDecoder           = opCodeDecoder;
            _instructionBlockFactory = instructionBlockFactory;
            _dmaController           = dmaController;
            _messageBus              = messageBus;
            messageBus.RegisterHandler(Message.PauseCpu, Pause);
            messageBus.RegisterHandler(Message.ResumeCpu, Resume);

            if (requireInstructionBlockCaching && !_instructionBlockFactory.SupportsInstructionBlockCaching)
            {
                throw new ArgumentException("Instruction block decoder must support caching");
            }
        }
Example #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="InterpreterHelper"/> class.
 /// </summary>
 /// <param name="operation">The operation.</param>
 /// <param name="registers">The registers.</param>
 /// <param name="mmu">The mmu.</param>
 /// <param name="alu">The alu.</param>
 /// <param name="peripheralManager">The peripheral manager.</param>
 public InterpreterHelper(IRegisters registers, IMmu mmu, IAlu alu, IPeripheralManager peripheralManager)
 {
     _registers         = registers;
     _mmu               = mmu;
     _alu               = alu;
     _peripheralManager = peripheralManager;
 }
Example #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CacheAwareZ80Mmu"/> class.
 /// </summary>
 /// <param name="peripheralManager">The peripheral manager.</param>
 /// <param name="platformConfig">The platform configuration.</param>
 /// <param name="memoryBankController">The memory bank controller.</param>
 /// <param name="dmaController">The dma controller.</param>
 /// <param name="instructionTimer">The instruction timer.</param>
 public Z80Mmu(IPeripheralManager peripheralManager,
               IPlatformConfig platformConfig,
               IMemoryBankController memoryBankController,
               IDmaController dmaController,
               IInstructionTimer instructionTimer)
     : base(GetAddressSegments(peripheralManager, platformConfig, memoryBankController), dmaController, instructionTimer)
 {
 }
Example #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CacheAwareZ80Mmu"/> class.
 /// </summary>
 /// <param name="peripheralManager">The peripheral manager.</param>
 /// <param name="platformConfig">The platform configuration.</param>
 /// <param name="memoryBankController">The memory bank controller.</param>
 /// <param name="dmaController">The dma controller.</param>
 /// <param name="instructionTimer">The instruction timer.</param>
 public CacheAwareZ80Mmu(IPeripheralManager peripheralManager,
                         IPlatformConfig platformConfig,
                         IMemoryBankController memoryBankController,
                         IDmaController dmaController,
                         IInstructionTimer instructionTimer,
                         IInstructionBlockCache instructionBlockCache)
     : base(peripheralManager, platformConfig, memoryBankController, dmaController, instructionTimer)
 {
     _instructionBlockCache = instructionBlockCache;
 }
Example #5
0
        /// <summary>
        /// Gets the address segments.
        /// </summary>
        /// <param name="peripheralManager">The peripheral manager.</param>
        /// <param name="platformConfig">The platform configuration.</param>
        /// <param name="memoryBankController">The memory bank controller.</param>
        /// <returns></returns>
        private static IEnumerable <IAddressSegment> GetAddressSegments(IPeripheralManager peripheralManager,
                                                                        IPlatformConfig platformConfig,
                                                                        IMemoryBankController memoryBankController)
        {
            var memoryBanks =
                platformConfig.MemoryBanks.GroupBy(x => x.Address)
                .Select(x => GetAddressSegment(x.ToArray(), memoryBankController))
                .ToArray();

            return(memoryBanks.Concat(peripheralManager.MemoryMap));
        }
Example #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CpuCore" /> class.
 /// </summary>
 /// <param name="registers">The registers.</param>
 /// <param name="interruptManager">The interrupt manager.</param>
 /// <param name="peripheralManager">The peripheral manager.</param>
 /// <param name="mmu">The mmu.</param>
 /// <param name="instructionTimer">The instruction timer.</param>
 /// <param name="alu">The alu.</param>
 /// <param name="opCodeDecoder">The opcode decoder.</param>
 /// <param name="instructionBlockFactory">The instruction block decoder.</param>
 /// <param name="dmaController">The dma controller.</param>
 /// <param name="messageBus">The message bus.</param>
 public CpuCore(IRegisters registers,
                IInterruptManager interruptManager,
                IPeripheralManager peripheralManager,
                IMmu mmu,
                IInstructionTimer instructionTimer,
                IAlu alu,
                IOpCodeDecoder opCodeDecoder,
                IInstructionBlockFactory instructionBlockFactory,
                IDmaController dmaController,
                IMessageBus messageBus)
     : base(registers, interruptManager, peripheralManager, mmu, instructionTimer, alu, opCodeDecoder, instructionBlockFactory, dmaController, messageBus, false)
 {
 }
Example #7
0
 public GattServerViewModel(IPeripheralManager peripheralManager)
 {
     this.peripheralManager = peripheralManager;
 }
Example #8
0
        private InstructionTimings Interpret(IRegisters registers, IMmu mmu, IAlu alu, IPeripheralManager peripherals, InterpreterHelper helper, Operation operation, DecodedBlock block)
        {
            helper.Operation = operation;
            var timer = new InstructionTimingsBuilder();

            switch (operation.OpCode)
            {
            case OpCode.NoOperation:
                break;

            case OpCode.Stop:
            case OpCode.Halt:
                SyncProgramCounter(registers, block);
                break;

            case OpCode.Load:
                if (operation.Operand1 == operation.Operand2)
                {
                    break;
                }

                helper.Operand1 = helper.Operand2;
                if (operation.Operand2 == Operand.I || operation.Operand2 == Operand.R)
                {
                    // LD A, R & LD A, I also reset H & N and copy IFF2 to P/V
                    registers.AccumulatorAndFlagsRegisters.Flags.SetResultFlags(registers.AccumulatorAndFlagsRegisters.A);
                    registers.AccumulatorAndFlagsRegisters.Flags.HalfCarry      = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.Subtract       = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.ParityOverflow = registers.InterruptFlipFlop2;
                }
                break;

            case OpCode.Load16:
                helper.WordOperand1 = helper.WordOperand2;
                break;

            case OpCode.Push:
                helper.PushStackPointer();
                mmu.WriteWord(registers.StackPointer, helper.WordOperand1);
                break;

            case OpCode.Pop:
                helper.WordOperand1 = mmu.ReadWord(registers.StackPointer);
                helper.PopStackPointer();
                break;

            case OpCode.Add:
                helper.Alu8BitOperation(alu.Add);
                break;

            case OpCode.AddWithCarry:
                helper.Alu8BitOperation(alu.AddWithCarry);
                break;

            case OpCode.Subtract:
                helper.Alu8BitOperation(alu.Subtract);
                break;

            case OpCode.SubtractWithCarry:
                helper.Alu8BitOperation(alu.SubtractWithCarry);
                break;

            case OpCode.And:
                helper.Alu8BitOperation(alu.And);
                break;

            case OpCode.Or:
                helper.Alu8BitOperation(alu.Or);
                break;

            case OpCode.Xor:
                helper.Alu8BitOperation(alu.Xor);
                break;

            case OpCode.Compare:
                alu.Compare(registers.AccumulatorAndFlagsRegisters.A, helper.Operand1);
                break;

            case OpCode.Increment:
                helper.Operand1 = alu.Increment(helper.Operand1);
                break;

            case OpCode.Decrement:
                helper.Operand1 = alu.Decrement(helper.Operand1);
                break;

            case OpCode.Add16:
                helper.Alu16BitOperation(alu.Add);
                break;

            case OpCode.AddWithCarry16:
                helper.Alu16BitOperation(alu.AddWithCarry);
                break;

            case OpCode.SubtractWithCarry16:
                helper.Alu16BitOperation(alu.SubtractWithCarry);
                break;

            case OpCode.Increment16:
                // INC ss (no flags changes so implemented directly)
                helper.WordOperand1 = (ushort)(helper.WordOperand1 + 1);
                break;

            case OpCode.Decrement16:
                // DEC ss (no flags changes so implemented directly)
                helper.WordOperand1 = (ushort)(helper.WordOperand1 - 1);
                break;

            case OpCode.Exchange:
            {
                var w = helper.WordOperand2;
                helper.WordOperand2 = helper.WordOperand1;
                helper.WordOperand1 = w;
            }
            break;

            case OpCode.ExchangeAccumulatorAndFlags:
                registers.SwitchToAlternativeAccumulatorAndFlagsRegisters();
                break;

            case OpCode.ExchangeGeneralPurpose:
                registers.SwitchToAlternativeGeneralPurposeRegisters();
                break;

            case OpCode.Jump:
                if (operation.FlagTest == FlagTest.None || helper.DoFlagTest())
                {
                    registers.ProgramCounter = helper.WordOperand1;
                }
                else
                {
                    SyncProgramCounter(registers, block);
                }
                break;

            case OpCode.JumpRelative:
                if (operation.FlagTest == FlagTest.None || helper.DoFlagTest())
                {
                    helper.JumpToDisplacement();

                    if (operation.FlagTest != FlagTest.None)
                    {
                        timer.Add(1, 5);
                    }
                }
                SyncProgramCounter(registers, block);
                break;

            case OpCode.DecrementJumpRelativeIfNonZero:
                registers.GeneralPurposeRegisters.B--;
                if (registers.GeneralPurposeRegisters.B != 0)
                {
                    helper.JumpToDisplacement();
                    timer.Add(1, 5);
                }
                SyncProgramCounter(registers, block);
                break;

            case OpCode.Call:
                SyncProgramCounter(registers, block);

                if (operation.FlagTest == FlagTest.None || helper.DoFlagTest())
                {
                    helper.PushStackPointer();
                    mmu.WriteWord(registers.StackPointer, registers.ProgramCounter);
                    registers.ProgramCounter = helper.WordOperand1;

                    if (operation.FlagTest != FlagTest.None)
                    {
                        timer.Add(2, 7);
                    }
                }
                break;

            case OpCode.Return:
                if (operation.FlagTest == FlagTest.None || helper.DoFlagTest())
                {
                    registers.ProgramCounter = mmu.ReadWord(registers.StackPointer);
                    helper.PopStackPointer();

                    if (operation.FlagTest != FlagTest.None)
                    {
                        timer.Add(2, 6);
                    }
                }
                else
                {
                    SyncProgramCounter(registers, block);
                }
                break;

            case OpCode.ReturnFromInterrupt:
                registers.ProgramCounter = mmu.ReadWord(registers.StackPointer);
                helper.PopStackPointer();
                registers.InterruptFlipFlop1 = true;
                break;

            case OpCode.ReturnFromNonmaskableInterrupt:
                registers.ProgramCounter = mmu.ReadWord(registers.StackPointer);
                helper.PopStackPointer();
                registers.InterruptFlipFlop1 = registers.InterruptFlipFlop2;
                break;

            case OpCode.Reset:
                SyncProgramCounter(registers, block);
                helper.PushStackPointer();
                mmu.WriteWord(registers.StackPointer, registers.ProgramCounter);
                registers.ProgramCounter = helper.WordOperand1;
                break;

            case OpCode.Input:
                helper.Operand1 = peripherals.ReadByteFromPort(helper.Operand2,
                                                               operation.Operand2 == Operand.n
                                                                       ? registers.AccumulatorAndFlagsRegisters.A
                                                                       : registers.GeneralPurposeRegisters.B);
                break;

            case OpCode.Output:
                peripherals.WriteByteToPort(helper.Operand2,
                                            operation.Operand2 == Operand.n
                                                    ? registers.AccumulatorAndFlagsRegisters.A
                                                    : registers.GeneralPurposeRegisters.B,
                                            helper.Operand1);
                break;

            case OpCode.RotateLeftWithCarry:
                helper.Operand1 = alu.RotateLeftWithCarry(helper.Operand1);
                if (operation.OpCodeMeta == OpCodeMeta.UseAlternativeFlagAffection)
                {
                    registers.AccumulatorAndFlagsRegisters.Flags.Zero = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.Sign = false;
                }
                break;

            case OpCode.RotateLeft:
                helper.Operand1 = alu.RotateLeft(helper.Operand1);
                if (operation.OpCodeMeta == OpCodeMeta.UseAlternativeFlagAffection)
                {
                    registers.AccumulatorAndFlagsRegisters.Flags.Zero = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.Sign = false;
                }
                break;

            case OpCode.RotateRightWithCarry:
                helper.Operand1 = alu.RotateRightWithCarry(helper.Operand1);
                if (operation.OpCodeMeta == OpCodeMeta.UseAlternativeFlagAffection)
                {
                    registers.AccumulatorAndFlagsRegisters.Flags.Zero = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.Sign = false;
                }
                break;

            case OpCode.RotateRight:
                helper.Operand1 = alu.RotateRight(helper.Operand1);
                if (operation.OpCodeMeta == OpCodeMeta.UseAlternativeFlagAffection)
                {
                    registers.AccumulatorAndFlagsRegisters.Flags.Zero = false;
                    registers.AccumulatorAndFlagsRegisters.Flags.Sign = false;
                }
                break;

            case OpCode.RotateLeftDigit:
            {
                var result = alu.RotateLeftDigit(registers.AccumulatorAndFlagsRegisters.A,
                                                 mmu.ReadByte(registers.GeneralPurposeRegisters.HL));
                registers.AccumulatorAndFlagsRegisters.A = result.Accumulator;
                mmu.WriteByte(registers.GeneralPurposeRegisters.HL, result.Result);
            }
            break;

            case OpCode.RotateRightDigit:
            {
                var result = alu.RotateRightDigit(registers.AccumulatorAndFlagsRegisters.A,
                                                  mmu.ReadByte(registers.GeneralPurposeRegisters.HL));
                registers.AccumulatorAndFlagsRegisters.A = result.Accumulator;
                mmu.WriteByte(registers.GeneralPurposeRegisters.HL, result.Result);
            }
            break;

            case OpCode.ShiftLeft:
                helper.Operand1 = alu.ShiftLeft(helper.Operand1);
                break;

            case OpCode.ShiftLeftSet:
                helper.Operand1 = alu.ShiftLeftSet(helper.Operand1);
                break;

            case OpCode.ShiftRight:
                helper.Operand1 = alu.ShiftRight(helper.Operand1);
                break;

            case OpCode.ShiftRightLogical:
                helper.Operand1 = alu.ShiftRightLogical(helper.Operand1);
                break;

            case OpCode.BitTest:
                alu.BitTest(helper.Operand1, operation.ByteLiteral);
                break;

            case OpCode.BitSet:
                helper.Operand1 = alu.BitSet(helper.Operand1, operation.ByteLiteral);
                break;

            case OpCode.BitReset:
                helper.Operand1 = alu.BitReset(helper.Operand1, operation.ByteLiteral);
                break;

            case OpCode.TransferIncrement:
                helper.BlockTransfer();
                break;

            case OpCode.TransferIncrementRepeat:
                helper.BlockTransferRepeat(timer);
                break;

            case OpCode.TransferDecrement:
                helper.BlockTransfer(true);
                break;

            case OpCode.TransferDecrementRepeat:
                helper.BlockTransferRepeat(timer, true);
                break;

            case OpCode.SearchIncrement:
                helper.BlockSearch();
                break;

            case OpCode.SearchIncrementRepeat:
                helper.BlockSearchRepeat(timer);
                break;

            case OpCode.SearchDecrement:
                helper.BlockSearch(true);
                break;

            case OpCode.SearchDecrementRepeat:
                helper.BlockSearchRepeat(timer, true);
                break;

            case OpCode.InputTransferIncrement:
                helper.InputTransfer();
                break;

            case OpCode.InputTransferIncrementRepeat:
                helper.InputTransferRepeat(timer);
                break;

            case OpCode.InputTransferDecrement:
                helper.InputTransfer(true);
                break;

            case OpCode.InputTransferDecrementRepeat:
                helper.InputTransferRepeat(timer, true);
                break;

            case OpCode.OutputTransferIncrement:
                helper.OutputTransfer();
                break;

            case OpCode.OutputTransferIncrementRepeat:
                helper.OutputTransferRepeat(timer);
                break;

            case OpCode.OutputTransferDecrement:
                helper.OutputTransfer(true);
                break;

            case OpCode.OutputTransferDecrementRepeat:
                helper.OutputTransferRepeat(timer, true);
                break;

            case OpCode.DecimalArithmeticAdjust:
                registers.AccumulatorAndFlagsRegisters.A = alu.DecimalAdjust(registers.AccumulatorAndFlagsRegisters.A,
                                                                             _cpuMode == CpuMode.Z80);
                break;

            case OpCode.NegateOnesComplement:
                registers.AccumulatorAndFlagsRegisters.A = (byte)~registers.AccumulatorAndFlagsRegisters.A;
                registers.AccumulatorAndFlagsRegisters.Flags.SetUndocumentedFlags(registers.AccumulatorAndFlagsRegisters.A);
                registers.AccumulatorAndFlagsRegisters.Flags.HalfCarry = true;
                registers.AccumulatorAndFlagsRegisters.Flags.Subtract  = true;
                break;

            case OpCode.NegateTwosComplement:
                registers.AccumulatorAndFlagsRegisters.A = alu.Subtract(0, registers.AccumulatorAndFlagsRegisters.A);
                break;

            case OpCode.InvertCarryFlag:
                registers.AccumulatorAndFlagsRegisters.Flags.SetUndocumentedFlags(registers.AccumulatorAndFlagsRegisters.A);
                registers.AccumulatorAndFlagsRegisters.Flags.HalfCarry = _cpuMode != CpuMode.GameBoy &&
                                                                         registers.AccumulatorAndFlagsRegisters.Flags.Carry;
                registers.AccumulatorAndFlagsRegisters.Flags.Subtract = false;
                registers.AccumulatorAndFlagsRegisters.Flags.Carry    = !registers.AccumulatorAndFlagsRegisters.Flags.Carry;
                break;

            case OpCode.SetCarryFlag:
                registers.AccumulatorAndFlagsRegisters.Flags.SetUndocumentedFlags(registers.AccumulatorAndFlagsRegisters.A);
                registers.AccumulatorAndFlagsRegisters.Flags.HalfCarry = false;
                registers.AccumulatorAndFlagsRegisters.Flags.Subtract  = false;
                registers.AccumulatorAndFlagsRegisters.Flags.Carry     = true;
                break;

            case OpCode.DisableInterrupts:
                registers.InterruptFlipFlop1 = false;
                registers.InterruptFlipFlop2 = false;
                break;

            case OpCode.EnableInterrupts:
                registers.InterruptFlipFlop1 = true;
                registers.InterruptFlipFlop2 = true;
                break;

            case OpCode.InterruptMode0:
                registers.InterruptMode = InterruptMode.InterruptMode0;
                break;

            case OpCode.InterruptMode1:
                registers.InterruptMode = InterruptMode.InterruptMode1;
                break;

            case OpCode.InterruptMode2:
                registers.InterruptMode = InterruptMode.InterruptMode2;
                break;

            case OpCode.Swap:
                helper.Operand1 = alu.Swap(helper.Operand1);
                break;

            case OpCode.LoadIncrement:
                helper.Operand1 = helper.Operand2;
                registers.GeneralPurposeRegisters.HL++;
                break;

            case OpCode.LoadDecrement:
                helper.Operand1 = helper.Operand2;
                registers.GeneralPurposeRegisters.HL--;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (operation.OpCodeMeta == OpCodeMeta.AutoCopy)
            {
                // Autocopy for DD/FD prefix
                helper.Operand2 = helper.Operand1;
            }

            return(timer.GetInstructionTimings());
        }
Example #9
0
        private InstructionTimings Interpret(IRegisters registers, IMmu mmu, IAlu alu, IPeripheralManager peripherals, DecodedBlock block)
        {
            var helper = new InterpreterHelper(registers, mmu, alu, peripherals);
            var result = block.Operations.Select(o => Interpret(registers, mmu, alu, peripherals, helper, o, block)).Aggregate((t0, t1) => t0 + t1);

            if (_cpuMode == CpuMode.Z80)
            {
                // Add the block length to the 7 lsb of memory refresh register.
                registers.R = (byte)((registers.R + block.Length) & 0x7f);
            }

            return(result);
        }
Example #10
0
        public MainViewModel(IPeripheralManager peripheral)
        {
            this.ToggleServer = ReactiveCommand.CreateFromTask(async _ =>
            {
                if (peripheral.IsAdvertising)
                {
                    this.timer?.Dispose();
                    this.IsRunning = false;
                    peripheral.ClearServices();
                    peripheral.StopAdvertising();
                    this.Write("GATT Server Stopped");
                }
                else
                {
                    await peripheral.AddService
                    (
                        ServiceUuid,
                        true,
                        sb =>
                    {
                        this.notifications = sb.AddCharacteristic
                                             (
                            NotifyCharacteristicUuid,
                            cb => cb.SetNotification(cs =>
                        {
                            var @event = cs.IsSubscribing ? "Subscribed" : "Unsubcribed";
                            this.Write($"Device {cs.Peripheral.Uuid} {@event}");
                            //this.Write($"Charcteristic Subcribers: {characteristic.SubscribedDevices.Count}");
                        })
                                             );

                        sb.AddCharacteristic
                        (
                            ReadWriteCharacteristicUuid,
                            cb => cb
                            .SetRead(req =>
                        {
                            var bytes = Encoding.UTF8.GetBytes(this.CharacteristicValue ?? "Test");
                            this.Write($"Characteristic Read Received - {bytes}");
                            return(ReadResult.Success(bytes));
                        })
                            .SetWrite(req =>
                        {
                            var write = Encoding.UTF8.GetString(req.Data, 0, req.Data.Length);
                            this.Write($"Characteristic Write Received - {write}");
                            return(GattState.Success);
                        })
                        );
                    }
                    );
                    await peripheral.StartAdvertising(new AdvertisementData
                    {
                        LocalName = "My GATT"
                    });
                    this.Write("GATT Server Started");

                    var count  = 0;
                    this.timer = Observable
                                 .Timer(TimeSpan.FromSeconds(10))
                                 // TODO: only when characteristic has subscribers
                                 .Subscribe(async x =>
                    {
                        count++;
                        //await this.notifications.Notify(Encoding.UTF8.GetBytes(count.ToString()));
                    });

                    this.IsRunning = true;
                }
            });

            this.Clear = ReactiveCommand.Create(() => this.Output = String.Empty);
        }
Example #11
0
        public MainViewModel(IPeripheralManager peripheral, IUserDialogs dialogs)
        {
            this.dialogs = dialogs;

            this.ToggleServer = ReactiveCommand.CreateFromTask(async _ =>
            {
                if (peripheral.IsAdvertising)
                {
                    this.timer?.Dispose();
                    this.IsRunning = false;
                    peripheral.ClearServices();
                    peripheral.StopAdvertising();
                    this.Write("GATT Server Stopped");
                }
                else
                {
                    await peripheral.AddService
                    (
                        ServiceUuid,
                        true,
                        sb =>
                    {
                        this.notifications = sb.AddCharacteristic
                                             (
                            NotifyCharacteristicUuid,
                            cb => cb.SetNotification(cs =>
                        {
                            var subs = cs.Characteristic.SubscribedCentrals.Count;

                            var @event = cs.IsSubscribing ? "Subscribed" : "Unsubcribed";
                            this.Write($"Device {cs.Peripheral.Uuid} {@event}");
                            this.Write($"Charcteristic Subcribers: {subs}");

                            if (subs == 0)
                            {
                                this.StopTimer();
                            }
                            else
                            {
                                this.StartTimer();
                            }
                        })
                                             );

                        sb.AddCharacteristic
                        (
                            ReadWriteCharacteristicUuid,
                            cb => cb
                            .SetRead(req =>
                        {
                            var value = this.CharacteristicValue ?? "Test";
                            var bytes = Encoding.UTF8.GetBytes(value);
                            this.Write($"Characteristic Read Received - Sent {value}");
                            return(ReadResult.Success(bytes));
                        })
                            .SetWrite(req =>
                        {
                            var write = Encoding.UTF8.GetString(req.Data, 0, req.Data.Length);
                            this.Write($"Characteristic Write Received - {write}");
                            return(GattState.Success);
                        })
                        );
                    }
                    );
                    await peripheral.StartAdvertising(new AdvertisementData
                    {
                        LocalName = "My GATT"
                    });
                    this.Write("GATT Server Started with Name: My GATT");
                    this.IsRunning = true;
                }
            });

            this.Clear = ReactiveCommand.Create(() => this.Output = String.Empty);
        }
Example #12
0
 /// <summary>
 /// Executes the instruction block.
 /// </summary>
 /// <param name="registers">The registers.</param>
 /// <param name="mmu">The mmu.</param>
 /// <param name="alu">The alu.</param>
 /// <param name="peripheralManager">The peripheral manager.</param>
 /// <returns></returns>
 public InstructionTimings ExecuteInstructionBlock(IRegisters registers,
                                                   IMmu mmu,
                                                   IAlu alu,
                                                   IPeripheralManager peripheralManager) => _action(registers, mmu, alu, peripheralManager) + _staticTimings;