using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using CrcTest;
using System.Collections;
using System.Threading;
using SXLibrary;
using System.Diagnostics;

namespace MOKA_Factory_Tools
{
    
    class SerialCMD
    {
        #region 串口重试机制;
        public static bool EnableRetry { get; set; } = false;

        public static int RetryCount { get; set; } = 3;
        #endregion

        /// <summary>
        /// 串口指令读超时值，单位毫秒;
        /// 默认：3000ms
        /// </summary>
        public static int ReadTimeout { get; set; } = 3000;

        /// <summary>
        /// 串口完成一次指令的Write、Read后，下一条指令等待多久开始执行（即执行完当前指令后，等待多久函数才返回）;
        /// 单位：毫秒，默认200毫秒
        /// </summary>
        public static int NextCommandWaitTime { get; set; } = 100;

        public static int SerialTimeout { get; set; }
        static byte[] ACKhead = new byte[5] { 0xAB, 0x05, 0x0A, 0xDF, 0x4E };//命令可执行数据返回
        static byte[] ACKhead2 = new byte[5] { 0xAB, 0x05, 0x0E, 0x9F, 0xCA };//命令错误或无法识别数据返回
        static byte[] ACKhead3 = new byte[5] { 0xAB, 0x05, 0x0F, 0x8F, 0xEB };//CRC16校验错误返回

        /// <summary>
        /// 进工厂
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool EnterFactory(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return Sendcmd(Comport, new byte[] { 0xAA }, new byte[] { 0x10 }, new byte[] { 0x01 },false,false, out result, out data,out error, waitTime);
        }

        /// <summary>
        /// 退工厂
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool LeaveFactory(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return Sendcmd(Comport, new byte[] { 0xAA }, new byte[] { 0x10 }, new byte[] { 0x00 }, false, false, out result, out data,out error, waitTime);
        }

