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