1
0

2 Коммитууд 380b7d0eed ... 16b1023287

Эзэн SHA1 Мессеж Огноо
  shayne_lo 16b1023287 design 1 1 долоо хоног өмнө
  shayne_lo dad00d035b test pass 3 долоо хоног өмнө

+ 218 - 0
Simano/Model/AesEncoder.cs

@@ -0,0 +1,218 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Simano.Model
+{
+    public static class AesEncoder
+    {
+        public static byte[] GetAesEncoded(byte[] rawBytes)
+        {
+            AES_Cipher(rawBytes);
+            return rawBytes;
+        }
+
+        //private static byte[] Bylocal(byte[] rawBytes)
+        //{
+        //    using (Aes aesAlg = Aes.Create())
+        //    {
+        //        aesAlg.CreateEncryptor()
+        //    }
+        //}
+
+        private const int M_CLR = 0;
+
+        private const int M_AES_NB = 4;
+        private const int M_AES_NBb = 16;
+        private const int M_AES_NK = 4;
+        private const int M_AES_NR = 10;
+
+        private const int M_AES_KEY_SIZE = 44;
+        private const int M_AES_BOX_SIZE = 256;
+        private const int M_AES_ROUND_CONSTANT_WORD_ARRAY = 10;
+
+        private const int E_AES_DATA_POS_1 = 0;
+        private const int E_AES_DATA_POS_2 = 1;
+        private const int E_AES_DATA_POS_3 = 2;
+        private const int E_AES_DATA_POS_4 = 3;
+        private const int E_AES_DATA_POS_MAX = 4;
+
+        private static UInt32[] s_aes_round_key = new UInt32[M_AES_KEY_SIZE];
+
+        private static byte[] sc_aes_sbox = new byte[M_AES_BOX_SIZE]
+        {
+            0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
+            0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
+            0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
+            0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
+            0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
+            0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
+            0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
+            0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
+            0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
+            0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
+            0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
+            0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
+            0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
+            0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
+            0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
+            0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
+        };
+
+        private static void AES_Cipher(byte[] ptr_data)
+        {
+            byte i, j;
+            UInt32[] data = new UInt32[M_AES_NB];
+
+            data[E_AES_DATA_POS_1] = (((UInt32)ptr_data[3] << 24) | ((UInt32)ptr_data[2] << 16) | ((UInt32)ptr_data[1] << 8) | (UInt32)ptr_data[0]);
+            data[E_AES_DATA_POS_2] = (((UInt32)ptr_data[7] << 24) | ((UInt32)ptr_data[6] << 16) | ((UInt32)ptr_data[5] << 8) | (UInt32)ptr_data[4]);
+            data[E_AES_DATA_POS_3] = (((UInt32)ptr_data[11] << 24) | ((UInt32)ptr_data[10] << 16) | ((UInt32)ptr_data[9] << 8) | (UInt32)ptr_data[8]);
+            data[E_AES_DATA_POS_4] = (((UInt32)ptr_data[15] << 24) | ((UInt32)ptr_data[14] << 16) | ((UInt32)ptr_data[13] << 8) | (UInt32)ptr_data[12]);
+
+            AES_AddRoundKey(data, 0);
+
+            for (i = 1; i < M_AES_NR; i++)
+            {
+                AES_SubBytes(data);
+
+                AES_ShiftRows(data);
+
+                AES_MixColumns(data);
+
+                AES_AddRoundKey(data, (UInt32)i);
+            }
+
+            AES_SubBytes(data);
+            AES_ShiftRows(data);
+            AES_AddRoundKey(data, (UInt32)i);
+
+            for (i = 0; i < 4; i++)
+            {
+                for (j = 0; j < 4; j++)
+                {
+                    ptr_data[4 * i + j] = (byte)(((UInt32)data[i] >> (8 * j)) & 0x000000FF);
+                }
+            }
+        }
+
+        private static void AES_AddRoundKey(UInt32[] data, UInt32 n)
+        {
+            byte i;
+
+            for (i = M_CLR; i < M_AES_NB; i++)
+            {
+                data[i] ^= s_aes_round_key[i + (M_AES_NB * n)];
+            }
+        }
+
+        private static unsafe void AES_SubBytes(UInt32[] data)
+        {
+            int i;
+            int j;
+
+            fixed (UInt32* ptr = data)
+            {
+                byte* ptr_cb;
+                ptr_cb = (byte*)ptr;
+                for (i = M_CLR; i < M_AES_NBb; i = i + 4)
+                {
+                    for (j = M_CLR; j < (byte)4; j++)
+                    {
+                        ptr_cb[i + j] = sc_aes_sbox[ptr_cb[i + j]];
+                    }
+                }
+            }
+        }
+
+        private static unsafe void AES_ShiftRows(UInt32[] data)
+        {
+            UInt32 i;
+            UInt32 j;
+            UInt32 i4;
+            byte* cb;
+            byte[] cw = new byte[M_AES_NBb];
+
+            fixed (UInt32* ptr = data)
+            {
+                cb = (byte*)ptr;
+
+                for (i = 0; i < M_AES_NBb; i++)
+                {
+                    cw[i] = cb[i];
+                }
+
+                for (i = 0; i < M_AES_NB; i += 4)
+                {
+                    i4 = i * 4;
+                    for (j = 1; j < 4; j++)
+                    {
+                        cw[i4 + j + 0 * 4] = cb[i4 + j + ((j + 0) & 3) * 4];
+                        cw[i4 + j + 1 * 4] = cb[i4 + j + ((j + 1) & 3) * 4];
+                        cw[i4 + j + 2 * 4] = cb[i4 + j + ((j + 2) & 3) * 4];
+                        cw[i4 + j + 3 * 4] = cb[i4 + j + ((j + 3) & 3) * 4];
+                    }
+                }
+
+                for (i = 0; i < M_AES_NBb; i++)
+                {
+                    cb[i] = cw[i];
+                }
+            }
+        }
+
+        private static unsafe void AES_MixColumns(UInt32[] dataIn)
+        {
+            UInt32 i;
+            UInt32 i4;
+            UInt32 data1;
+            UInt32 data2;
+            UInt32 data3;
+            UInt32 data4;
+            UInt32 x;
+
+            fixed (UInt32* data = dataIn)
+            {
+                //byte* data = (byte*) ptr;
+                for (i = (UInt32)M_CLR; i < (UInt32)M_AES_NB; i++)
+                {
+                    i4 = (i * (UInt32)4);
+                    data1 = ((byte*)data)[i4 + (UInt32)0];
+                    data2 = ((byte*)data)[i4 + (UInt32)1];
+                    data3 = ((byte*)data)[i4 + (UInt32)2];
+                    data4 = ((byte*)data)[i4 + (UInt32)3];
+                    x = (AES_Mul(data1, (UInt32)2) ^ AES_Mul(data2, (UInt32)3) ^ AES_Mul(data3, (UInt32)1) ^ AES_Mul(data4, (UInt32)1));
+                    x |= (AES_Mul(data2, (UInt32)2) ^ AES_Mul(data3, (UInt32)3) ^ AES_Mul(data4, (UInt32)1) ^ AES_Mul(data1, (UInt32)1)) << 8;
+                    x |= (AES_Mul(data3, (UInt32)2) ^ AES_Mul(data4, (UInt32)3) ^ AES_Mul(data1, (UInt32)1) ^ AES_Mul(data2, (UInt32)1)) << 16;
+                    x |= (AES_Mul(data4, (UInt32)2) ^ AES_Mul(data1, (UInt32)3) ^ AES_Mul(data2, (UInt32)1) ^ AES_Mul(data3, (UInt32)1)) << 24;
+
+                    data[i] = x;
+                }
+            }
+                
+        }
+
+        private static UInt32 AES_Mul(UInt32 data, UInt32 n)
+        {
+            UInt32 i;
+            UInt32 x;
+
+            x = 0;
+            for (i = (UInt32)8; i > (UInt32)0; i = i / (UInt32)2)
+            {
+                x = x * (UInt32)2;
+                if (M_CLR != (x & (UInt32)0x0100))
+                {
+                    x = (x ^ (UInt32)0x001B) & (UInt32)0x00FF;
+                }
+                if (M_CLR != (n & i))
+                {
+                    x = x ^ data;
+                }
+            }
+            return x;
+        }
+    }
+}

