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.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.I2C;
12 using System.Linq;
13 using System.Collections.Generic;
14 using Antmicro.Renode.Utilities;
15 using System.Threading.Tasks;
16 using System.Threading;
17 
18 
19 namespace Antmicro.Renode.Peripherals.Input
20 {
21     public class FT5x06 : II2CPeripheral, IAbsolutePositionPointerInput
22     {
23         public int MaxX
24         {
25             get
26             {
27                 return NumX * 64 - 1;
28             }
29         }
30         public int MaxY
31         {
32             get
33             {
34                 return NumY * 64 - 1;
35             }
36         }
37          public int MinX
38         {
39             get
40             {
41                 return 0;
42             }
43         }
44 
45         public int MinY
46         {
47             get
48             {
49                 return 0;
50             }
51         }
FT5x06(int maxPoints = 5)52         public FT5x06 (int maxPoints = 5)
53         {
54             maxSupportedPoints = maxPoints;
55             points = new TouchedPoint[maxSupportedPoints];
56             for (ushort i = 0; i< points.Length; ++i) {
57                 points [i] = new TouchedPoint ()
58                 {
59                     Type=PointType.Reserved,
60                     X = 0,
61                     Y = 0,
62                     Id = i
63                 };
64             }
65             IRQ = new GPIO ();
66             Reset ();
67         }
68 
FinishTransmission()69         public void FinishTransmission()
70         {
71         }
72 
Reset()73         public void Reset ()
74         {
75             currentRetValue = null;
76         }
Write(byte[] data)77         public void Write (byte[] data)
78         {
79             this.NoisyLog ("Write {0}",
80                         data.Select (x => x.ToString ("X")).Aggregate ((x,y) => x + " " + y));
81             switch ((Mode)data [0]) {
82             case Mode.Model:
83                 currentRetValue = new System.Text.ASCIIEncoding ().GetBytes (" EP0700M06*A0G_110610$");
84                 break;
85             case Mode.Data:
86                 PrepareTouchData ();
87                 break;
88             case Mode.Register:
89                 byte val;
90                 switch ((Registers)(data [1] & 0x3f)) {
91                 case Registers.WorkRegisterThreshold:
92                     val = 40;
93                     break;
94                 case Registers.WorkRegisterGain:
95                     val = 8;
96                     break;
97                 case Registers.WorkRegisterOffset:
98                     val = 0;
99                     break;
100                 case Registers.WorkRegisterReportRate:
101                     val = 8;
102                     break;
103                 case Registers.WorkRegisterNumX:
104                     val = NumX;
105                     break;
106                 case Registers.WorkRegisterNumY:
107                     val = NumY;
108                     break;
109                 default:
110                     this.Log (
111                         LogLevel.Warning,
112                         "Unknown register write: {0}",
113                         data.Select (x => x.ToString ("X")).Aggregate ((x,y) => x + " " + y)
114                     );
115                     val = 0;
116                     break;
117                 }
118 
119                 currentRetValue = new byte[]{val, GetCRC (data, val)};
120 
121                 break;
122             default:
123                 this.Log (
124                     LogLevel.Warning,
125                     "Unknown mode write: {0}",
126                     data.Select (x => x.ToString ("X")).Aggregate ((x,y) => x + " " + y)
127                     );
128                 break;
129             }
130         }
131 
Read(int count)132         public byte[] Read (int count)
133         {
134             this.NoisyLog ("Read {0}", currentRetValue.Select(x=>x.ToString("X")).Aggregate((x,y)=>x+" "+y));
135             //       throw new System.NotImplementedException ();
136             return currentRetValue;
137         }
138 
Press(MouseButton button = MouseButton.Left)139         public void Press (MouseButton button = MouseButton.Left)
140         {
141             this.NoisyLog("Pressing the pointer at {0}x{1}", points[0].X, points[0].Y);
142             points[0].Type = PointType.On;
143             Update();
144         }
145 
Release(MouseButton button = MouseButton.Left)146         public void Release (MouseButton button = MouseButton.Left)
147         {
148             this.NoisyLog("Releasing the pointer at {0}x{1}", points[0].X, points[0].Y);
149             points[0].Type = PointType.Up;
150             Update();
151         }
152 
MoveTo(int x, int y)153         public void MoveTo (int x, int y)
154         {
155             points[0].X = (ushort)x;
156             points[0].Y = (ushort)y;
157             if(points[0].Type == PointType.Down || points[0].Type == PointType.On)
158             {
159                 this.NoisyLog("Moving the pointer at {0}x{1}", x, y);
160                 points[0].Type = PointType.On;
161                 Update();
162             }
163         }
164 
Unset()165         public void Unset ()
166         {
167             IRQ.Unset ();
168         }
169 
170         public GPIO IRQ { get; private set; }
171 
Update()172         private void Update ()
173         {
174             IRQ.Blink ();
175         }
176 
PrepareTouchData()177         private void PrepareTouchData ()
178         {
179             var data = new byte[26];
180             data [0] = 0xAA;
181             data [1] = 0xAA;
182             data [2] = 26;
183             for (int i = 0; i < points.Length; i++) {
184                 data [i * 4 + 5] = (byte)(((int)points [i].Type << 6) | ((points [i].X.HiByte () & 0xF)));
185                 data [i * 4 + 6] = points [i].X.LoByte ();
186                 data [i * 4 + 7] = (byte)(((int)points [i].Id << 4) | ((points [i].Y.HiByte () & 0xF)));
187                 data [i * 4 + 8] = points [i].Y.LoByte ();
188 
189             }
190 
191             data [25] = GetFullCRC (data.Take (25));
192             currentRetValue = data;
193 
194         }
195 
GetCRC(byte[] input, byte output)196         private byte GetCRC (byte[] input, byte output)
197         {
198             return (byte)(input [0] ^ input [1] ^ output);
199         }
200 
GetFullCRC(IEnumerable<byte> data)201         private byte GetFullCRC (IEnumerable<byte> data)
202         {
203             byte result = 0;
204             foreach (var item in data) {
205                 result ^= item;
206             }
207             return result;
208         }
209 
210         private byte[] currentRetValue;
211         private readonly int maxSupportedPoints;
212         private TouchedPoint[] points;
213 
214         private const byte NumX = 28;
215         private const byte NumY = 16;
216 
217         private struct TouchedPoint
218         {
219             public UInt16 X;
220             public UInt16 Y;
221             public UInt16 Id;
222             public PointType Type;
223         }
224 
225         private enum PointType
226         {
227             Down = 0,
228             Up = 1,
229             On = 2,
230             Reserved = 3
231         }
232 
233         private enum Registers
234         {
235             WorkRegisterThreshold = 0x0,
236             WorkRegisterReportRate = 0x08,
237             WorkRegisterGain = 0x30,
238             WorkRegisterOffset = 0x31,
239             WorkRegisterNumX = 0x33,
240             WorkRegisterNumY = 0x34
241         }
242 
243         private enum Mode
244         {
245             Model = 0xBB,
246             Data = 0xF9,
247             Register = 0xFC,
248         }
249     }
250 }
251 
252