1 // 2 // Copyright (c) 2010-2020 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 Antmicro.Renode.Core; 9 using Antmicro.Renode.Logging; 10 using Antmicro.Renode.Peripherals.I2C; 11 using System.Linq; 12 using Antmicro.Renode.Utilities; 13 using System.Collections.Generic; 14 15 namespace Antmicro.Renode.Peripherals.Input 16 { 17 /// <summary> 18 /// This class differs from FT5x06. Although it was based on FT5x06 datasheet, it is inconsistent 19 /// with the Linux driver we used to create FT5x06.cs. 20 /// This name is used because of STM32F7 Cube, providing such a driver. 21 /// </summary> 22 public sealed class FT5336 : II2CPeripheral, IAbsolutePositionPointerInput 23 { FT5336(bool isRotated = false)24 public FT5336(bool isRotated = false) 25 { 26 this.isRotated = isRotated; 27 IRQ = new GPIO(); 28 Reset(); 29 } 30 Reset()31 public void Reset() 32 { 33 IRQ.Unset(); 34 currentReturnValue = null; 35 lastWriteRegister = 0; 36 for(ushort i = 0; i < touchedPoints.Length; ++i) 37 { 38 touchedPoints[i] = new TouchedPoint 39 { 40 Type = PointType.Reserved, 41 X = 0, 42 Y = 0, 43 Id = i 44 }; 45 } 46 } 47 Write(byte[] data)48 public void Write(byte[] data) 49 { 50 lastWriteRegister = (Registers)data[0]; 51 if(lastWriteRegister < Registers.TouchEndRegister && lastWriteRegister >= Registers.TouchBeginRegister) 52 { 53 PrepareTouchData((byte)((lastWriteRegister - Registers.TouchBeginRegister) % TouchInfoSize), (lastWriteRegister - Registers.TouchBeginRegister) / TouchInfoSize); 54 return; 55 } 56 switch(lastWriteRegister) 57 { 58 case Registers.TouchDataStatus: 59 SetReturnValue((byte)touchedPoints.Count(x => x.Type == PointType.Contact || x.Type == PointType.Down)); 60 break; 61 case Registers.InterruptStatus: 62 break; 63 case Registers.ChipVendorId: 64 SetReturnValue(ChipVendorId); 65 break; 66 default: 67 this.Log(LogLevel.Warning, "Unhandled write to offset 0x{0:X}{1:X}.", lastWriteRegister, 68 data.Length == 1 ? String.Empty : ", values {0}".FormatWith(data.Skip(1).Select(x => "0x" + x.ToString("X")).Stringify(", "))); 69 break; 70 } 71 } 72 Read(int count)73 public byte[] Read(int count) 74 { 75 return currentReturnValue.Take(count).ToArray(); 76 } 77 FinishTransmission()78 public void FinishTransmission() 79 { 80 } 81 MoveTo(int x, int y)82 public void MoveTo(int x, int y) 83 { 84 if(!isRotated) 85 { 86 touchedPoints[0].X = (ushort)x; 87 touchedPoints[0].Y = (ushort)y; 88 } 89 else 90 { 91 touchedPoints[0].X = (ushort)y; 92 touchedPoints[0].Y = (ushort)x; 93 } 94 if(touchedPoints[0].Type == PointType.Down || touchedPoints[0].Type == PointType.Contact) 95 { 96 this.NoisyLog("Moving the pointer at {0}x{1}", touchedPoints[0].X, touchedPoints[0].Y); 97 touchedPoints[0].Type = PointType.Contact; 98 } 99 if(touchedPoints.Any(b => b.Type == PointType.Down || b.Type == PointType.Contact)) 100 { 101 IRQ.Blink(); 102 } 103 } 104 Press(MouseButton button = MouseButton.Left)105 public void Press(MouseButton button = MouseButton.Left) 106 { 107 this.NoisyLog("Pressing the pointer at {0}x{1}", touchedPoints[0].X, touchedPoints[0].Y); 108 touchedPoints[0].Type = PointType.Contact; 109 IRQ.Blink(); 110 } 111 Release(MouseButton button = MouseButton.Left)112 public void Release(MouseButton button = MouseButton.Left) 113 { 114 this.NoisyLog("Releasing the pointer at {0}x{1}", touchedPoints[0].X, touchedPoints[0].Y); 115 touchedPoints[0].Type = PointType.Up; 116 IRQ.Blink(); 117 } 118 119 public int MaxX { get; set; } 120 121 public int MaxY { get; set; } 122 123 public int MinX 124 { 125 get 126 { 127 return 0; 128 } 129 } 130 131 public int MinY 132 { 133 get 134 { 135 return 0; 136 } 137 } 138 139 public GPIO IRQ { get; private set; } 140 PrepareTouchData(byte offset, int pointNumber)141 private void PrepareTouchData(byte offset, int pointNumber) 142 { 143 var queue = new Queue<byte>(); 144 145 switch((TouchDataRegisters)offset) 146 { 147 case TouchDataRegisters.TouchXHigh: 148 queue.Enqueue((byte)(((int)touchedPoints[pointNumber].Type << 6) | (touchedPoints[pointNumber].X.HiByte() & 0xF))); 149 goto case TouchDataRegisters.TouchXLow; 150 case TouchDataRegisters.TouchXLow: 151 queue.Enqueue(touchedPoints[pointNumber].X.LoByte()); 152 goto case TouchDataRegisters.TouchYHigh; 153 case TouchDataRegisters.TouchYHigh: 154 queue.Enqueue((byte)((touchedPoints[pointNumber].Id << 4) | (touchedPoints[pointNumber].Y.HiByte() & 0xF))); 155 goto case TouchDataRegisters.TouchYLow; 156 case TouchDataRegisters.TouchYLow: 157 queue.Enqueue(touchedPoints[pointNumber].Y.LoByte()); 158 goto case TouchDataRegisters.TouchWeight; 159 case TouchDataRegisters.TouchWeight: 160 queue.Enqueue(0); 161 goto case TouchDataRegisters.TouchMisc; 162 case TouchDataRegisters.TouchMisc: 163 queue.Enqueue(0); 164 break; 165 default: 166 throw new Exception("Should not reach here."); 167 } 168 SetReturnValue(queue.ToArray()); 169 } 170 SetReturnValue(params byte[] bytes)171 private void SetReturnValue(params byte[] bytes) 172 { 173 currentReturnValue = bytes; 174 } 175 176 private byte[] currentReturnValue; 177 private Registers lastWriteRegister; 178 private readonly bool isRotated; 179 180 private readonly TouchedPoint[] touchedPoints = new TouchedPoint[5]; 181 182 private const byte ChipVendorId = 0x51; 183 184 private const int TouchInfoSize = TouchDataRegisters.TouchMisc - TouchDataRegisters.TouchXHigh + 1; 185 186 private struct TouchedPoint 187 { 188 public UInt16 X; 189 public UInt16 Y; 190 public UInt16 Id; 191 public PointType Type; 192 } 193 194 private enum PointType 195 { 196 Down = 0, 197 Up = 1, 198 Contact = 2, 199 Reserved = 3 200 } 201 202 private enum TouchDataRegisters 203 { 204 TouchXHigh = 0x0, 205 TouchXLow = 0x1, 206 TouchYHigh = 0x2, 207 TouchYLow = 0x3, 208 TouchWeight = 0x4, 209 TouchMisc = 0x5, 210 } 211 212 private enum Registers 213 { 214 GestureId = 0x1, 215 TouchDataStatus = 0x2, 216 TouchBeginRegister = 0x3, 217 TouchEndRegister = 0x21, 218 InterruptStatus = 0xA4, 219 ChipVendorId = 0xA8 220 } 221 } 222 } 223 224