1 //
2 // Copyright (c) 2010-2022 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Threading;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Time;
13 
14 namespace Antmicro.Renode.Peripherals
15 {
16     public class PWMTester : IGPIOReceiver, IExternal
17     {
PWMTester()18         public PWMTester()
19         {
20             innerLock = new object();
21         }
22 
OnGPIO(int number, bool value)23         public void OnGPIO(int number, bool value)
24         {
25             if(number != 0)
26             {
27                 throw new ArgumentException("This tester should be attached by pin 0 only");
28             }
29 
30             if(!TimeDomainsManager.Instance.TryGetVirtualTimeStamp(out var vts))
31             {
32                 return;
33             }
34 
35             lock(innerLock)
36             {
37                 if(previousEvent != null)
38                 {
39                     TimeInterval dt;
40                     // TODO: Below `if` block is a way to avoid TimeInterval underflow and the resulting exception
41                     // that occurs when the OnGPIO comes from a different thread(core) than expected.
42                     // This should be fixed by making sure we always get the Timestamp from the correct thread.
43                     // Until then the results will be radomly less accurate.
44                     if(vts.TimeElapsed > previousEvent.Value.TimeElapsed)
45                     {
46                         dt = vts.TimeElapsed - previousEvent.Value.TimeElapsed;
47                     }
48                     else
49                     {
50                         dt = TimeInterval.Empty;
51                     }
52 
53                     if(value)
54                     {
55                         // we switch to high, so up to this point it was low
56                         LowTicks += dt.Ticks;
57                     }
58                     else
59                     {
60                         HighTicks += dt.Ticks;
61                     }
62                 }
63                 previousEvent = vts;
64             }
65         }
66 
Reset()67         public void Reset()
68         {
69             lock(innerLock)
70             {
71                 LowTicks = 0;
72                 HighTicks = 0;
73                 previousEvent = null;
74             }
75         }
76 
ToString()77         public override string ToString()
78         {
79             return $"HIGH {HighTicks} ({HighPercentage}%) LOW {LowTicks} ({LowPercentage}%)";
80         }
81 
82         public ulong LowTicks { get; private set; }
83         public ulong HighTicks { get; private set; }
84         public double HighPercentage => (double)HighTicks / (HighTicks + LowTicks) * 100;
85         public double LowPercentage => (double)LowTicks / (HighTicks + LowTicks) * 100;
86 
87         private readonly object innerLock;
88         private TimeStamp? previousEvent;
89     }
90 }
91