+ 89 - 0
Simano/Model/CrcCalculator.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Simano.Model
+{
+    public static class CrcCalculator
+    {
+        const int M_POLYNOMIAL = 0x1021;
+        static ushort[] s_crc_tbl = new ushort[]
+        {
+            0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
+            0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
+            0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
+            0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
+            0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
+            0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
+            0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
+            0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
+            0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
+            0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
+            0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
+            0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
+            0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
+            0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
+            0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
+            0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
+            0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
+            0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
+            0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
+            0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
+            0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
+            0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
+            0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
+            0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
+            0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
+            0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
+            0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
+            0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
+            0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
+            0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
+            0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
+            0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
+        };
+
+        /**************************************************************************
+                        プロトタイプ宣言
+        **************************************************************************/
+
+        /**************************************************************************
+                        GLOBAL関数
+        **************************************************************************/
+
+        /*************************************************************************/
+        /**
+         * @brief       チェックサム16ビット生成
+         *              ⽣成多項式: X^16 + X^12 + X^5 + 1
+         *              初期化:0
+         * @par         概要:
+         * @return      なし
+        **************************************************************************/
+        public static ushort CMN_YmodemGenCrc16(byte[] data)
+        {
+            ushort crc = 0;
+
+            for (int i = 0; i < data.Length; ++i)
+            {
+                crc ^= (ushort)(data[i] << 8);
+
+                for (int j = 0; j < 8; ++j)
+                {
+                    if ((crc & 0x8000) > 0)
+                    {
+                        crc = (ushort)((crc << 1) ^ M_POLYNOMIAL);
+                    }
+                    else
+                    {
+                        crc <<= 1;
+                    }
+                }
+            }
+
+            return crc;
+        }
+
+    }
+}

