1 //
2 // Copyright (c) 2010-2024 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 System.Diagnostics;
9 using System.IO;
10 using System.Net.Sockets;
11 using System.Threading;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Exceptions;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.I2C;
16 using Antmicro.Renode.Sockets;
17 using Antmicro.Renode.Time;
18 using Antmicro.Renode.Utilities;
19 #if !PLATFORM_WINDOWS
20 using Mono.Unix;
21 #endif
22 
23 namespace Antmicro.Renode.Extensions.Mocks
24 {
25     public static class HPSHostControllerExtensions
26     {
AddHPSHostController(this Emulation emulation, STM32F7_I2C device, string name = R)27         public static void AddHPSHostController(this Emulation emulation, STM32F7_I2C device, string name = "HPSHostController")
28         {
29             emulation.HostMachine.AddHostMachineElement(new HPSHostController(device), name);
30         }
31     }
32 
33     public class HPSHostController : IHostMachineElement
34     {
HPSHostController(STM32F7_I2C device)35         public HPSHostController(STM32F7_I2C device)
36         {
37             currentSlave = device;
38         }
39 
FlashMCU(ReadFilePath path)40         public void FlashMCU(ReadFilePath path)
41         {
42             var address = 0;
43             var data = new byte[256 + 5];
44             data[0] = ((byte)Commands.WriteMemory << 6) | (byte)MemoryBanks.MCUFlash;
45 
46             var bytes = File.ReadAllBytes(path);
47             var left = bytes.Length;
48 
49             while(left > 0)
50             {
51                 var batchSize = Math.Min(left, 256);
52                 Array.Copy(bytes, address, data, 5, batchSize);
53                 data[1] = (byte)(address >> 24);
54                 data[2] = (byte)(address >> 16);
55                 data[3] = (byte)(address >> 8);
56                 data[4] = (byte)address;
57                 IssueCommand(data);
58 
59                 currentSlave.Read(0);
60                 // Poll until all the bytes are written
61                 PollForRegisterBit(RegisterBitName.RXNE);
62 
63                 address += 256;
64                 left -= batchSize;
65             }
66         }
67 
CommandEraseSPIFlash()68         public void CommandEraseSPIFlash()
69         {
70             var data = new byte[] {
71                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemCommands,
72                 0x0,
73                 (byte)CommonSystemCommands.EraseSPIFlash,
74                 0x0
75             };
76             IssueCommand(data);
77             currentSlave.Read(0);
78         }
79 
CommandEraseStage1()80         public void CommandEraseStage1()
81         {
82             var data = new byte[] {
83                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemCommands,
84                 0x0,
85                 (byte)CommonSystemCommands.EraseStage1,
86                 0x0
87             };
88             IssueCommand(data);
89             currentSlave.Read(0);
90         }
91 
CommandLaunchApplication()92         public void CommandLaunchApplication()
93         {
94             var data = new byte[] {
95                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemCommands,
96                 0x0,
97                 (byte)CommonSystemCommands.LaunchApplication,
98                 0x0
99             };
100             IssueCommand(data);
101             currentSlave.Read(0);
102         }
103 
CommandLaunchStage1()104         public void CommandLaunchStage1()
105         {
106             var data = new byte[] {
107                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemCommands,
108                 0x0,
109                 (byte)CommonSystemCommands.LaunchStage1,
110                 0x0
111             };
112             IssueCommand(data);
113             currentSlave.Read(0);
114         }
115 
CommandIssueReset()116         public void CommandIssueReset()
117         {
118             var data = new byte[] {
119                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemCommands,
120                 0x0,
121                 (byte)CommonSystemCommands.Reset,
122                 0x0
123             };
124             IssueCommand(data);
125             currentSlave.Read(0);
126         }
127 
SetNumberOfCameraTestIterations(int count)128         public void SetNumberOfCameraTestIterations(int count)
129         {
130             var data = new byte[] {
131                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.CameraTestIterations,
132                 0x0,
133                 (byte)count,
134                 0x0
135             };
136             IssueCommand(data);
137             currentSlave.Read(0);
138         }
139 
SetOptionBytes(int value)140         public void SetOptionBytes(int value)
141         {
142             var data = new byte[] {
143                 ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.OptionBytesConfiguration,
144                 0x0,
145                 (byte)(value >> 8),
146                 (byte)value,
147                 0x0
148             };
149             IssueCommand(data);
150             currentSlave.Read(0);
151         }
152 
153         // Register 0:
ReadMagicNumber(TimeInterval timeInterval)154         public byte[] ReadMagicNumber(TimeInterval timeInterval)
155         {
156             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.MagicNumber});
157             return GetBytesFromSlave(2, timeInterval);
158         }
159 
160         // Register 1:
ReadHardwareVersion(TimeInterval timeInterval)161         public byte[] ReadHardwareVersion(TimeInterval timeInterval)
162         {
163             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.HardwareVersion });
164             return GetBytesFromSlave(2, timeInterval);
165         }
166 
167         // Register 2:
ReadSystemStatus(TimeInterval timeInterval)168         public string[,] ReadSystemStatus(TimeInterval timeInterval)
169         {
170             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SystemStatus });
171             return FormatSystemStatus(GetBytesFromSlave(2, timeInterval));
172         }
173 
174         // Register 5:
ReadMemoryBankAvailable(TimeInterval timeInterval)175         public byte[] ReadMemoryBankAvailable(TimeInterval timeInterval)
176         {
177             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.MemoryBankAvailable });
178             return GetBytesFromSlave(2, timeInterval);
179         }
180 
181         // Register 6:
ReadError(TimeInterval timeInterval)182         public string[,] ReadError(TimeInterval timeInterval)
183         {
184             return FormatCommonErrorStatus(ReadErrorBytes(timeInterval));
185         }
186 
ReadErrorBytes(TimeInterval timeInterval)187         public byte[] ReadErrorBytes(TimeInterval timeInterval)
188         {
189             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.Error });
190             return GetBytesFromSlave(2, timeInterval);
191         }
192 
193         // Register 7: should be RW
ReadEnabledFeatures(TimeInterval timeInterval)194         public string[,] ReadEnabledFeatures(TimeInterval timeInterval)
195         {
196             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.Enabledfeatures });
197             return FormatEnabledFeatures(GetBytesFromSlave(2, timeInterval));
198         }
199 
200         // Register 8:
ReadFeature0StatusBits(TimeInterval timeInterval)201         public string[,] ReadFeature0StatusBits(TimeInterval timeInterval)
202         {
203             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.Feature0 });
204             return FormatFeature(GetBytesFromSlave(2, timeInterval));
205         }
206 
207         // Register 9:
ReadFeature1StatusBits(TimeInterval timeInterval)208         public string[,] ReadFeature1StatusBits(TimeInterval timeInterval)
209         {
210             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.Feature1 });
211             return FormatFeature(GetBytesFromSlave(2, timeInterval));
212         }
213 
214         // Register 10:
ReadFirmwareVersionHigh(TimeInterval timeInterval)215         public byte[] ReadFirmwareVersionHigh(TimeInterval timeInterval)
216         {
217             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.FirmwareVersionHIGH });
218             return GetBytesFromSlave(2, timeInterval);
219         }
220 
221         // Register 11:
ReadFirmwareVersionLow(TimeInterval timeInterval)222         public byte[] ReadFirmwareVersionLow(TimeInterval timeInterval)
223         {
224             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.FirmwareVersionLOW });
225             return GetBytesFromSlave(2, timeInterval);
226         }
227 
228         // Register 12:
ReadFPGABootCount(TimeInterval timeInterval)229         public byte[] ReadFPGABootCount(TimeInterval timeInterval)
230         {
231             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.FPGABootCount });
232             return GetBytesFromSlave(2, timeInterval);
233         }
234 
235         // Register 13:
ReadFPGALoopCount(TimeInterval timeInterval)236         public byte[] ReadFPGALoopCount(TimeInterval timeInterval)
237         {
238             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.FPGALoopCount });
239             return GetBytesFromSlave(2, timeInterval);
240         }
241 
242         // Register 14:
ReadFPGAROMVersion(TimeInterval timeInterval)243         public byte[] ReadFPGAROMVersion(TimeInterval timeInterval)
244         {
245             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.FPGAROMVersion });
246             return GetBytesFromSlave(2, timeInterval);
247         }
248 
249         // Register 15:
ReadSPIFlashStatus(TimeInterval timeInterval)250         public byte[] ReadSPIFlashStatus(TimeInterval timeInterval)
251         {
252             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.SPIFlashStatusBits });
253             return GetBytesFromSlave(2, timeInterval);
254         }
255 
256         // Register 16:
ReadDebugIndex(TimeInterval timeInterval)257         public byte[] ReadDebugIndex(TimeInterval timeInterval)
258         {
259             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.DebugIndex });
260             return GetBytesFromSlave(2, timeInterval);
261         }
262 
263         // Register 17:
ReadDebugValue(TimeInterval timeInterval)264         public byte[] ReadDebugValue(TimeInterval timeInterval)
265         {
266             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.DebugValue });
267             return GetBytesFromSlave(2, timeInterval);
268         }
269 
270         // Register 18:
ReadCameraConfiguration(TimeInterval timeInterval)271         public string[,] ReadCameraConfiguration(TimeInterval timeInterval)
272         {
273             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.CameraConfiguration });
274             return FormatCameraConfiguration(GetBytesFromSlave(2, timeInterval));
275         }
276 
277         // Register 19:
ReadCameraTestIterations(TimeInterval timeInterval)278         public byte[] ReadCameraTestIterations(TimeInterval timeInterval)
279         {
280             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.CameraTestIterations });
281             return GetBytesFromSlave(2, timeInterval);
282         }
283 
284         // Register 20:
ReadOptionBytes(TimeInterval timeInterval)285         public byte[] ReadOptionBytes(TimeInterval timeInterval)
286         {
287             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.OptionBytesConfiguration });
288             return GetBytesFromSlave(2, timeInterval);
289         }
290 
291         // Register 21:
ReadPartIDs(TimeInterval timeInterval)292         public byte[] ReadPartIDs(TimeInterval timeInterval)
293         {
294             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.PartIDs });
295             return GetBytesFromSlave(20, timeInterval);
296         }
297 
298         // Register 22:
ReadPreviousCrash(TimeInterval timeInterval)299         public byte[] ReadPreviousCrash(TimeInterval timeInterval)
300         {
301             IssueCommand(new byte[] { ((byte)Commands.RegisterAccess << 6) | (byte)RegisterAccessType.PreviousCrash });
302             // PreviousCrash register can return up to 256 bytes, but we are limited to 255 bytes because the NBYTES field
303             // in STM32F7_I2C model is 8 bytes long.
304             return GetBytesFromSlave(255, timeInterval);
305         }
306 
GetBytesFromSlave(int count, TimeInterval timeInterval)307         private byte[] GetBytesFromSlave(int count, TimeInterval timeInterval)
308         {
309             if(currentSlave == null)
310             {
311                 throw new RecoverableException("Cannot read data because no slave is connected.");
312             }
313             var result = new byte[count];
314             var sw = new Stopwatch();
315             sw.Start();
316             do
317             {
318                 result = currentSlave.Read(count);
319                 if(result.Length == count)
320                 {
321                     break;
322                 }
323                 if(sw.Elapsed > timeInterval.ToTimeSpan())
324                 {
325                     currentSlave.Read(0);
326                     result = new byte[count];
327                     break;
328                 }
329             } while(result.Length == 0);
330             return result;
331         }
332 
333         // This method is for getting OA1EN,
334         // returns true when OA1EN is enabled.
OA1ENEnabled()335         private bool OA1ENEnabled()
336         {
337             return currentSlave.OwnAddress1Enabled;
338         }
339 
340         // This method is for getting RXEN,
341         // returns true when the buffer is empty.
RXNECleared()342         private bool RXNECleared()
343         {
344             return !currentSlave.RxNotEmpty;
345         }
346 
PollForRegisterBit(RegisterBitName bitName)347         private void PollForRegisterBit(RegisterBitName bitName)
348         {
349             int i = 0;
350             Func<bool> registerAccess;
351             switch(bitName)
352             {
353                 case RegisterBitName.OA1EN:
354                     registerAccess = OA1ENEnabled;
355                     break;
356                 case RegisterBitName.RXNE:
357                     registerAccess = RXNECleared;
358                     break;
359                 default:
360                     throw new RecoverableException("Register bit name does not exist.");
361             }
362             while(!registerAccess() && i < 8)
363             {
364                 Thread.Sleep(500);
365                 i++;
366             }
367         }
368 
PollForError(TimeInterval timeInterval)369         private void PollForError(TimeInterval timeInterval)
370         {
371             for(int i = 0; i < 3; i++)
372             {
373                 var errors = ReadErrorBytes(timeInterval);
374                 if(errors[0] + errors[1] != 0x00)
375                 {
376                     break;
377                 }
378                 Thread.Sleep(1000);
379             }
380         }
381 
382         // When we need to read for more than 255 bytes, we will need this method
GetLongBytes(int count, TimeInterval timeInterval)383         private byte[] GetLongBytes(int count, TimeInterval timeInterval)
384         {
385             var result = new byte[count];
386             var rounds = count / ReadChunkSize;
387             var remainder = count % ReadChunkSize;
388             for(int i = 0; i <= rounds; i++)
389             {
390                 int toRead = i == rounds ? remainder : ReadChunkSize;
391                 Array.Copy(GetBytesFromSlave(toRead, timeInterval), 0, result, i * ReadChunkSize, toRead);
392             }
393             return result;
394         }
395 
StartSocketServer(TimeInterval timeInterval)396         public void StartSocketServer(TimeInterval timeInterval)
397         {
398 #if PLATFORM_WINDOWS
399             throw new RecoverableException("This method is not supported on Windows");
400 #else
401             string path = "/tmp/i2c.sock";
402             if(File.Exists(path))
403             {
404                 File.Delete(path);
405             }
406             this.Log(LogLevel.Info, "Server starting at{0}", path);
407             var socket = SocketsManager.Instance.AcquireSocket(this, AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified, new UnixEndPoint(path));
408             this.Log(LogLevel.Info, "Connection established");
409 
410             currentSlave.Read(0);
411             var connection = socket.Accept();
412 
413             var commandBuffer = new byte[(int)NumberOfBytes.MessageType];
414             var prevWrite = false;
415             var length = 0;
416 
417             while(SocketConnected(connection))
418             {
419                 PollForRegisterBit(RegisterBitName.OA1EN);
420                 try
421                 {
422                     PollForSocketData(connection, commandBuffer);
423                 }
424                 catch(Exception e)
425                 {
426                     this.Log(LogLevel.Error, "{0} Exception caught.", e);
427                     return;
428                 }
429                 switch((SocketI2CMessageType)commandBuffer[0])
430                 {
431                     case SocketI2CMessageType.Stop:
432                         currentSlave.FinishTransmission();
433                         break;
434                     // Parse read command
435                     case SocketI2CMessageType.Read:
436                         prevWrite = false;
437                         length = GetLength(connection);
438 
439                         byte[] dataToSend = GetLongBytes(length, timeInterval);
440                         try
441                         {
442                             PollForSocketData(connection, dataToSend, true);
443                         }
444                         catch(Exception e)
445                         {
446                             this.Log(LogLevel.Error, "{0} Exception caught.", e);
447                             return;
448                         }
449                         break;
450                     // Parse write command
451                     case SocketI2CMessageType.Write:
452                         // Seems that the slave needs a read operation
453                         // to flush out the bits written
454                         if(prevWrite)
455                         {
456                             currentSlave.Read(0);
457                             PollForRegisterBit(RegisterBitName.RXNE);
458                         }
459                         prevWrite = true;
460                         length = GetLength(connection);
461                         byte[] data = new byte[length];
462                         try
463                         {
464                             PollForSocketData(connection, data);
465                         }
466                         catch(Exception e)
467                         {
468                             this.Log(LogLevel.Error, "{0} Exception caught.", e);
469                             return;
470                         }
471                         if(data.Length == 1 && data[0] == 0x86)
472                         {
473                             PollForError(timeInterval);
474                             Thread.Sleep(10);
475                         }
476                         IssueCommand(data);
477                         break;
478                 }
479             }
480 #endif
481         }
482 
GetLength(Socket connection)483         private int GetLength(Socket connection)
484         {
485             var lengthBytes = new byte[(int)NumberOfBytes.LengthBytes];
486             PollForSocketData(connection, lengthBytes);
487             var combined = (int)lengthBytes[0] << 8 | lengthBytes[1];
488             return combined;
489         }
490 
PollForSocketData(Socket connection, byte[] data, bool send = false)491         private void PollForSocketData(Socket connection, byte[] data, bool send = false)
492         {
493             var tempLength = 0;
494             var sendReceive = (send == true)
495                 ? connection.Send
496                 : (Func<byte[], int, int, SocketFlags, int>)connection.Receive;
497 
498             while(tempLength < data.Length)
499             {
500                 tempLength += sendReceive(data, tempLength, data.Length - tempLength, SocketFlags.None);
501             }
502         }
503 
IssueCommand(byte[] data)504         private void IssueCommand(byte[] data)
505         {
506             if(currentSlave == null)
507             {
508                 throw new RecoverableException("Cannot issue command because no slave is connected.");
509             }
510             currentSlave.Write(data);
511         }
512 
SocketConnected(Socket s)513         private bool SocketConnected(Socket s)
514         {
515             bool dataAvailableForReading = s.Poll(1000, SelectMode.SelectRead);
516             bool availableBytesIsEmpty = (s.Available == 0);
517             return !(dataAvailableForReading && availableBytesIsEmpty);
518         }
519 
FormatSystemStatus(byte[] data)520         private string[,] FormatSystemStatus(byte[] data)
521         {
522             if(data.Length != 2)
523             {
524                 throw new RecoverableException(string.Format("Received {0} bytes of data (expected 2) from System Status register.", data.Length));
525             }
526             var table = new Table().AddRow("Value", "Bit", "Name", "Description");
527             table.AddRow(string.Empty, "15", string.Empty, string.Empty);
528             table.AddRow(string.Empty, "14", string.Empty, string.Empty);
529             table.AddRow((data[0] & 0x20) >> 5 == 1 ? "1" : "0", "13", "ONE_TIME_INIT", "Whether the one_time_init binary is running");
530             table.AddRow((data[0] & 0x10) >> 4 == 1 ? "1" : "0", "12", "STAGE0_PERM_LOCKED", "Whether stage0 has been made permanently read-only");
531             table.AddRow((data[0] & 0x8) >> 3 == 1 ? "1" : "0", "11", "STAGE0_LOCKED", "Whether stage0 has been make read-only");
532             table.AddRow((data[0] & 0x4) >> 2 == 1 ? "1" : "0", "10", "CMDINPROGRESS", "A command is in-progress");
533             table.AddRow((data[0] & 0x2) >> 1 == 1 ? "1" : "0", "9", "APPLREADY", "Application is running, and features may be enabled");
534             table.AddRow((data[0] & 0x1) == 1 ? "1" : "0", "8", "APPLRUN", "Stage 1 has been launched, and is now running");
535             table.AddRow(string.Empty, "7", string.Empty, string.Empty);
536             table.AddRow(string.Empty, "6", string.Empty, string.Empty);
537             table.AddRow((data[1] & 0x20) >> 5 == 1 ? "1" : "0", "5", "WPOFF", "Write protect pin off");
538             table.AddRow((data[1] & 0x10) >> 4 == 1 ? "1" : "0", "4", "WPON", "Write protect pin on");
539             table.AddRow((data[1] & 0x8) >> 3 == 1 ? "1" : "0", "3", "STAGE0", "Stage 0 is running");
540             table.AddRow(string.Empty, "2", string.Empty, string.Empty);
541             table.AddRow((data[1] & 0x2) >> 1 == 1 ? "1" : "0", "1", "FAULT", "System has an unrecoverable fault");
542             table.AddRow((data[1] & 0x1) == 1 ? "1" : "0", "0", "OK", "System is operational");
543             return table.ToArray();
544         }
545 
FormatCommonErrorStatus(byte[] data)546         private string[,] FormatCommonErrorStatus(byte[] data)
547         {
548             if(data.Length != 2)
549             {
550                 throw new RecoverableException(string.Format("Received {0} bytes of data (expected 2) from Error Status register.", data.Length));
551             }
552             var table = new Table().AddRow("Value", "Bit", "Name", "Description");
553             table.AddRow(string.Empty, "15", string.Empty, string.Empty);
554             table.AddRow(string.Empty, "14", string.Empty, string.Empty);
555             table.AddRow(string.Empty, "13", string.Empty, string.Empty);
556             table.AddRow(string.Empty, "12", string.Empty, string.Empty);
557             table.AddRow(string.Empty, "11", string.Empty, string.Empty);
558             table.AddRow(string.Empty, "10", string.Empty, string.Empty);
559             table.AddRow((data[0] & 0x2) >> 1 == 1 ? "1" : "0", "9", "BUFORUN", "Buffer overrun");
560             table.AddRow((data[0] & 0x1) == 1 ? "1" : "0", "8", "BUFNAVAIL", "Buffer not available");
561             table.AddRow((data[1] & 0x80) >> 7 == 1 ? "1" : "0", "7", "I2CBADREQ", "A bad I2C request was made");
562             table.AddRow((data[1] & 0x40) >> 6 == 1 ? "1" : "0", "6", "SPIFLASH", "SPI flash access failed");
563             table.AddRow((data[1] & 0x20) >> 5 == 1 ? "1" : "0", "5", "CAMERA", "Camera not functional");
564             table.AddRow((data[1] & 0x10) >> 4 == 1 ? "1" : "0", "4", "I2CORUN", "I2C overrun");
565             table.AddRow((data[1] & 0x8) >> 3 == 1 ? "1" : "0", "3", "I2CBERR", "I2C bus error");
566             table.AddRow((data[1] & 0x4) >> 2 == 1 ? "1" : "0", "2", "PANIC", "A panic occurred");
567             table.AddRow((data[1] & 0x2) >> 1 == 1 ? "1" : "0", "1", "MCUFLASH", "Error writing to MCU flash");
568             table.AddRow((data[1] & 0x1) == 1 ? "1" : "0", "0", "I2CURUN", "I2C underrun");
569             return table.ToArray();
570         }
571 
FormatEnabledFeatures(byte[] data)572         private string[,] FormatEnabledFeatures(byte[] data)
573         {
574             if(data.Length != 2)
575             {
576                 throw new RecoverableException(string.Format("Received {0} bytes of data (expected 2) from Enabled Features register.", data.Length));
577             }
578             var table = new Table().AddRow("Value", "Bit", "Name", "Description");
579             table.AddRow(string.Empty, "15", string.Empty, string.Empty);
580             table.AddRow(string.Empty, "14", string.Empty, string.Empty);
581             table.AddRow(string.Empty, "13", string.Empty, string.Empty);
582             table.AddRow(string.Empty, "12", string.Empty, string.Empty);
583             table.AddRow(string.Empty, "11", string.Empty, string.Empty);
584             table.AddRow(string.Empty, "10", string.Empty, string.Empty);
585             table.AddRow(string.Empty, "9", string.Empty, string.Empty);
586             table.AddRow(string.Empty, "8", string.Empty, string.Empty);
587             table.AddRow(string.Empty, "7", string.Empty, string.Empty);
588             table.AddRow(string.Empty, "6", string.Empty, string.Empty);
589             table.AddRow(string.Empty, "5", string.Empty, string.Empty);
590             table.AddRow(string.Empty, "4", string.Empty, string.Empty);
591             table.AddRow(string.Empty, "3", string.Empty, string.Empty);
592             table.AddRow(string.Empty, "2", string.Empty, string.Empty);
593             table.AddRow((data[1] & 0x2) >> 1 == 1 ? "1" : "0", "1", "FEATURE1", "Enable feature 1");
594             table.AddRow((data[1] & 0x1) == 1 ? "1" : "0", "0", "FEATURE0", "Enable feature 0");
595             return table.ToArray();
596         }
597 
FormatFeature(byte[] data)598         private string[,] FormatFeature(byte[] data)
599         {
600             if(data.Length != 2)
601             {
602                 throw new RecoverableException(string.Format("Received {0} bytes of data (expected 2) from Feature N register.", data.Length));
603             }
604             var table = new Table().AddRow("Value", "Bit", "Name", "Description");
605             table.AddRow((data[0] & 0x80) >> 7 == 1 ? "1" : "0", "15", "USABLE", "The feature result is valid to use");
606             table.AddRow(string.Empty, "14", string.Empty, string.Empty);
607             table.AddRow(string.Empty, "13", string.Empty, string.Empty);
608             table.AddRow(string.Empty, "12", string.Empty, string.Empty);
609             table.AddRow(string.Empty, "11", string.Empty, string.Empty);
610             table.AddRow(string.Empty, "10", string.Empty, string.Empty);
611             table.AddRow(string.Empty, "9", string.Empty, string.Empty);
612             table.AddRow(string.Empty, "8", string.Empty, string.Empty);
613             table.AddRow(string.Empty, "7", string.Empty, string.Empty);
614             table.AddRow(string.Empty, "6", string.Empty, string.Empty);
615             table.AddRow(string.Empty, "5", string.Empty, string.Empty);
616             table.AddRow(string.Empty, "4", string.Empty, string.Empty);
617             table.AddRow(string.Empty, "3", string.Empty, string.Empty);
618             table.AddRow(string.Empty, "2", string.Empty, string.Empty);
619             table.AddRow(string.Empty, "1", string.Empty, string.Empty);
620             table.AddRow(string.Empty, "0", string.Empty, string.Empty);
621             return table.ToArray();
622         }
623 
FormatCameraConfiguration(byte[] data)624         private string[,] FormatCameraConfiguration(byte[] data)
625         {
626             if(data.Length != 2)
627             {
628                 throw new RecoverableException(string.Format("Received {0} bytes of data (expected 2) from Camera Configuration register.", data.Length));
629             }
630             var table = new Table().AddRow("Value", "Bit", "Name", "Description");
631             table.AddRow(string.Empty, "15", string.Empty, string.Empty);
632             table.AddRow(string.Empty, "14", string.Empty, string.Empty);
633             table.AddRow(string.Empty, "13", string.Empty, string.Empty);
634             table.AddRow(string.Empty, "12", string.Empty, string.Empty);
635             table.AddRow(string.Empty, "11", string.Empty, string.Empty);
636             table.AddRow(string.Empty, "10", string.Empty, string.Empty);
637             table.AddRow(string.Empty, "9", string.Empty, string.Empty);
638             table.AddRow(string.Empty, "8", string.Empty, string.Empty);
639             table.AddRow(string.Empty, "7", string.Empty, string.Empty);
640             table.AddRow(string.Empty, "6", string.Empty, string.Empty);
641             table.AddRow(string.Empty, "5", string.Empty, string.Empty);
642             table.AddRow(string.Empty, "4", string.Empty, string.Empty);
643             table.AddRow(string.Empty, "3", string.Empty, string.Empty);
644             table.AddRow(string.Empty, "2", string.Empty, string.Empty);
645             table.AddRow((data[1] & 0x2) >> 1 == 1 ? "1" : "0", "1", "ROTATION", "Rotation bit 1");
646             table.AddRow((data[1] & 0x1) == 1 ? "1" : "0", "0", "ROTATION", "Rotation bit 0");
647             return table.ToArray();
648         }
649 
650         private STM32F7_I2C currentSlave;
651 
652         private const int ReadChunkSize = 255;
653 
654         private enum Commands
655         {
656             WriteMemory     = 0,
657             Unused          = 1,
658             RegisterAccess  = 2
659         }
660 
661         private enum MemoryBanks
662         {
663             MCUFlash = 0,
664             SPIFlash = 1
665         }
666 
667         private enum RegisterAccessType
668         {
669             MagicNumber                 = 0,
670             HardwareVersion             = 1,
671             SystemStatus                = 2,
672             SystemCommands              = 3,
673             Unused                      = 4,
674             MemoryBankAvailable         = 5,
675             Error                       = 6,
676             Enabledfeatures             = 7,
677             Feature0                    = 8,
678             Feature1                    = 9,
679             FirmwareVersionHIGH         = 10,
680             FirmwareVersionLOW          = 11,
681             FPGABootCount               = 12,
682             FPGALoopCount               = 13,
683             FPGAROMVersion              = 14,
684             SPIFlashStatusBits          = 15,
685             DebugIndex                  = 16,
686             DebugValue                  = 17,
687             CameraConfiguration         = 18,
688             CameraTestIterations        = 19,
689             OptionBytesConfiguration    = 20,
690             PartIDs                     = 21,
691             PreviousCrash               = 22,
692         }
693 
694         private enum CommonSystemCommands
695         {
696             Reset = 1,
697             LaunchStage1 = 2,
698             LaunchApplication = 4,
699             EraseStage1 = 8,
700             EraseSPIFlash = 16,
701         }
702 
703         private enum RegisterBitName
704         {
705             OA1EN = 1,
706             RXNE = 2,
707         }
708 
709         private enum SocketI2CMessageType
710         {
711             Stop = 0,
712             Read = 1,
713             Write = 2,
714         }
715 
716         private enum NumberOfBytes
717         {
718             MessageType = 1,
719             LengthBytes = 2,
720         }
721     }
722 }
723