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