+ 2 - 2
Simano/Properties/AssemblyInfo.cs

@@ -48,5 +48,5 @@ using System.Windows;
 //      組建編號
 //      修訂
 //
-[assembly: AssemblyVersion("0.0.1.0")]
-[assembly: AssemblyFileVersion("0.0.1.0")]
+[assembly: AssemblyVersion("0.0.2.0")]
+[assembly: AssemblyFileVersion("0.0.2.0")]

+ 442 - 61
Simano/Service/SimanoService.cs

@@ -1,11 +1,10 @@
-using Simano.Service.Adapter;
+using Simano.Model;
+using Simano.Service.Adapter;
 using Simano.Service.CubeProgrammerAPI;
 using System;
 using System.Collections.Generic;
 using System.IO.Ports;
 using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
 using System.Threading.Tasks;
 
 namespace Simano.Service
@@ -45,20 +44,42 @@ namespace Simano.Service
 
         private SerialPort serialPort;
         private string portName = string.Empty;
-        private byte cmdCNT = 0;
         private bool isApiMode = true;
 
+        private byte _cmdCNT = 0;
+        private byte cmdCNT
+        {
+            get
+            {
+                var record = _cmdCNT;
+                _cmdCNT++;
+                if (_cmdCNT >= 4)
+                {
+                    _cmdCNT = 0;
+                }
+                return record;
+            }
+        }
+
         public async Task<bool> Connect(string portName)
         {
             try
             {
-                cmdCNT = 0;
+                _cmdCNT = 0;
                 serialPort = new SerialPort(portName, baudRate:115200);
                 serialPort.Open();
                 this.portName = portName;
 
                 ClearReadBuffer();
                 var getStatusSuccess = await GetBoardStatus();
+                if (!getStatusSuccess)
+                {
+                    serialPort.Close();
+                }
+                if (getStatusSuccess && isApiMode)
+                {
+                    var aesVerifySuccess = await AesVerify();
+                }
                 return getStatusSuccess;
             }
             catch (Exception ex)
@@ -67,6 +88,19 @@ namespace Simano.Service
             }
         }
 
