1 // 2 // Copyright (c) 2010-2023 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 System.Collections.Generic; 10 using System.Linq; 11 using Antmicro.Renode.Exceptions; 12 using Antmicro.Renode.Utilities; 13 14 namespace Antmicro.Renode.Core 15 { 16 [Convertible] 17 public sealed class GPIO : IGPIOWithHooks 18 { GPIO()19 public GPIO() 20 { 21 sync = new object(); 22 targets = new List<GPIOEndpoint>(); 23 stateChangedHook = delegate {}; 24 } 25 Set(bool value)26 public void Set(bool value) 27 { 28 // yup, we're locking on self in order not to create an additional field (and object, more importantly) 29 lock(sync) 30 { 31 if(state == value) 32 { 33 return; 34 } 35 state = value; 36 for(var i = 0; i < targets.Count; ++i) 37 { 38 targets[i].Receiver.OnGPIO(targets[i].Number, state); 39 } 40 stateChangedHook(value); 41 } 42 } 43 Toggle()44 public void Toggle() 45 { 46 lock(sync) 47 { 48 Set(!IsSet); 49 } 50 } 51 Connect(IGPIOReceiver destination, int destinationNumber)52 public void Connect(IGPIOReceiver destination, int destinationNumber) 53 { 54 if(destination == null) 55 { 56 throw new ArgumentNullException("destination"); 57 } 58 Validate(destination, destinationNumber); 59 lock(sync) 60 { 61 if(!targets.Any(x => x.Receiver == destination && x.Number == destinationNumber)) 62 { 63 targets.Add(new GPIOEndpoint(destination, destinationNumber)); 64 destination.OnGPIO(destinationNumber, state); 65 } 66 } 67 } 68 Disconnect()69 public void Disconnect() 70 { 71 lock(sync) 72 { 73 targets.Clear(); 74 } 75 } 76 Disconnect(GPIOEndpoint endpoint)77 public void Disconnect(GPIOEndpoint endpoint) 78 { 79 lock(sync) 80 { 81 targets.Remove(endpoint); 82 } 83 } 84 ToString()85 public override string ToString() 86 { 87 return IsSet ? "GPIO: set" : "GPIO: unset"; 88 } 89 90 public bool IsSet 91 { 92 get 93 { 94 lock(sync) 95 { 96 return state; 97 } 98 } 99 } 100 101 public bool IsConnected 102 { 103 get 104 { 105 lock(sync) 106 { 107 return targets.Count > 0; 108 } 109 } 110 } 111 112 public IList<GPIOEndpoint> Endpoints 113 { 114 get 115 { 116 lock(sync) 117 { 118 return targets; 119 } 120 } 121 } 122 AddStateChangedHook(Action<bool> hook)123 public void AddStateChangedHook(Action<bool> hook) 124 { 125 stateChangedHook += hook; 126 } 127 RemoveStateChangedHook(Action<bool> hook)128 public void RemoveStateChangedHook(Action<bool> hook) 129 { 130 stateChangedHook -= hook; 131 } 132 RemoveAllStateChangedHooks()133 public void RemoveAllStateChangedHooks() 134 { 135 stateChangedHook = delegate {}; 136 } 137 GetAttribute(IGPIOReceiver per)138 private static GPIOAttribute GetAttribute(IGPIOReceiver per) 139 { 140 return (GPIOAttribute)per.GetType().GetCustomAttributes(true).FirstOrDefault(x => x is GPIOAttribute); 141 } 142 Validate(IGPIOReceiver to, int toNumber)143 private static void Validate(IGPIOReceiver to, int toNumber) 144 { 145 var destPeriAttribute = GetAttribute(to); 146 var destPeriInNum = destPeriAttribute != null ? destPeriAttribute.NumberOfInputs : 0; 147 if(destPeriInNum != 0 && toNumber >= destPeriInNum) 148 { 149 throw new ConstructionException(string.Format( 150 "Cannot connect {0}th input of {1}; it has only {2} GPIO inputs.", 151 toNumber, to, destPeriInNum)); 152 } 153 } 154 155 private bool state; 156 private Action<bool> stateChangedHook; 157 private readonly object sync; 158 private readonly IList<GPIOEndpoint> targets; 159 } 160 } 161 162