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 FusionF0710A : II2CPeripheral, IAbsolutePositionPointerInput
19     {
FusionF0710A()20         public FusionF0710A()
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             IRQ.Unset();
29             if(data.Length > 0)
30             {
31                 switch((Command)data[0])
32                 {
33                 case Command.VersionInfoLow:
34                 case Command.VersionInfo:
35                     //just set command. Here to prevent default case.
36                     break;
37                 case Command.Reset:
38                     Reset();
39                     break;
40                 case Command.ScanComplete:
41                     IRQ.Unset();
42                     break;
43                 default:
44                     this.Log(LogLevel.Warning, "Unknown write data: {0}.", data.Select(x => x.ToString("X")).Stringify());
45                     break;
46                 }
47                 lastCommand = (Command)data[0];
48             }
49 
50             PressAgainIfNeeded();
51         }
52 
Read(int count)53         public byte[] Read(int count)
54         {
55             byte[] returnValue;
56             switch(lastCommand)
57             {
58             case Command.VersionInfoLow:
59                 returnValue = new []{ versionInfoLo };
60                 break;
61             case Command.VersionInfo:
62                 returnValue = new []{ versionInfo };
63                 break;
64             case Command.Unset:
65             case Command.Reset:
66             case Command.ScanComplete:
67             default:
68                 returnValue = currentRetValue ?? new byte[12];
69                 this.DebugLog("Read returning {0}.", returnValue.Select(x => x.ToString()).Stringify());
70                 readItAlready = true;
71                 break;
72             }
73             lastCommand = Command.Unset;
74             return returnValue;
75         }
76 
FinishTransmission()77         public void FinishTransmission()
78         {
79         }
80 
Reset()81         public void Reset()
82         {
83             readQueue.Clear();
84             readItAlready = false;
85             pressed = false;
86             currentRetValue = null;
87         }
88 
MoveTo(int x, int y)89         public void MoveTo(int x, int y)
90         {
91             points[0].X = (ushort)(MaxY - y);
92             points[0].Y = (ushort)(MaxX - x);
93             //WARNING! X and Y ARE reversed! Intentionaly!
94             if(points[0].Type == PointType.Down)
95             {
96                 this.DebugLog("Moving the pointer to {0}x{1}", x, y);
97                 EnqueueNewPoint();
98                 IRQ.Set();
99             }
100         }
101 
Press(MouseButton button = MouseButton.Left)102         public void Press(MouseButton button = MouseButton.Left)
103         {
104             pressed = true;
105             points[0].Type = PointType.Down;
106             this.DebugLog("Button pressed, sending press signal at {0}x{1}.", points[0].X, points[0].Y);
107             EnqueueNewPoint();
108             IRQ.Set();
109         }
110 
Release(MouseButton button = MouseButton.Left)111         public void Release(MouseButton button = MouseButton.Left)
112         {
113             this.Log(LogLevel.Noisy, "Sending release signal");
114             points[0].Type = PointType.Up;
115             pressed = false;
116             EnqueueNewPoint();
117             IRQ.Set();
118             this.DebugLog("Button released at {0}x{1}.", points[0].X, points[0].Y);
119         }
120 
121         public GPIO IRQ
122         {
123             get;
124             private set;
125         }
126 
127         public int MinX
128         {
129             get
130             {
131                 return 0;
132             }
133         }
134 
135         public int MinY
136         {
137             get
138             {
139                 return 0;
140             }
141         }
142 
143         public int MaxX
144         {
145             get
146             {
147                 return 2275;
148             }
149         }
150 
151         public int MaxY
152         {
153             get
154             {
155                 return 1275;
156             }
157         }
158 
PressAgainIfNeeded()159         private void PressAgainIfNeeded()
160         {
161             var newPacket = false;
162             if(readQueue.Any())
163             {
164                 this.Log(LogLevel.Noisy, "Another packet to send.");
165                 newPacket = true;
166                 currentRetValue = readQueue.Dequeue();
167                 readItAlready = false;
168             }
169             if(pressed || newPacket || !readItAlready)
170             {
171                 this.Log(LogLevel.Noisy, "Sending signal again at {0}x{1}, state is {2}.", points[0].X, points[0].Y, points[0].Type);
172                 IRQ.Set();
173             }
174             else
175             {
176                 this.Log(LogLevel.Noisy, "No more packets.");
177                 currentRetValue = null;
178             }
179         }
180 
EnqueueNewPoint()181         private void EnqueueNewPoint()
182         {
183             var data = PrepareTouchData();
184             if(currentRetValue == null)
185             {
186                 this.Log(LogLevel.Noisy, "Setting currentRetValue");
187                 currentRetValue = data;
188                 readItAlready = false;
189             }
190             else
191             {
192                 this.Log(LogLevel.Noisy, "Enqueueing packet");
193                 readQueue.Enqueue(data);
194                 if(IRQ.IsSet)
195                 {
196                     this.Log(LogLevel.Noisy, "Forcing IRQ");
197                     IRQ.Unset();
198                     IRQ.Set();
199                 }
200             }
201         }
202 
PrepareTouchData()203         private byte[] PrepareTouchData()
204         {
205             var data = new byte[14];
206             data[0] = 1;
207             for(var i = 0; i < points.Length; i++)
208             {
209                 data[i * 6 + XCoordinateHi] = (byte)(points[i].X >> 8);
210                 data[i * 6 + XCoordinateLo] = (byte)points[i].X;
211                 data[i * 6 + YCoordinateHi] = (byte)(points[i].Y >> 8);
212                 data[i * 6 + YCoordinateLo] = (byte)points[i].Y;
213                 data[i * 6 + PointPressure] = (byte)(points[i].Type == PointType.Down ? 1 : 0);
214                 data[i * 6 + DigitIdentifier] = (byte)((points[i].Type == PointType.Down ? 0x1 : 0) | 0x10); //as seen on HW
215 
216             }
217             return data;
218         }
219 
220         private Queue<byte[]> readQueue = new Queue<byte[]>();
221         private readonly TouchedPoint[] points = new TouchedPoint[2];
222         private byte[] currentRetValue;
223         private bool pressed;
224         private bool readItAlready;
225 
226         private const int XCoordinateHi = 1;
227         private const int XCoordinateLo = 2;
228         private const int YCoordinateHi = 3;
229         private const int YCoordinateLo = 4;
230         private const int PointPressure = 5;
231         private const int DigitIdentifier = 6;
232 
233         private Command lastCommand;
234 
235         //Fake data, update when needed.
236         private byte versionInfo = 0x1;
237         private byte versionInfoLo = 0x2;
238 
239 
240         private enum Command : byte
241         {
242             Unset = 0,
243             VersionInfoLow = 0xE,
244             VersionInfo = 0xF,
245             Reset = 0x10,
246             ScanComplete = 0x11
247         }
248 
249         private struct TouchedPoint
250         {
251             public UInt16 X;
252             public UInt16 Y;
253             public PointType Type;
254         }
255 
256         private enum PointType
257         {
258             Up = 0,
259             Down = 1
260         }
261     }
262 }
263 
264