+        public bool Disconnect()
+        {
+            try
+            {
+                serialPort?.Close();
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+            return true;
+        }
+
         private async Task<bool> GetBoardStatus()
         {
             if (serialPort is null ||
@@ -75,87 +109,100 @@ namespace Simano.Service
                 return false;
             }
 
-            var test = serialPort.BytesToRead;
-
             WriteLog(null, "Detecting Board status...");
 
-            await Task.Delay(2500);
-            var canreceivedData = serialPort.BytesToRead > 0;
-
-            if (canreceivedData)
+            SendGetStatusCmd();
+            var result = await GetGetStatusRespond();
+            if (result is null)
             {
-                var readBuffer = new byte[20];
-                var readByteCnt = serialPort.Read(readBuffer, 0, 20);
-
-                try
-                {
-                    var reseivedString = Encoding.UTF8.GetString(readBuffer);
-                    WriteLog(null, reseivedString);
-                    if (reseivedString.Contains("OPEN"))
-                    {
-                        WriteLog(null, "ApiMode");
-                        isApiMode = true;
-                        return true;
-                    }
-                    return false;
-                }
-                catch
-                {
-                    return false;
-                }
+                return false;
             }
-
-            if (!canreceivedData)
+            if (result == 0x89)
             {
-                serialPort.Close();
-                var openPortResult = await CubeProgrammerAPIWrapper.OpenPort(portName);
-                if (!openPortResult)
-                    return false;
-                CubeProgrammerAPIAdapter.ClosePort();
-                serialPort.Open();
+                WriteLog(null, "ApiMode Detected");
+                isApiMode = true;
+                return true;
+            }
+            if (result == 0x79 || result == 0x1F)
+            {
+                WriteLog(null, "BootloadMode Detected");
                 isApiMode = false;
-                WriteLog(null, "BootloaderMode");
                 return true;
             }
-
+            WriteLog(null, "Not Supported Board!");
             return false;
         }
 
-        public bool Disconnect()
+        private async Task<bool> AesVerify()
         {
-            try
+            if (serialPort is null ||
+                !serialPort.IsOpen)
             {
-                serialPort?.Close();
+                return false;
             }
-            catch (Exception ex)
+
+            WriteLog(null, "Starting verify by aes...");
+
+            var challenge = await GetChallenge();
+            if (challenge is null)
             {
                 return false;
             }
-            return true;
+
+            var aesEncodedChallenge = AesEncoder.GetAesEncoded(challenge);
+            bool isChallengeSuccess = await RespondChallenge(aesEncodedChallenge);
+            if (isChallengeSuccess)
+            {
+                WriteLog(null, "AES verify success");
+            }
+            else
+            {
+                WriteLog(null, "AES verify FAILED");
+            }
+            return isChallengeSuccess;
         }
 
         public async Task<bool> FlashFirmware(string filePath)
         {
+            if (serialPort is null ||
+                !serialPort.IsOpen)
+            {
+                return false;
+            }
+            WriteLog(this, "Starting FlashFirmware");
+
             await GetBoardStatus();
             if (isApiMode)
             {
-                SendFlashFirmwareCmd();
-                await Task.Delay(3000);
-                ClearReadBuffer();
+                var changeToBootloadModeResult = await ChangeToBootloadMode();
+                if (!changeToBootloadModeResult)
+                {
+                    WriteLog(this, "Change to Bootload FAILED");
+                    return false;
+                }
             }
             serialPort.Close();
             try
             {
                 var openPortResult = await CubeProgrammerAPIWrapper.OpenPort(portName);
                 if (!openPortResult)
+                {
+                    WriteLog(this, "CubeProgrammer open port FAILED");
                     return false;
+                }
                 //var flshResult = CubeProgrammerAPIAdapter.DownloadFile(filePath, 0x08008000u);
                 var flshResult = await CubeProgrammerAPIWrapper.DownloadFile(filePath, 0x08008000u);
                 if (!flshResult)
+                {
+                    WriteLog(this, "CubeProgrammer download file FAILED");
                     return false;
+                }
                 var runResult = await CubeProgrammerAPIWrapper.Run(0x08008000u);
                 if (!runResult)
+                {
+                    WriteLog(this, "CubeProgrammer start run FAILED");
                     return false;
+                }
             }
             finally
             {
@@ -165,6 +212,66 @@ namespace Simano.Service
             return true;
         }
 
+        public Task<byte?> GetFirmwareVersion()
+        {
+            if (serialPort is null ||
+                !serialPort.IsOpen)
+            {
+                return null;
+            }
+            WriteLog(this, "Starting GetFirmwareVersion");
+
+            SendGetFirmwareVersionCmd();
+            return GetGetFirmwareVersionRespond();
+        }
+
+        public Task<byte?> GetEeprom(int address)
+        {
+            if (serialPort is null ||
+                !serialPort.IsOpen)
+            {
+                return null;
+            }
+            WriteLog(this, $"Starting GetEeprom at {address}");
+
+            SendGetEepromCmd((byte)address);
+            return GetGetEepromRespond((byte)address);
+        }
+
+        public Task<bool?> EraseEeprom(int address)
+        {
+            if (serialPort is null ||
+                !serialPort.IsOpen)
+            {
+                return null;
+            }
+            WriteLog(this, $"Starting EraseEeprom at {address}");
+
+            SendEraseEepromCmd((byte)address);
+            return GetEraseEepromRespond((byte)address);
+        }
+
+        private async Task<byte[]> GetChallenge()
+        {
+            SendGetChallengeCmd();
+            var result = await GetGetChallengeRespond();
+            return result;
+        }
+
+        private async Task<bool> RespondChallenge(byte[] aesEncodedChallenge)
+        {
+            SendChallengedDataCmd(aesEncodedChallenge);
+            var result = await GetRespondChallengeRespond();
+            return result;
+        }
+
+        private Task<bool> ChangeToBootloadMode()
+        {
+            SendFlashFirmwareCmd();
+            return GetFlashFirmwareCmdRespond();
+        }
+
+
         private void CubeProgrammerAPIAdapter_OnLogReceived(object sender, string e)
         {
             //Console.WriteLine(e);
@@ -176,33 +283,307 @@ namespace Simano.Service
             OnLogReceived?.Invoke(sender, e);
         }
 
+        private void SendGetStatusCmd()
+        {
+            ClearReadBuffer();
+            var cmd = GetGetStatusCmd();
+            serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
+        private void SendGetChallengeCmd()
+        {
+            ClearReadBuffer();
+            var cmd = GetGetChallengeCmd();
+            serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
+        private void SendChallengedDataCmd(byte[] data)
+        {
+            ClearReadBuffer();
+            serialPort.Write(data, 0, data.Length);
+            return;
+        }
         private void SendFlashFirmwareCmd()
         {
             ClearReadBuffer();
             var cmd = GetFlashFirmwareCmd();
             serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
+        private void SendGetFirmwareVersionCmd()
+        {
+            ClearReadBuffer();
+            var cmd = GetGetFirmwareVersionCmd();
+            serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
+        private void SendGetEepromCmd(byte address)
+        {
+            ClearReadBuffer();
+            var cmd = GetGetEepromCmd(address);
+            serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
+        private void SendEraseEepromCmd(byte address)
+        {
+            ClearReadBuffer();
+            var cmd = GetEraseEepromCmd(address);
+            serialPort.Write(cmd, 0, cmd.Length);
+            return;
+        }
 
-            //var readBuffer = new byte[10];
-            //var readByteCnt = serialPort.Read(readBuffer, 0 , 10);
+        private async Task<byte?> GetGetStatusRespond()
+        {
+            await Task.Delay(1000);
+            if (serialPort.BytesToRead <= 0)
+            {
+                return null;
+            }
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+            if (dumpBuffer.Length != 1)
+            {
+                return null;
+            }
+            return dumpBuffer[0];
+        }
+        private async Task<byte[]> GetGetChallengeRespond()
+        {
+            await Task.Delay(1000);
+            if (serialPort.BytesToRead <= 0)
+            {
+                return null;
+            }
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+            if (dumpBuffer.Length != 16)
+            {
+                return null;
+            }
+            return dumpBuffer;
+        }
+        private async Task<bool> GetRespondChallengeRespond()
+        {
+            if (serialPort.BytesToRead <= 0)
+            {
+                return false;
+            }
+            await Task.Delay(1000);
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+            if (dumpBuffer.Length == 9)
+            {
+                //AES_ERROR
+                if (dumpBuffer[0] == 0x41 &&
+                    dumpBuffer[1] == 0x45 &&
+                    dumpBuffer[2] == 0x53 &&
+                    dumpBuffer[3] == 0x2D &&
+                    dumpBuffer[4] == 0x45 &&
+                    dumpBuffer[5] == 0x72 &&
+                    dumpBuffer[6] == 0x72 &&
+                    dumpBuffer[7] == 0x6F &&
+                    dumpBuffer[8] == 0x72 )
+                {
+                    return false;
+                }
+            }
 
-            //try
-            //{
-            //    var reseivedString = Encoding.UTF8.GetString(readBuffer);
-            //    Console.WriteLine(reseivedString);
-            //}
-            //catch
-            //{
+            if (dumpBuffer.Length == 6)
+            {
+                //AES_OK
+                if (dumpBuffer[0] == 0x41 &&
+                    dumpBuffer[1] == 0x45 &&
+                    dumpBuffer[2] == 0x53 &&
+                    dumpBuffer[3] == 0x2D &&
+                    dumpBuffer[4] == 0x4F &&
+                    dumpBuffer[5] == 0x4B )
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+        private async Task<bool> GetFlashFirmwareCmdRespond()
+        {
+            if (serialPort.BytesToRead <= 0)
+            {
+                return false;
+            }
+            await Task.Delay(1000);
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
 
-            //}
+            if (dumpBuffer.Length != 8)
+            {
+                return false;
+            }
+            if (dumpBuffer[0] == 0x00 &&    //0x00
+                //dumpBuffer[1] == 0x45 &&  //0x80
+                //dumpBuffer[2] == 0x53 &&  //0x03
+                dumpBuffer[3] == 0xD1 &&    //0xd1
+                dumpBuffer[4] == 0x00 &&    //0x00
+                dumpBuffer[5] == 0x01       //0x01
+                //dumpBuffer[6] == 0x72 &&
+                //dumpBuffer[7] == 0x6F
+                )
+            {
+                return true;
+            }
 
-            return;
+            return false;
+        }
+        private async Task<byte?> GetGetFirmwareVersionRespond()
+        {
+            if (serialPort.BytesToRead <= 0)
+            {
+                return null;
+            }
+            await Task.Delay(1000);
+
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+
+            if (dumpBuffer.Length != 8)
+            {
+                return null;
+            }
+
+            if (dumpBuffer[0] == 0x00 &&    //0x00
+                //dumpBuffer[1] == 0x45 &&  //0x8x
+                //dumpBuffer[2] == 0x53 &&  //0x03
+                dumpBuffer[3] == 0xD2 &&    //0xd2
+                dumpBuffer[4] == 0x00       //0x00
+                //dumpBuffer[5] == 0x01     //0xXX
+                //dumpBuffer[6] == 0x72
+                //dumpBuffer[7] == 0x6F
+                )
+            {
+                return dumpBuffer[5];
+            }
+
+            return null;
+        }
+        private async Task<byte?> GetGetEepromRespond(byte expectedAddress)
+        {
+            if (serialPort.BytesToRead <= 0)
+            {
+                return null;
+            }
+            await Task.Delay(1000);
+
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+
+            if (dumpBuffer.Length != 10)
+            {
+                return null;
+            }
+
+            if (dumpBuffer[0] == 0x00 &&    //0x00
+                //dumpBuffer[1] == 0x45 &&  //0x8x
+                //dumpBuffer[2] == 0x53 &&  //0x03
+                dumpBuffer[3] == 0xD0 &&    //0xd0
+                dumpBuffer[4] == 0x00 &&    //0x00
+                dumpBuffer[5] == 0x01 &&    //0x01
+                dumpBuffer[6] == expectedAddress    //0x10
+                //dumpBuffer[7] == 0x6F     //data
+                //dumpBuffer[8] == 0x6F    
+                //dumpBuffer[9] == 0x6F     
+                )
+            {
+                return dumpBuffer[7];
+            }
+
+            return null;
+        }
+        private async Task<bool?> GetEraseEepromRespond(byte expectedAddress)
+        {
+            if (serialPort.BytesToRead <= 0)
+            {
+                return null;
+            }
+            await Task.Delay(1000);
+
+            var dumpBuffer = new byte[serialPort.BytesToRead];
+            serialPort.Read(dumpBuffer, 0, dumpBuffer.Length);
+
+            if (dumpBuffer.Length != 8)
+            {
+                return null;
+            }
+
+            if (dumpBuffer[0] == 0x00 &&    //0x00
+                //dumpBuffer[1] == 0x45 &&  //0x8x
+                //dumpBuffer[2] == 0x53 &&  //0x03
+                dumpBuffer[3] == 0xD0 &&    //0xD0
+                dumpBuffer[4] == 0x00 &&    //0x00
+                dumpBuffer[5] == expectedAddress    //0x01
+                //dumpBuffer[6] == 0x6F     
+                //dumpBuffer[7] == 0x6F     
+                )
+            {
+                return true;
+            }
+            return false;
         }
 
         private byte[] GetFlashFirmwareCmd()
         {
-            byte[] baseCmd = new byte[] { 0x00, 0x00, 0x02, 0xD1, 0x01, 0x26, 0xD4 };
+            byte[] baseCmd = new byte[] { 0x00, 0x00, 0x02, 0xD1, 0x01 };
+            baseCmd[1] = cmdCNT;
+            ushort crc16 = CrcCalculator.CMN_YmodemGenCrc16(baseCmd);
+            byte[] result = new byte[baseCmd.Length + 2];
+            Array.Copy(baseCmd, result, baseCmd.Length);
+            result[result.Length - 2] = (byte)(crc16 / 256);
+            result[result.Length - 1] = (byte)(crc16 % 256);
+            return result;
+        }
+        private byte[] GetGetFirmwareVersionCmd()
+        {
+            byte[] baseCmd = new byte[] { 0x00, 0x00, 0x02, 0xD2, 0x01 };
             baseCmd[1] = cmdCNT;
-            cmdCNT++;
+            ushort crc16 = CrcCalculator.CMN_YmodemGenCrc16(baseCmd);
+            byte[] result = new byte[baseCmd.Length + 2];
+            Array.Copy(baseCmd, result, baseCmd.Length);
+            result[result.Length - 2] = (byte)(crc16 / 256);
+            result[result.Length - 1] = (byte)(crc16 % 256);
+            return result;
+        }
+        private byte[] GetGetEepromCmd(byte address)
+        {
+            byte[] baseCmd = new byte[] { 0x00, 0x00, 0x02, 0xD0, 0x01, 0x00 };
+            baseCmd[1] = cmdCNT;
+            baseCmd[5] = address;
+            ushort crc16 = CrcCalculator.CMN_YmodemGenCrc16(baseCmd);
+            byte[] result = new byte[baseCmd.Length + 2];
+            Array.Copy(baseCmd, result, baseCmd.Length);
+            result[result.Length - 2] = (byte)(crc16 / 256);
+            result[result.Length - 1] = (byte)(crc16 % 256);
+            return result;
+        }
+
+        private byte[] GetEraseEepromCmd(byte address)
+        {
+            byte[] baseCmd = new byte[] { 0x00, 0x00, 0x02, 0xD0, 0x00, 0x01 };
+            baseCmd[1] = cmdCNT;
+            baseCmd[5] = address;
+            ushort crc16 = CrcCalculator.CMN_YmodemGenCrc16(baseCmd);
+            byte[] result = new byte[baseCmd.Length + 2];
+            Array.Copy(baseCmd, result, baseCmd.Length);
+            result[result.Length - 2] = (byte)(crc16 / 256);
+            result[result.Length - 1] = (byte)(crc16 % 256);
+            return result;
+        }
+
+        private byte[] GetGetStatusCmd()
+        {
+            byte[] baseCmd = new byte[] { 0x7F, 0x7F };
+            return baseCmd;
+        }
+
+        private byte[] GetGetChallengeCmd()
+        {
+            byte[] baseCmd = new byte[] { 0x7A, 0x7A };
             return baseCmd;
         }
 

+ 2 - 0
Simano/Simano.csproj

@@ -83,7 +83,9 @@
       <SubType>Designer</SubType>
     </ApplicationDefinition>
     <Compile Include="AppSettingConfig.cs" />
+    <Compile Include="Model\AesEncoder.cs" />
     <Compile Include="Model\AppSettingConfigModel.cs" />
+    <Compile Include="Model\CrcCalculator.cs" />
     <Compile Include="Model\UiStatus.cs" />
     <Compile Include="Service\CubeProgrammerAPI\CubeProgrammerAPIAdapter.cs" />
     <Compile Include="Service\CubeProgrammerAPI\CubeProgrammerAPIAdapterModels.cs" />

+ 42 - 1
Simano/UserControls/MainUserUI.xaml

@@ -48,7 +48,7 @@
                 <RowDefinition/>
                 <RowDefinition/>
             </Grid.RowDefinitions>
-            <StackPanel Orientation="Vertical" VerticalAlignment="Center">
+            <StackPanel Grid.Row="0" Orientation="Vertical" VerticalAlignment="Center">
                 <Label Content="FW Update" FontWeight="Bold" FontSize="24"  VerticalAlignment="Top" HorizontalAlignment="Left"/>
                 <Grid>
                     <Grid.ColumnDefinitions>
@@ -63,6 +63,47 @@
                     </StackPanel>
                 </Grid>
             </StackPanel>
+            <StackPanel Grid.Row="1" Orientation="Vertical" VerticalAlignment="Center">
+                <Label Content="FW Version" FontWeight="Bold" FontSize="24"  VerticalAlignment="Top" HorizontalAlignment="Left"/>
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*"/>
+                        <ColumnDefinition Width="100"/>
+                    </Grid.ColumnDefinitions>
+                    <Button x:Name="uxFirmwareVersionBtn" Content="Get" Grid.Column="1"/>
+                    <StackPanel Orientation="Horizontal">
+                        <TextBox x:Name="uxFirmwareVersionText" Text="Unknown" Width="270" IsReadOnly="True"/>
+                    </StackPanel>
+                </Grid>
+            </StackPanel>
+            <StackPanel Grid.Row="2" Orientation="Vertical" VerticalAlignment="Center">
+                <Label Content="EEPROM read" FontWeight="Bold" FontSize="24"  VerticalAlignment="Top" HorizontalAlignment="Left"/>
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*"/>
+                        <ColumnDefinition Width="100"/>
+                    </Grid.ColumnDefinitions>
+                    <Button x:Name="uxEepromReadBtn" Content="Read" Grid.Column="1"/>
+                    <StackPanel Orientation="Horizontal">
+                        <ComboBox x:Name="uxEepromReadAddress" Width="70"/>
+                        <Rectangle Width="10"/>
+                        <TextBox x:Name="uxEepromReadText" Text="Unknown" Width="200" IsReadOnly="True"/>
+                    </StackPanel>
+                </Grid>
+            </StackPanel>
+            <StackPanel Grid.Row="3" Orientation="Vertical" VerticalAlignment="Center">
+                <Label Content="EEPROM erase" FontWeight="Bold" FontSize="24"  VerticalAlignment="Top" HorizontalAlignment="Left"/>
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*"/>
+                        <ColumnDefinition Width="100"/>
+                    </Grid.ColumnDefinitions>
+                    <Button x:Name="uxEepromEraseBtn" Content="Erase" Grid.Column="1"/>
+                    <StackPanel Orientation="Horizontal">
+                        <ComboBox x:Name="uxEepromEraseAddress" Width="70"/>
+                    </StackPanel>
+                </Grid>
+            </StackPanel>
         </Grid>
         <FlowDocumentScrollViewer  x:Name="uxConsoleScroller" Grid.Column="2" Background="Black" Foreground="White" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
             <FlowDocument Background="Black">

+ 108 - 0
Simano/UserControls/MainUserUI.xaml.cs

@@ -51,6 +51,9 @@ namespace Simano.UserControls
             uxComportSelector.SelectionChanged += UxComportSelector_SelectionChanged;
             uxFirmwareUpdateBtn.Click += UxFirmwareUpdateBtn_Click;
             uxSelectFirmwareBtn.Click += UxSelectFirmwareBtn_Click;
+            uxFirmwareVersionBtn.Click += UxFirmwareVersionBtn_Click;
+            uxEepromReadBtn.Click += UxEepromReadBtn_Click;
+            uxEepromEraseBtn.Click += UxEepromEraseBtn_Click;
             SimanoService.Instance.OnLogReceived += SimanoService_OnLogReceived;
 
             var comList = SimanoService.Instance.GetComportList();
@@ -64,6 +67,17 @@ namespace Simano.UserControls
 
             var recordedFirmwarePath = AppSettingConfig.Instance.FirmwarePath;
             uxFirmwarelocationText.Text = recordedFirmwarePath;
+
+            List<string> numbers = Enumerable.Range(1, 0xFF).Select(x => x.ToString("X") ).ToList();
+
+            var eraseAddressItems = new List<string>();
+            eraseAddressItems.Add("ALL");
+            eraseAddressItems.AddRange(numbers);
+            uxEepromReadAddress.ItemsSource = eraseAddressItems;
+
+            var readAddressItems = new List<string>();
+            eraseAddressItems.AddRange(numbers);
+            uxEepromEraseAddress.ItemsSource = eraseAddressItems;
         }
 
         private void MainUserUI_Loaded(object sender, RoutedEventArgs e)
@@ -128,6 +142,54 @@ namespace Simano.UserControls
             Status = UiStatus.Connected;
         }
 
+        private async void UxFirmwareVersionBtn_Click(object sender, RoutedEventArgs e)
+        {
+            Status = UiStatus.Busy;
+            var result = await SimanoService.Instance.GetFirmwareVersion();
+            if (result is null)
+            {
+                MessageBox.Show("Get Version Failed");
+            }
+            uxFirmwareVersionText.Text = result.ToString();
+            Status = UiStatus.Connected;
+        }
+
+        private async void UxEepromReadBtn_Click(object sender, RoutedEventArgs e)
+        {
+            Status = UiStatus.Busy;
+            int? address = GetAddress(uxEepromReadAddress);
+            if (address is null)
+            {
+                MessageBox.Show("Address Error");
+                return;
+            }    
+            var result = await SimanoService.Instance.GetEeprom(address.Value);
+            if (result is null)
+            {
+                MessageBox.Show("Get Version Failed");
+            }
+            uxEepromReadText.Text = result.ToString();
+            Status = UiStatus.Connected;
+        }
+
+        private async void UxEepromEraseBtn_Click(object sender, RoutedEventArgs e)
+        {
+            Status = UiStatus.Busy;
+            int? address = GetAddress(uxEepromEraseAddress);
+            if (address is null)
+            {
+                MessageBox.Show("Address Error");
+                return;
+            }
+            var result = await SimanoService.Instance.EraseEeprom(address.Value);
+            if (result is null || result == false)
+            {
+                MessageBox.Show("EEPROM Erase failed");
+            }
+            MessageBox.Show("EEPROM Erase success");
+            Status = UiStatus.Connected;
+        }
+
         private void UxComportSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
             AppSettingConfig.Instance.PortName = uxComportSelector.SelectedItem.ToString();
@@ -215,6 +277,12 @@ namespace Simano.UserControls
                     uxFirmwareUpdateBtn.IsEnabled = false;
                     uxSelectFirmwareBtn.IsEnabled = true;
 
+                    uxFirmwareVersionBtn.IsEnabled = false;
+                    uxEepromReadBtn.IsEnabled = false;
+                    uxEepromEraseBtn.IsEnabled = false;
+                    uxEepromReadAddress.IsEnabled = false;
+                    uxEepromEraseAddress.IsEnabled = false;
+
                     uxConnectedStatusHint.Visibility = Visibility.Collapsed;
                     uxDisconnectedStatusHint.Visibility = Visibility.Visible;
                     uxRunningStatusHint.Visibility = Visibility.Collapsed;
@@ -226,6 +294,12 @@ namespace Simano.UserControls
                     uxFirmwareUpdateBtn.IsEnabled = false;
                     uxSelectFirmwareBtn.IsEnabled = true;
 
+                    uxFirmwareVersionBtn.IsEnabled = false;
+                    uxEepromReadBtn.IsEnabled = false;
+                    uxEepromEraseBtn.IsEnabled = false;
+                    uxEepromReadAddress.IsEnabled = false;
+                    uxEepromEraseAddress.IsEnabled = false;
+
                     uxConnectedStatusHint.Visibility = Visibility.Collapsed;
                     uxDisconnectedStatusHint.Visibility = Visibility.Visible;
                     uxRunningStatusHint.Visibility = Visibility.Collapsed;
@@ -237,6 +311,12 @@ namespace Simano.UserControls
                     uxFirmwareUpdateBtn.IsEnabled = true;
                     uxSelectFirmwareBtn.IsEnabled = true;
 
+                    uxFirmwareVersionBtn.IsEnabled = true;
+                    uxEepromReadBtn.IsEnabled = true;
+                    uxEepromEraseBtn.IsEnabled = true;
+                    uxEepromReadAddress.IsEnabled = true;
+                    uxEepromEraseAddress.IsEnabled = true;
+
                     uxConnectedStatusHint.Visibility = Visibility.Visible;
                     uxDisconnectedStatusHint.Visibility = Visibility.Collapsed;
                     uxRunningStatusHint.Visibility = Visibility.Collapsed;
@@ -248,6 +328,12 @@ namespace Simano.UserControls
                     uxFirmwareUpdateBtn.IsEnabled = false;
                     uxSelectFirmwareBtn.IsEnabled = false;
 
+                    uxFirmwareVersionBtn.IsEnabled = false;
+                    uxEepromReadBtn.IsEnabled = false;
+                    uxEepromEraseBtn.IsEnabled = false;
+                    uxEepromReadAddress.IsEnabled = false;
+                    uxEepromEraseAddress.IsEnabled = false;
+
                     uxConnectedStatusHint.Visibility = Visibility.Collapsed;
                     uxDisconnectedStatusHint.Visibility = Visibility.Collapsed;
                     uxRunningStatusHint.Visibility = Visibility.Visible;
@@ -255,5 +341,27 @@ namespace Simano.UserControls
             }
 
         }
+
+        private int? GetAddress(ComboBox source)
+        {
+            var selected = source.SelectedItem as string;
+            if (selected.ToUpper() == "ALL")
+            {
+                return 0;
+            }
+            try
+            {
+                int address = Convert.ToInt32(selected, 16);
+                if (address < 0 || address > 0xff)
+                {
+                    return null;
+                }
+                return address;
+            }
+            catch
+            {
+                return null;
+            }
+        }
     }
 }