1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Time; 11 12 namespace Antmicro.Renode.Peripherals.Miscellaneous 13 { 14 public class Button : IPeripheral, IGPIOSender 15 { 16 // Registration address ('gpio 3' in the example below) has no influence on the button's logic. 17 // It's just a way to inform the peripherals tree ('peripherals' command) how the button is 18 // connected to the GPIO controller. The actual connection is done with '-> gpio@3'. 19 // 20 // button: Miscellaneous.Button @ gpio 3 21 // -> gpio@3 Button(bool invert = false)22 public Button(bool invert = false) 23 { 24 ReleaseOnReset = true; 25 Inverted = invert; 26 IRQ = new GPIO(); 27 28 Reset(); 29 } 30 Reset()31 public void Reset() 32 { 33 if(ReleaseOnReset) 34 { 35 Press(); 36 Release(); 37 } 38 else 39 { 40 // Toggle the button twice to refresh it's state to the same value as before the reset 41 Toggle(); 42 Toggle(); 43 } 44 } 45 PressAndRelease()46 public void PressAndRelease() 47 { 48 Press(); 49 Release(); 50 } 51 Press()52 public void Press() 53 { 54 SetGPIO(!Inverted); 55 Pressed = true; 56 OnStateChange(true); 57 } 58 Release()59 public void Release() 60 { 61 SetGPIO(Inverted); 62 Pressed = false; 63 OnStateChange(false); 64 } 65 Toggle()66 public void Toggle() 67 { 68 if(Pressed) 69 { 70 Release(); 71 } 72 else 73 { 74 Press(); 75 } 76 } 77 78 public GPIO IRQ { get; } 79 80 public event Action<bool> StateChanged; 81 82 public bool Pressed { get; private set; } 83 84 public bool Inverted { get; private set; } 85 86 public bool ReleaseOnReset { get; set; } 87 OnStateChange(bool pressed)88 private void OnStateChange(bool pressed) 89 { 90 var sc = StateChanged; 91 if (sc != null) 92 { 93 sc(pressed); 94 } 95 } 96 SetGPIO(bool value)97 private void SetGPIO(bool value) 98 { 99 if(!this.TryGetMachine(out var machine)) 100 { 101 // can happen during button creation 102 IRQ.Set(value); 103 return; 104 } 105 if(!TimeDomainsManager.Instance.TryGetVirtualTimeStamp(out var vts)) 106 { 107 // this is almost always the case, but maybe someday we'll be able to press the 108 // button by a machine-controlled actuator 109 vts = new TimeStamp(default(TimeInterval), EmulationManager.ExternalWorld); 110 } 111 112 machine.HandleTimeDomainEvent(IRQ.Set, value, vts); 113 } 114 } 115 } 116