1 //
2 // Copyright (c) 2010-2020 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.Peripherals.I2C;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Utilities;
13 using System.Linq;
14 using System.Collections.Generic;
15 
16 namespace Antmicro.Renode.Peripherals.Input
17 {
18     public class AR1021 : II2CPeripheral, IAbsolutePositionPointerInput
19     {
AR1021()20         public AR1021()
21         {
22             IRQ = new GPIO();
23         }
24 
Write(byte[] data)25         public void Write(byte[] data)
26         {
27             this.DebugLog("Writing {0}.", data.Select(x => x.ToString()).Stringify());
28         }
29 
Read(int count)30         public byte[] Read(int count)
31         {
32             var returnValue = currentRetValue ?? new byte[5];
33             this.DebugLog("Read returning {0}.", returnValue.Select(x => x.ToString()).Stringify());
34             readItAlready = true;
35             return returnValue;
36         }
37 
FinishTransmission()38         public void FinishTransmission()
39         {
40         }
41 
Reset()42         public void Reset()
43         {
44             readQueue.Clear();
45             readItAlready = false;
46             pressed = false;
47             currentRetValue = null;
48         }
49 
MoveTo(int x, int y)50         public void MoveTo(int x, int y)
51         {
52             points[0].X = (ushort)(y);
53             points[0].Y = (ushort)(x);
54             if(points[0].Type == PointType.Down)
55             {
56                 this.DebugLog("Moving the pointer to {0}x{1}", x, y);
57                 EnqueueNewPoint();
58                 IRQ.Set();
59             }
60         }
61 
Press(MouseButton button = MouseButton.Left)62         public void Press(MouseButton button = MouseButton.Left)
63         {
64             pressed = true;
65             points[0].Type = PointType.Down;
66             this.DebugLog("Button pressed, sending press signal at {0}x{1}.", points[0].X, points[0].Y);
67             EnqueueNewPoint();
68             IRQ.Set();
69         }
70 
Release(MouseButton button = MouseButton.Left)71         public void Release(MouseButton button = MouseButton.Left)
72         {
73             this.Log(LogLevel.Noisy, "Sending release signal");
74             points[0].Type = PointType.Up;
75             pressed = false;
76             EnqueueNewPoint();
77             IRQ.Set();
78             this.DebugLog("Button released at {0}x{1}.", points[0].X, points[0].Y);
79         }
80 
81         public GPIO IRQ
82         {
83             get;
84             private set;
85         }
86 
87         public int MaxY
88         {
89             get{ return 4095; }
90         }
91 
92         public int MaxX
93         {
94             get{ return 4095; }
95         }
96 
97         public int MinX
98         {
99             get { return 0; }
100         }
101 
102         public int MinY
103         {
104             get { return 0; }
105         }
106 
PressAgainIfNeeded()107         private void PressAgainIfNeeded()
108         {
109             var newPacket = false;
110             if(readQueue.Any())
111             {
112                 this.Log(LogLevel.Noisy, "Another packet to send.");
113                 newPacket = true;
114                 currentRetValue = readQueue.Dequeue();
115                 readItAlready = false;
116             }
117             if(pressed || newPacket || !readItAlready)
118             {
119                 this.Log(LogLevel.Noisy, "Sending signal again at {0}x{1}, state is {2}.", points[0].X, points[0].Y, points[0].Type);
120                 IRQ.Set();
121             }
122             else
123             {
124                 this.Log(LogLevel.Noisy, "No more packets.");
125                 currentRetValue = null;
126             }
127         }
128 
EnqueueNewPoint()129         private void EnqueueNewPoint()
130         {
131             var data = PrepareTouchData();
132             if(currentRetValue == null)
133             {
134                 this.Log(LogLevel.Noisy, "Setting currentRetValue");
135                 currentRetValue = data;
136                 readItAlready = false;
137             }
138             else
139             {
140                 this.Log(LogLevel.Noisy, "Enqueueing packet");
141                 readQueue.Enqueue(data);
142                 if(IRQ.IsSet)
143                 {
144                     this.Log(LogLevel.Noisy, "Forcing IRQ");
145                     IRQ.Unset();
146                     IRQ.Set();
147                 }
148             }
149         }
150 
PrepareTouchData()151         private byte[] PrepareTouchData()
152         {
153             var data = new byte[5];
154             data[0] = (byte)(0x80 | ((points[0].Type == PointType.Down) ? 0x1 : 0));
155             data[2] = (byte)((points[0].X >> 7) & 0x1f);
156             data[1] = (byte)(points[0].X & 0x7f);
157             data[4] = (byte)((points[0].Y >> 7) & 0x1f);
158             data[3] = (byte)(points[0].Y & 0x7f);
159             return data;
160         }
161 
162         private Queue<byte[]> readQueue = new Queue<byte[]>();
163         private readonly TouchedPoint[] points = new TouchedPoint[1];
164         private byte[] currentRetValue;
165         private bool pressed;
166         private bool readItAlready;
167 
168         private enum Command : byte
169         {
170             Reset = 0x10,
171             ScanComplete = 0x11
172         }
173 
174         private struct TouchedPoint
175         {
176             public UInt16 X;
177             public UInt16 Y;
178             public PointType Type;
179         }
180 
181         private enum PointType
182         {
183             Up = 0,
184             Down = 1
185         }
186     }
187 }
188