        /// <summary>
        /// 白平衡初始化
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool WBInit(SerialPort Comport, out byte[] result, out byte[]data,out string error,int waitTime)
        {
             return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x16 }, new byte[] { 0x02 }, false, false, out result,out data, out error, waitTime);
        }

        //get keys
        /// <summary>
        /// 查询PID
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetProjectID(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime, bool WriteEDID=false)
        {
            if (!WriteEDID) Thread.Sleep(3000);
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x84 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 获取软件版本
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetSoftVersion(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x57 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 获取Device ID
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetDeviceId(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x01 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x01)
                {
                    data=data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回did类型错误，应为01";
                    return false;
                }

            }
            else
                return false;
            
        }

        /// <summary>
        /// 获取Client Type
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetClientType(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x8C }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 获取Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetMAC(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x00)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回MAC类型错误，应为00";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取HDCP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetHDCPKey(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEE }, new byte[] { 0x00 }, true, true, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 获取HDCP2.2
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetHDCPKey22(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xE7 }, new byte[] { 0x00 }, true, true, out result, out data, out error,waitTime);
        }

        /// <summary>
        /// 获取WiDi
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetWidi(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xE7 }, new byte[] { 0x00 }, true, true, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 获取ESN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetNetflixESN(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x06 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x06)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回NetflixESN类型错误，应为06";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取Widevine
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetWidevine(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x00 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x00)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Widevine类型错误，应为00";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取Ci
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetCiKey(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x01 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x01)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回CiKey类型错误，应为01";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取ECP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetECP(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x0C }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x0C)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回ECP类型错误，应为01";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取MGK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetMGKKey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x06 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x06)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回MGKKey类型错误，应为06";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取OSD语言
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetOSDLanguage(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if(SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x97 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x00)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回OSD language类型错误，应为00";
                    return false;
                }              
            }
            else
                return false;
        }

        /// <summary>
        /// 获取出货语言
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetShopLanguage(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if(SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x97 }, new byte[] { 0x01 }, true, false, out result, out data, out error, waitTime))
            {
                {
                    if (data[0] == 0x01)
                    {
                        data = data.Skip(1).Take(data.Length - 1).ToArray();
                        return true;
                    }
                    else
                    {
                        error = "返回SHOP language类型错误，应为01";
                        return false;
                    }
                }            
            }
            else
                return false;
        }

        /// <summary>
        /// 获取当前信源
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetChannel(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x97 }, new byte[] { 0x13 }, true, false, out result, out data, out error, waitTime);
        }

        //Set keys
        /// <summary>
        /// 写入Pid
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetProjectId(SerialPort Comport, byte[] param,out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x70 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入Device ID
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetDeviceID(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xB2 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetMAC(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xB3 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入HDCP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetHDCPKey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA,0xFE }, new byte[] { 0x86 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入HDCP22
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetHDCPKey22(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE4 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入ESN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetNetflixESN(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA}, new byte[] { 0x99,0x00 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入Widi
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetWidi(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE4 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入Widevine
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetWidevine(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE9,0x00 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入Ci
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetCiKey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE9, 0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 写入ECP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetECP(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE9, 0x0C }, param, false, false, out result, out data, out error, waitTime);
        }


        /// <summary>
        /// 写入MGK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetMGKKey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0x99, 0x00 }, param, false, false, out result, out data, out error, waitTime);
        }

        //check keys
        /// <summary>
        /// 校验Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckMAC(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if(SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xB4 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 1 && (data[0] == 0x01 || data[0] == 0x03 || data[0] == 0x05 || data[0] == 0x07)) 
                {
                    /*
                    0x00:All data hadn't beeninstalled
                    0x01:MAC address successful
                    0x02:Device ID successful
                    0x03:Mac and device ID had been installed
                    0x04:User ID successful
                    0x05:Mac and user ID had been installed
                    0x06:User ID and device ID had been installed
                    0x07:All data had been installed
                    */
                    return true;
                }
                else
                {
                    error = "Mac haven't been installed";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 校验Device ID
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckDeviceId(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xB4 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 1 && (data[0] == 0x02 || data[0] == 0x03 || data[0] == 0x06 || data[0] == 0x07))
                {
                    /*
                    0x00:All data hadn't beeninstalled
                    0x01:MAC address successful
                    0x02:Device ID successful
                    0x03:Mac and device ID had been installed
                    0x04:User ID successful
                    0x05:Mac and user ID had been installed
                    0x06:User ID and device ID had been installed
                    0x07:All data had been installed
                    */
                    return true;
                }
                else
                {
                    error = "Diveice ID haven't been installed";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 校验HDCP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckHDCP(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x87 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 1 && data[0] == 0x01)
                    return true;
                else
                {
                    error = "HDCP KEY check fail,return status shoule be 0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 校验ESN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckNetflixESN(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x00 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ESN return status fail,should be 0x00,0x01";
                    return false;
                }
                    
            }
            else
                return false;
        }

        /// <summary>
        /// 校验Widi
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckWidi(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if( SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xE5 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 1 && data[0] == 0x01)
                    return true;
                else
                {
                    error = "WiDi KEY check fail,return status shoule be 0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 校验Widevine
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckWidevine(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if( SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEA }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x00 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Widevine return status fail,should be 0x00,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 校验Ci
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckCikey(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if( SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEA }, new byte[] { 0x01 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x01 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Ci return status fail,should be 0x01,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 校验ECP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckECP(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEA }, new byte[] { 0x0C }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0C && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ECP return status fail,should be 0x01,0x01";
                    return false;
                }

            }
            else
                return false;
        }


        /// <summary>
        /// 校验MGK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckMGKkey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x00 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "MGK return status fail,should be 0x00,0x01";
                    return false;
                }

            }
            else
                return false;
        }
        /// <summary>
        /// 校验HDCP22
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckHDCP22(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if( SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xE5 }, new byte[] { 0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 1 && data[0] == 0x01)
                    return true;
                else
                {
                    error = "HDCP22 KEY check fail,return status shoule be 0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 开老化
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool StartWarmUpMode(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x13 }, new byte[] { 0x01 }, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 关老化
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool StopWarmUpMode(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x13 }, new byte[] { 0x00 }, false, false, out result, out data, out error, waitTime);
        }

        //set something
        /// <summary>
        /// 设置OSD语言
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetOSDLanguage(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x96, 0x00 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 设置出厂语言
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetShopLanguage(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x96, 0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 预置频道
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetChannel(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x15 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 设置标准色温RGB值
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetWBNormal(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x4D ,0x04 ,0x01 ,0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 设置冷色温RGB值
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetWBCool(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x4D, 0x04, 0x02, 0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 设置暖色温RGB值
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetWBWarm(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x4D, 0x04, 0x03, 0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目品牌服务信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKUBrand(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x11 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目区域服务信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKURegion(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x12 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目服务网站服务信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKUSupportURL(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x13 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目服务电话服务信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKUSupportPhone(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x14 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目服务生产日期信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKUProductionDate(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x15 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目遥控器类型信息抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetROKURemoteType(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x19 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// SCBC ROKU 项目品牌服务信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKUBrand(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x0B }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0B && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ROKU Brand check fail,return status shoule be 0x0B ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// SCBC ROKU 项目服务网址服务信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKUSupportURL(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x0D }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0D && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ROKU Support URL check fail,return status shoule be 0x0D ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// SCBC ROKU 项目区域服务信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKURegion(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x0C }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0C && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ROKU Region check fail,return status shoule be 0x0C ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// SCBC ROKU 项目服务电话服务信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKUSupportPhone(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x0E }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0E && data[1] == 0x01)
                    return true;
                else
                {
                    error = "ROKU Support Phone check fail,return status shoule be 0x0E ,0x01";
                    return false;
                }
            }
            else
                return false;
        }


        /// <summary>
        /// SCBC ROKU 项目生产日期服务信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKUProductionDate(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x0F }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0F && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Production Date check fail,return status shoule be 0x0F ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// SCBC ROKU 项目遥控器信息抄写状态查询
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckROKURemoteType(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x13 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x13 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Remote type check fail,return status shoule be 0x13 ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 获取SCBC ROKU 项目品牌服务信息
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKUBrand(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x10 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x10)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回brand类型错误，应为10";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取SCBC ROKU 项目区域服务信息
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKURegion(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x11 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x11)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Region类型错误，应为11";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取SCBC ROKU 项目服务网址服务信息
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKUSupportURL(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x12 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x12)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Support URL类型错误，应为12";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取SCBC ROKU 项目服务网址服务信息
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKUSupportPhone(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x13 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x13)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Support Phone类型错误，应为13";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取SCBC ROKU 项目服务网址服务信息
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKUProductionDate(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x14 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x14)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Production Date类型错误，应为14";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取SCBC ROKU 项目遥控器类型信息（00---普通遥控器；01---语音遥控器）
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetROKURemoteType(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x18 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x18)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Remote Type类型错误，应为0x18";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 产品机型名抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetModelName(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x09 }, param, false, false, out result, out data, out error,waitTime);
        }

        /// <summary>
        /// 产品机型名检查
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckModelName(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x08 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x08 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Model name check fail,return status shoule be 0x08 ,0x01";
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// 产品机型名读取
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetModelName(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x0E }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x0E)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Model name类型错误，应为0E";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 写入Attestation Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetAttestationKey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE9, 0x0D }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查Attestation Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckAttestationKey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEA }, new byte[] { 0x0D }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0D && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Attestation Key return status fail,should be 0x0D,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取AttestationKey
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetAttestationKey(SerialPort Comport, out byte[] result, out byte[] data, out string error,int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x0D }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x0D)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回AttestationKey类型错误，应为0D";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// FireTV项目WiFi_Mac抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVWifiMac(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x16 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// FireTV项目BT_Mac抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVBTMac(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x17 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// FireTV项目DSN抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVDSN(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x18 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 校验FireTV项目WiFi_Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckFireTVWifiMac(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x10 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x10 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "FireTVWifiMac return status fail,should be 0x10,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 校验FireTV项目BT_Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckFireTVBTMac(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x11 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x11 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "FireTVBTMac return status fail,should be 0x11,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 校验FireTV项目DSN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckFireTVDSN(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x12 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x12 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "FireTVDSN return status fail,should be 0x12,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 获取FireTV项目WiFi_Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetFireTVWiFi_Mac(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x15 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x15)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回FireTVWiFi_Mac类型错误，应为15";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取FireTV项目BT_Mac
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetFireTVBT_Mac(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x16 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x16)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回FireTVBT_Mac类型错误，应为16";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 获取FireTV项目DSN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetFireTVDSN(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x17 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x17)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回FireTVDSN类型错误，应为17";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// FireTV项目Fairplay key抄写
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool SetFireTVFairplay(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xE9, 0x0E }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 校验FireTV项目Fairplay key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CheckFireTVFairplay(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEA }, new byte[] { 0x0E }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x0E && data[1] == 0x01)
                    return true;
                else
                {
                    error = "Fairplay return status fail,should be 0x0E,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目Fairplay key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool ReadFireTVFairplay(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x0F }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x0F)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Fairplay类型错误，应为0F";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// DHA激活生成
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool CreateFireTVDHA(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x96, 0x03 }, new byte[] { 0x00 }, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查DHA生成情况
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVDHA(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x14 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 2 && data[0] == 0x14 && data[1] == 0x01)
                    return true;
                else
                {
                    error = "DHA return status fail,should be 0x14,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取设备码
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool GetFireTVDevcieCode(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            // 计算函数耗时;
            Stopwatch watch = new Stopwatch();
            watch.Start();
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xEC }, new byte[] { 0x11,0x06 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x11 & data[1] == 0x06)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    if (data.Length == 3)
                        return true;
                    error = "返回DevcieCode长度错误，应为3 bytes";
                }
                else
                {
                    error = "返回DevcieCode类型错误，应为0x11 0x06";
                }
            }

            Log.WriteInfoLog(string.Format("GetDeviceCode Elapsed = {0}", watch.Elapsed.TotalMilliseconds));
            
            return false;
        }

        /// <summary>
        /// 烧录FireTV项目Playready key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVPlayready(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x00 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查FireTV项目Playready key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVPlayready(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01,0x00 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x00 && data[2] == 0x01)
                    return true;
                else
                {
                    error = "Playready return status fail,should be 0x02,0x00,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目Playready key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVPlayready(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x00 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x00)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Playready类型错误，应为0x04, 0x00";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 烧录FireTV项目LEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVLEK(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x02 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查FireTV项目LEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVLEK(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x02 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x02 && data[2] == 0x01)
                    return true;
                else
                {
                    error = "LEK return status fail,should be 0x02,0x02,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目LEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVLEK(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x02 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x02)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回LEK类型错误，应为0x04,0x02";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 烧录FireTV项目PEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVPEK(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x01 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查FireTV项目PEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVPEK(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x01 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x01 && data[2] == 0x01)
                    return true;
                else
                {
                    error = "PEK return status fail,should be 0x02,0x01,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目PEK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVPEK(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x01 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x01)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回PEK类型错误，应为0x04 0x01";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 烧录FireTV项目的DAK
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVDAK(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x0E }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 校验FireTV项目的DAK抄写状态;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVDAK(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x0E }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x0E && data[2] == 0x01)
                    return true;
                else
                {
                    error = "DAK return status fail,should be 0x02,0x0E,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 激活小米FireTV项目的FVP
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ActiveMiFireTVFVP(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC, 0x00, 0x0F }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 校验小米FireTV项目的FVP激活状态;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckMiFireTVFVP(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x0F }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x0F && data[2] == 0x01)
                    return true;
                else
                {
                    error = "FVP return status fail,should be 0x02,0x0F,0x01";
                    return false;
                }
            }
            else
                return false;
        }


        /// <summary>
        /// 烧录FireTV项目Hash key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVHashkey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x03 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查FireTV项目Hash key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVHashkey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x03 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x03 && data[2] == 0x01)
                    return true;
                else
                {
                    error = "Hashkey return status fail,should be 0x02,0x03,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目Hash key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVHashkey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x03 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x03)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Hashkey类型错误，应为0x04 0x03";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 烧录条码
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetBarcode(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x71 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 烧录PSN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVPSN(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC, 0x00, 0x05 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 烧录FireTV项目Youtube
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetFireTVYoutube(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x06 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 检查FireTV项目Youtube
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool CheckFireTVYoutube(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x06 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x06 && data[2] == 0x01)
                    return true;
                else
                {
                    error = "Youtube return status fail,should be 0x02,0x06,0x01";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取FireTV项目Youtube
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVYoutube(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x06 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x06)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Youtube类型错误，应为0x04 0x06";
                    return false;
                }

            }
            else
                return false;

        }

        /// <summary>
        /// 读取条码
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadBarcode(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x03 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x03)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回S/N类型错误，应为0x03";
                    return false;
                }

            }
            else
                return false;
        }

        /// <summary>
        /// 读取PSN
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadFireTVPSN(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            // 计算函数耗时;
            Stopwatch watch = new Stopwatch();
            watch.Start();
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x05 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x05)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    Log.WriteInfoLog(string.Format("Read PSN Elapsed={0}", watch.Elapsed.TotalMilliseconds));
                    return true;
                }
                else
                {
                    error = "返回PSN类型错误，应为0x04 0x05";
                }
            }
            
            return false;
        }

        /// <summary>
        /// 读取日本客户的ACAS ID;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadJapaneseACASID(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x15 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x15)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回ACASID类型错误，应为15";
                    return false;
                }
            }

            return false;
        }

        /// <summary>
        /// 读取EDID Pid;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadEDIDPid(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x09 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x09)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回EDID PID错误，应为0x04 0x07";
                }
            }

            return false;
        }

        /// <summary>
        /// 设置EDID Pid;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetEDIDPid(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC, 0x00, 0x09 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 读取EDID Mode Name;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool ReadEDIDModelName(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xBE }, new byte[] { 0x0E }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x0E)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "返回EDID Mode Name错误，应为01";
                }
            }
            
            return false;
        }

        /// <summary>
        /// 抄写EDID Mode Name;
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetEDIDModelName(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x99, 0x09 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 读取ACAS Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns>注意返回值为:md5xxxxx</returns>
        public static bool ReadACASKeyData(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x08 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x08)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回ACAS KEY DATA错误!";
                }
            }

            return false;
        }

        public static bool CheckACASKeyData(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x08 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x08 && data[2] == 0x01)
                {
                    return true;
                }
                else
                {
                    error = "检验ACAS KEY DATA错误，应为0x02 0x08 0x01";
                }
            }

            return false;
        }

        /// <summary>
        /// 设置ACAS Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetACASKeyData(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x08 }, param, false, false, out result, out data, out error, waitTime);
        }

        /// <summary>
        /// 读取ACAS Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns>注意返回值为:md5xxxxx</returns>
        public static bool ReadACASKeyTool(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x0A }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x0A)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回ACAS KEY TOOL 错误!";
                }
            }

            return false;
        }

        public static bool CheckACASKeyTool(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x0A }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x0A && data[2] == 0x01)
                {
                    return true;
                }
                else
                {
                    error = "检验ACAS KEY TOOL 错误，应为0x02 0x0A 0x01";
                }
            }

            return false;
        }

        /// <summary>
        /// 设置ACAS Key
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="param"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public static bool SetACASKeyTool(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x0A }, param, false, false, out result, out data, out error, waitTime);
        }

        #region 波兰工厂临时功能-抄写所有Key后执行Trigger和Check指令;
        public static bool TriggerDHA(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x96, 0x03 }, new byte[]{ 0x00 }, false, false, out result, out data, out error, waitTime);
        }

        public static bool CheckDHA(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0x9A }, new byte[] { 0x014 }, true, false, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x14 && data[1] == 0x01)
                {
                    data = data.Skip(1).Take(data.Length - 1).ToArray();
                    return true;
                }
                else
                {
                    error = "Check DHA失败，应为01";
                }
            }

            return false;
        }

        #endregion

        public static bool SetDolbyKey(SerialPort Comport, byte[] param, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            return SendcmdEx(Comport, new byte[] { 0xAA, 0xFE }, new byte[] { 0xFC, 0x00, 0x13 }, param, false, false, out result, out data, out error, waitTime);
        }

        public static bool CheckDolbyKey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x01, 0x13 }, true, false, out result, out data, out error, waitTime))
            {
                if (data.Length == 3 && data[0] == 0x02 && data[1] == 0x13 && data[2] == 0x01)
                {
                    return true;
                }
                else
                {
                    error = "检验 Dolby Key 错误，应为0x02 0x13 0x01";
                }
            }

            return false;
        }

        public static bool ReadDolbyKey(SerialPort Comport, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (SendcmdEx(Comport, new byte[] { 0xAA }, new byte[] { 0xFC }, new byte[] { 0x03, 0x13 }, true, true, out result, out data, out error, waitTime))
            {
                if (data[0] == 0x04 && data[1] == 0x13)
                {
                    data = data.Skip(2).Take(data.Length - 2).ToArray();
                    return true;
                }
                else
                {
                    error = "返回Dolby Key错误!";
                }
            }

            return false;
        }

        /// <summary>
        /// 通讯逻辑
        /// </summary>
        /// <param name="Comport"></param>
        /// <param name="CMDHead"></param>
        /// <param name="CMDID"></param>
        /// <param name="param"></param>
        /// <param name="receive2"></param>
        /// <param name="TwoLengthBit"></param>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        private static bool Sendcmd(SerialPort Comport, byte[] CMDHead,byte[] CMDID, byte[] param,bool receive2,bool TwoLengthBit,out byte[] result,out byte[] data,out string error,int waitTime)
        {
            result = new byte[20480];
            data = new byte[20480];
            error = "";
            Comport.ReadExisting();
            ArrayList command = new ArrayList();
            command.Add(CMDHead);
            int Wholelength = CMDHead.Length * 2 + param.Length + CMDID.Length + 2;
            if(CMDHead.Length==1)
                command.Add(new byte[1] { Convert.ToByte(Wholelength) } );
            else if(CMDHead.Length==2)
                command.Add(new byte[2] { Convert.ToByte(Wholelength/256), Convert.ToByte(Wholelength % 256) });
            else
            {
                error = "无法识别的命令头";
                return false;              
            }
            command.Add(CMDID);
            command.Add(param);
            ArrayList head1 = new ArrayList();
            byte[] head = new byte[Convert.ToUInt16(param.Length + CMDHead.Length * 2 + CMDID.Length)];
            foreach (byte[] b in command)
            {
                foreach (byte b2 in b)
                    head1.Add(b2);
            }
            head1.CopyTo(head);
            try
            {
                string CRC = CrcTest.Program.CalcCRC16(head);
                command.Add(SerialInit.HexToByte(CRC));
                string s = "";
                byte[] wdata = new byte[0] { };
                foreach (byte[] b in command)
                {
                    wdata= wdata.Concat(b).ToArray();                  
                }
                Comport.WriteTimeout = 3000;
                Comport.Write(wdata, 0, wdata.Length);
                s += SerialInit.ByteToHex(wdata);
                Log.WriteInfoLog("Write:" + s);
                bool mark = false;
                // 设置读超时;
                Comport.ReadTimeout = ReadTimeout;
                //delay(Comport, CMDID);//已有ReadTimeout了，这里多余;
                // ReadTimeout对ReadByte生效的话，所有ReadByte都会有超时响应，如果异常存在会导致更长的延时？
                while (true)
                {
                    if (Comport.ReadByte() == ACKhead[0])
                    {
                        if (Comport.ReadByte() == ACKhead[1])
                        {
                            int onebit = Comport.ReadByte();
                            if (onebit == ACKhead[2])
                            {
                                if (Comport.ReadByte() == ACKhead[3])
                                    if (Comport.ReadByte() == ACKhead[4])
                                    {
                                        for (int j = 0; j <= 4; j++)
                                        {
                                            result[j] = ACKhead[j];
                                        }
                                        mark = true;
                                        goto CheckTCL2Receive;
                                    }
                            }
                            else if (onebit == ACKhead2[2])
                            {
                                if (Comport.ReadByte() == ACKhead2[3])
                                    if (Comport.ReadByte() == ACKhead2[4])
                                    {
                                        for (int j = 0; j <= 4; j++)
                                        {
                                            result[j] = ACKhead2[2];
                                        }
                                        error = "命令错误或无法识别数据返回";
                                        Log.WriteInfoLog("Received ErrorACK:" + SerialInit.ByteToHex(ACKhead2) + "\r\n" + error);
                                        return false;
                                    }
                            }
                            else if (onebit == ACKhead3[2])
                            {
                                if (Comport.ReadByte() == ACKhead3[3])
                                    if (Comport.ReadByte() == ACKhead3[4])
                                    {
                                        for (int j = 0; j <= 4; j++)
                                        {
                                            result[j] = ACKhead3[2];
                                        }
                                        Log.WriteInfoLog("Received ErrorACK:" + SerialInit.ByteToHex(ACKhead3) + "\r\n" + error);
                                        error = "CRC16校验错误返回";
                                        return false;
                                    }
                            }
                        }
                    }
                    //delay(Comport, CMDID);
                }
                CheckTCL2Receive:
                if (receive2)
                {
                    //delay(Comport, CMDID, true);
                    if (mark)
                    {
                        string Br = "";
                        string Sr = "";
                        // 分2段2次返回，第2次同样要再次设置超时值;
                        Comport.ReadTimeout = ReadTimeout;
                        while (Comport.BytesToRead >= 0)
                        {
                            if (Comport.ReadByte() == ACKhead[0])
                            {
                                result[5] = ACKhead[0];
                                break;
                            }                           
                        }
                        if (!TwoLengthBit)
                        {
                            int k = Comport.ReadByte();
                            result[6] = (byte)k;
                            int timeout = 0;
                            while (Comport.BytesToRead < (k - 2) && timeout < 20)
                            {
                                Thread.Sleep(100);
                                timeout++;
                            }
                            Comport.Read(result, 7, k - 2);
                            Comport.ReadTimeout = 200;
                            Br = SerialInit.ByteToHex(result.Skip(8).Take(k - 5).ToArray());
                            Sr = Encoding.ASCII.GetString(result.Skip(8).Take(k - 5).ToArray());
                            data = result.Skip(8).Take(k - 5).ToArray();
                            Log.WriteInfoLog("Received:" + SerialInit.ByteToHex(result.Take(5 + k).ToArray()));
                        }                           
                        else
                        {
                            int mark1= Comport.ReadByte();
                            result[6] = (byte)mark1;
                            int k1 = Comport.ReadByte();
                            int k2 = Comport.ReadByte();
                            result[7] = (byte)k1;
                            result[8] = (byte)k2;
                            int k = k1 * 256 + k2;
                            int timeout = 0;
                            while (Comport.BytesToRead < (k - 4) && timeout < 20)
                            {
                                Thread.Sleep(100);
                                timeout++;
                            }
                            Comport.Read(result, 9, k - 4);
                            Comport.ReadTimeout = 200;
                            Br = SerialInit.ByteToHex(result.Skip(10).Take(k - 7).ToArray());
                            Sr = Encoding.ASCII.GetString(result.Skip(10).Take(k - 7).ToArray());
                            data = result.Skip(10).Take(k - 7).ToArray();
                            Log.WriteInfoLog("Received:" + SerialInit.ByteToHex(result.Take(5 + k).ToArray()));
                        }

                        Thread.Sleep(NextCommandWaitTime);
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    Log.WriteInfoLog("Received ACK:" + SerialInit.ByteToHex(result.Take(5).ToArray()));
                    Thread.Sleep(NextCommandWaitTime);
                    return true;
                }
            }  
            catch(Exception ex)
            {
                error = ex.Message;
                Log.WriteErrorLog("Serial Error:" + ex.Message);
                return false;
            }
        }

        private static bool SendcmdEx(SerialPort Comport, byte[] CMDHead, byte[] CMDID, byte[] param, bool receive2, bool TwoLengthBit, out byte[] result, out byte[] data, out string error, int waitTime)
        {
            if (!EnableRetry)
                return Sendcmd(Comport, CMDHead, CMDID, param, receive2, TwoLengthBit, out result, out data, out error, waitTime);

            int count = RetryCount;
            bool bRet = false;
            do
            {
                --count;
                Log.WriteInfoLog(string.Format("Retrying {0} time", RetryCount-count));
                bRet = Sendcmd(Comport, CMDHead, CMDID, param, receive2, TwoLengthBit, out result, out data, out error, waitTime);
                if (bRet) break;
            } while (count > 0);

            return bRet;
        }

        // 这个函数在receive2时,不具有超时有效性,不保证能读取成功;
        private static void delay(SerialPort Comport, byte[] CMDID, bool receive2 = false)
        {
            int l = 0;
            int num = SerialTimeout * 20;
            // CMD = 0x10表示EnterFactory指令;
            if (CMDID.Length == 1 && CMDID[0] == 0x10)
                num = 20;

            while (Comport.BytesToRead < 5 && l < num)
            {
                Thread.Sleep(SerialTimeout);
                l++;
            }
        }
    }
}
