From 487248120fb825e60e6709b25ba0383f88b36a3e Mon Sep 17 00:00:00 2001
From: Auto <onerow@163.com>
Date: Fri, 23 Apr 2021 15:25:39 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0AutoUI=E5=88=B0V0.032=20?=
 =?UTF-8?q?=E5=8A=A0=E5=85=A5=E4=B8=B2=E5=8F=A3=E9=80=9A=E4=BF=A1=E7=BB=84?=
 =?UTF-8?q?=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Assets/AutoUI/README.md                       |  12 +-
 Assets/AutoUI/Scripts/SerialPort.meta         |   8 +
 .../Scripts/SerialPort/AutoUISerialPort.cs    | 229 ++++++++++++++++++
 .../SerialPort/AutoUISerialPort.cs.meta       |  11 +
 Assets/StreamingAssets/Config/Config.txt      |   7 +-
 ProjectSettings/ProjectSettings.asset         |  23 +-
 README.md                                     |  12 +-
 7 files changed, 293 insertions(+), 9 deletions(-)
 create mode 100644 Assets/AutoUI/Scripts/SerialPort.meta
 create mode 100644 Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs
 create mode 100644 Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs.meta

diff --git a/Assets/AutoUI/README.md b/Assets/AutoUI/README.md
index cf4cdb3..1df7020 100644
--- a/Assets/AutoUI/README.md
+++ b/Assets/AutoUI/README.md
@@ -3,10 +3,9 @@
 ## 简介
    - **AutoUI框架**来组织**页面**切换的通用逻辑。
    - 只需定制每个**页面**的业务逻辑内容,将页面的切换交给框架来处理。
-   - *当前版本:* **AutoUI-V0.031**
+   - *当前版本:* **AutoUI-V0.032**
       - 更新内容:
-         - 加入**缓冲池**来优化打开和关闭面板时的性能开销。(打开过的页面会进入缓冲池。缓冲池会占用一定的显存和内存,来缓存页面加速页面加载。加入缓冲池能有效的解决页面切换时的性能开销以解决瞬时性能开销暴涨导致的程序崩溃。)
-            - 加入缓冲池不影响程序接口,按照事例场景中添加一个PanelBufferPoolParent,并将其拖拽到UIManager的PanelBufferPoolParent属性上即可。
+         - 加入**串口通信组件**
 
    - *Author:* [SmalBox](https://smalbox.top),*GitHub:* [GitHub/SmalBox](https://github.com/smalbox)
 
@@ -135,6 +134,13 @@
          - 获取本组件,注册 **SocketReceiveCallBack** 用来接收消息,用 **Send** 发送消息。
          - *注:本组件需要实用工具中的AutoUIUtilities.GetInfoForConfig来帮助获取ip端口配置文件。*
          - 在 StreamingAssets/Config/Config.txt 中 的 **UDPServerIP**, **UDPServerPort** 属性填写对应的ip和端口号。在程序中获取此组件注册回调来接收消息,调用Send可以发送消息(消息是ASCII编码,不要输入此编码外的字符,例如不要传输中文,使用ASCII表中的字符)。
+   - **串口组件**
+      - 串口组件位于 AutoUI/Scripts/SerialPort/ 中
+      - **AutoUISerialPort**
+         - 获取本组件,注册 **ComReceiveCallBack** 用来接收串口消息。
+         - *注:本组件需要实用工具中的AutoUIUtilities.GetInfoForConfig来帮助获取ComName配置文件。*
+         - 在 Inspector 中可配置串口名、波特率等串口配置,当开启 isConfigComName 选项后,可修改配置文件中的 COMName 为实际串口名。
+         - 组件可接收串口发来的消息,并且自动计算校验码解析命令(已做了错误命令过滤),在成功接收到完整命令后调用 ComReceiveCallBack 回调。
 
 ## 高级功能
    - **创建页面管理工具**
diff --git a/Assets/AutoUI/Scripts/SerialPort.meta b/Assets/AutoUI/Scripts/SerialPort.meta
new file mode 100644
index 0000000..4925793
--- /dev/null
+++ b/Assets/AutoUI/Scripts/SerialPort.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 40f62cbbb7a32ba438b40d8f8d7aa440
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs b/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs
new file mode 100644
index 0000000..71e798e
--- /dev/null
+++ b/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs
@@ -0,0 +1,229 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.IO.Ports;
+using System;
+using SmalBox.AutoUI;
+/// <summary>
+/// 串口通信组件,可在inspector中配置要连接的串口属性,在外部配置文件中修改串口号。
+/// 提供串口接收消息的回调 ComReceiveCallBack , 当收到串口消息时此组件会自动解析命令
+/// 解析到完整命令后会自动调用 ComReceiveCallBack 回调来执行处理命令。
+/// 通过配置 CMD_LENGTH 配置命令长度。
+/// </summary>
+public class AutoUISerialPort : MonoBehaviour
+{
+    public SerialPort sp;
+    public bool isConfigComName = false;
+    public string comName = "COM1";
+    public int baudRate = 9600;
+    public Parity parity = Parity.None;
+    public int dataBits = 8;
+    public StopBits stopBits = StopBits.One;
+
+    public int CMD_LENGTH = 9;
+
+    public Action<String> ComReceiveCallBack;
+
+    private Queue buffQueue;
+    private List<byte> cmd;
+
+    private void Awake()
+    {
+        sp = new SerialPort();
+        sp.ReadTimeout = 400;
+        sp.RtsEnable = true;
+        //sp.DataReceived += new SerialDataReceivedEventHandler(PortDataReceived); // unity 无法触发这个回调。手动调用read读取数据
+        //sp.ReceivedBytesThreshold = 1; // Unity 支持不全
+        InitSP();
+        OpenSP();
+        buffQueue = new Queue();
+        cmd = new List<byte>();
+        ComReceiveCallBack = (string str) => { };
+    }
+    private void Update()
+    {
+        if (sp != null && sp.IsOpen && sp.BytesToRead > 0)
+        {
+            try
+            {
+                byte[] dataBytes = new byte[sp.BytesToRead];
+                sp.Read(dataBytes, 0, sp.BytesToRead);
+                foreach (var item in dataBytes)
+                {
+                    print("收到:" + item.ToString("X2"));
+                    // 加入缓冲队列
+                    buffQueue.Enqueue(item);
+                }
+                // 解析缓冲队列
+                ParsedData();
+            }
+            catch (Exception ex)
+            {
+                print("输出错误:" + ex.ToString());
+            }
+        }
+        #region 数据测试
+        if (Input.GetKeyDown(KeyCode.Space))
+        {
+            if (sp != null && sp.IsOpen)
+            {
+                print("当前接受到的字符个数:" + sp.BytesToRead);
+            }
+        }
+        if (Input.GetKeyDown(KeyCode.A))
+        {
+            print("开始输出消息");
+            if (sp != null && sp.IsOpen && sp.BytesToRead > 0)
+            {
+                try
+                {
+                    byte[] dataBytes = new byte[9];
+                    sp.Read(dataBytes, 0, dataBytes.Length);
+                    foreach (var item in dataBytes)
+                    {
+                        print(item.ToString("X2"));
+                    }
+                }
+                catch (Exception ex)
+                {
+                    print("输出错误:" + ex.ToString());
+                }
+            }
+        }
+        if (Input.GetKeyDown(KeyCode.B))
+        {
+            //byte[] data = { 0x00, 0x5A, 0x58, 0x00, 0x07, 0x00, 0x00, 0x00, B9 };
+            byte[] data = new byte[9];
+            // 取字节的ascii数值 求和 ,转换成16进制,即使校验和。
+        }
+        if (Input.GetKeyDown(KeyCode.C))
+        {
+            print("数据队列长度:" + buffQueue.Count);
+        }
+
+        if (Input.GetKeyDown(KeyCode.Q))
+        {
+            print(sp.ReadLine());
+        }
+        if (Input.GetKeyDown(KeyCode.W))
+        {
+            //print(sp.Read());
+        }
+        if (Input.GetKeyDown(KeyCode.E))
+        {
+            print(sp.ReadByte());
+        }
+        #endregion
+    }
+
+    private void InitSP()
+    {
+        if (isConfigComName)
+        {
+            sp.PortName = AutoUIUtilities.GetInfoForConfig("COMName");
+        }else
+        {
+            sp.PortName = comName;
+        }
+        sp.BaudRate = 9600;
+        sp.Parity = Parity.None;
+        sp.DataBits = 8;
+        sp.StopBits = StopBits.One;
+    }
+    private void OpenSP()
+    {
+        try
+        {
+            print("打开串口" + sp.PortName);
+            sp.Open();
+        }
+        catch ( Exception ex)
+        {
+            print("打开出错,错误信息:" + ex.ToString());
+            return;
+        }
+    }
+    private void CloseSP()
+    {
+        try
+        {
+            print("关闭串口" + sp.PortName);
+            sp.Close();
+        }
+        catch ( Exception ex)
+        {
+            print("关闭出错,错误信息:" + ex.ToString());
+            return;
+        }
+    }
+    
+    // 解析数据
+    private void ParsedData()
+    {
+        int emptyData;
+        // 将缓冲区数据填充命令列表
+
+        // 查看命令列表当前字节数,与命令长度对比计算有几个空位字节
+        emptyData = CMD_LENGTH - cmd.Count;
+        // 向空位填充字节,填充时通过缓冲区剩余个数控制数组别越界
+        for (int i = 0; i < emptyData; i++)
+        {
+            if (buffQueue.Count > 0)
+            {
+                cmd.Add((byte)buffQueue.Dequeue());
+            }
+        }
+        // 填充后再次查看字节数,当空余字节数为0时,计算校验和对比
+        emptyData = CMD_LENGTH - cmd.Count;
+        if (emptyData == 0)
+        {
+            if (cmd[CMD_LENGTH - 1] == CalculateChecksum()) // 当校验和正确时
+            {
+                // 对比成功则执行命令
+                ExeCmd();
+            } else
+            {
+                // 对比失败查看缓冲区数据是否为空,不为空则向后移动命令列表一个位置继续判断
+                if (buffQueue.Count > 0)
+                {
+                    cmd.RemoveAt(0);
+                    ParsedData();
+                }
+            }
+        }
+    }
+    // 执行命令
+    private void ExeCmd()
+    {
+        // 判断命令 列表长度 和 校验和 是否符合要求
+        if (cmd.Count < CMD_LENGTH || cmd[CMD_LENGTH - 1] != CalculateChecksum())
+            return;
+        // 解析地址,根据地址判断哪个内容播放
+        // 将命令字节列表转化成字符串对比
+        string cmdStr = "";
+        ComReceiveCallBack?.Invoke(cmdStr);
+        // 命令执行完毕,清空命令列表
+        cmd.Clear();
+    }
+    // 计算校验和
+    private byte CalculateChecksum()
+    {
+        if (cmd.Count < CMD_LENGTH)
+            return 0x00;
+        byte sum = 0x00;
+        for (int i = 0; i < CMD_LENGTH - 1; i++)
+        {
+            sum += cmd[i];
+        }
+        return sum;
+    }
+
+    private void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
+    {
+        print("收到串口" + sp.PortName + "的消息:");
+    }
+    private void OnDestroy()
+    {
+        CloseSP();
+    }
+}
diff --git a/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs.meta b/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs.meta
new file mode 100644
index 0000000..b3e6d76
--- /dev/null
+++ b/Assets/AutoUI/Scripts/SerialPort/AutoUISerialPort.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 16b33159db63e4641819e7014e26c428
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/StreamingAssets/Config/Config.txt b/Assets/StreamingAssets/Config/Config.txt
index e0a3300..2644496 100644
--- a/Assets/StreamingAssets/Config/Config.txt
+++ b/Assets/StreamingAssets/Config/Config.txt
@@ -2,4 +2,9 @@
 ##UDPServerIP##:127.0.0.1
 ##UDPServerPort##:55666
 ##LocalUDPServerIP##:127.0.0.1
-##LocalUDPServerPort##:22333
\ No newline at end of file
+##LocalUDPServerPort##:22333
+##addr1##:005A58002000FF00D1
+##addr2##:005A580020FBFF00CC
+##addr3##:005A580020F7FF00C8
+##addr4##:005A580020EFFF00C0
+##COMName##:COM2
\ No newline at end of file
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 01f9d24..a5f3979 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -3,7 +3,7 @@
 --- !u!129 &1
 PlayerSettings:
   m_ObjectHideFlags: 0
-  serializedVersion: 15
+  serializedVersion: 18
   productGUID: 66f99a8b96074954bb60304390c35e23
   AndroidProfiler: 0
   AndroidFilterTouchesWhenObscured: 0
@@ -41,6 +41,12 @@ PlayerSettings:
     height: 1
   m_SplashScreenLogos: []
   m_VirtualRealitySplashScreen: {fileID: 0}
+  m_ShowUnitySplashAds: 0
+  m_AdsAndroidGameId: 
+  m_AdsIosGameId: 
+  m_ShowSplashAdsSlogan: 0
+  m_SloganImage: {fileID: 0}
+  m_SloganHeight: 150
   m_HolographicTrackingLossScreen: {fileID: 0}
   defaultScreenWidth: 1024
   defaultScreenHeight: 768
@@ -52,8 +58,8 @@ PlayerSettings:
   m_StackTraceTypes: 010000000100000001000000010000000100000001000000
   iosShowActivityIndicatorOnLoading: -1
   androidShowActivityIndicatorOnLoading: -1
-  iosAppInBackgroundBehavior: 0
   displayResolutionDialog: 1
+  iosUseCustomAppBackgroundBehavior: 0
   iosAllowHTTPDownload: 1
   allowedAutorotateToPortrait: 1
   allowedAutorotateToPortraitUpsideDown: 1
@@ -104,6 +110,7 @@ PlayerSettings:
   xboxOneMonoLoggingLevel: 0
   xboxOneLoggingLevel: 1
   xboxOneDisableEsram: 0
+  xboxOneEnableTypeOptimization: 0
   xboxOnePresentImmediateThreshold: 0
   switchQueueCommandMemory: 0
   switchQueueControlMemory: 16384
@@ -111,7 +118,10 @@ PlayerSettings:
   switchNVNShaderPoolsGranularity: 33554432
   switchNVNDefaultPoolsGranularity: 16777216
   switchNVNOtherPoolsGranularity: 16777216
+  switchNVNMaxPublicTextureIDCount: 0
+  switchNVNMaxPublicSamplerIDCount: 0
   vulkanEnableSetSRGBWrite: 0
+  useSecurityBuild: 0
   m_SupportedAspectRatios:
     4:3: 1
     5:4: 1
@@ -143,6 +153,9 @@ PlayerSettings:
     oculus:
       sharedDepthBuffer: 1
       dashSupport: 1
+      lowOverheadMode: 0
+      protectedContext: 0
+      v2Signing: 0
     enable360StereoCapture: 0
   protectGraphicsMemory: 0
   enableFrameTimingStats: 0
@@ -228,6 +241,7 @@ PlayerSettings:
   metalEditorSupport: 1
   metalAPIValidation: 1
   iOSRenderExtraFrameOnPause: 0
+  iosCopyPluginsCodeInsteadOfSymlink: 0
   appleDeveloperTeamID: 
   iOSManualSigningProvisioningProfileID: 
   tvOSManualSigningProvisioningProfileID: 
@@ -275,6 +289,7 @@ PlayerSettings:
   - m_BuildTarget: WebGL
     m_StaticBatching: 0
     m_DynamicBatching: 0
+  m_BuildTargetEncrypting: []
   m_BuildTargetGraphicsAPIs:
   - m_BuildTarget: AndroidPlayer
     m_APIs: 0b00000008000000
@@ -412,6 +427,7 @@ PlayerSettings:
   switchRatingsInt_9: 0
   switchRatingsInt_10: 0
   switchRatingsInt_11: 0
+  switchRatingsInt_12: 0
   switchLocalCommunicationIds_0: 
   switchLocalCommunicationIds_1: 
   switchLocalCommunicationIds_2: 
@@ -468,6 +484,7 @@ PlayerSettings:
   ps4ShareFilePath: 
   ps4ShareOverlayImagePath: 
   ps4PrivacyGuardImagePath: 
+  ps4ExtraSceSysFile: 
   ps4NPtitleDatPath: 
   ps4RemotePlayKeyAssignment: -1
   ps4RemotePlayKeyMappingDir: 
@@ -508,6 +525,8 @@ PlayerSettings:
   ps4disableAutoHideSplash: 0
   ps4videoRecordingFeaturesUsed: 0
   ps4contentSearchFeaturesUsed: 0
+  ps4CompatibilityPS5: 0
+  ps4GPU800MHz: 1
   ps4attribEyeToEyeDistanceSettingVR: 0
   ps4IncludedModules: []
   monoEnv: 
diff --git a/README.md b/README.md
index cf4cdb3..1df7020 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,9 @@
 ## 简介
    - **AutoUI框架**来组织**页面**切换的通用逻辑。
    - 只需定制每个**页面**的业务逻辑内容,将页面的切换交给框架来处理。
-   - *当前版本:* **AutoUI-V0.031**
+   - *当前版本:* **AutoUI-V0.032**
       - 更新内容:
-         - 加入**缓冲池**来优化打开和关闭面板时的性能开销。(打开过的页面会进入缓冲池。缓冲池会占用一定的显存和内存,来缓存页面加速页面加载。加入缓冲池能有效的解决页面切换时的性能开销以解决瞬时性能开销暴涨导致的程序崩溃。)
-            - 加入缓冲池不影响程序接口,按照事例场景中添加一个PanelBufferPoolParent,并将其拖拽到UIManager的PanelBufferPoolParent属性上即可。
+         - 加入**串口通信组件**
 
    - *Author:* [SmalBox](https://smalbox.top),*GitHub:* [GitHub/SmalBox](https://github.com/smalbox)
 
@@ -135,6 +134,13 @@
          - 获取本组件,注册 **SocketReceiveCallBack** 用来接收消息,用 **Send** 发送消息。
          - *注:本组件需要实用工具中的AutoUIUtilities.GetInfoForConfig来帮助获取ip端口配置文件。*
          - 在 StreamingAssets/Config/Config.txt 中 的 **UDPServerIP**, **UDPServerPort** 属性填写对应的ip和端口号。在程序中获取此组件注册回调来接收消息,调用Send可以发送消息(消息是ASCII编码,不要输入此编码外的字符,例如不要传输中文,使用ASCII表中的字符)。
+   - **串口组件**
+      - 串口组件位于 AutoUI/Scripts/SerialPort/ 中
+      - **AutoUISerialPort**
+         - 获取本组件,注册 **ComReceiveCallBack** 用来接收串口消息。
+         - *注:本组件需要实用工具中的AutoUIUtilities.GetInfoForConfig来帮助获取ComName配置文件。*
+         - 在 Inspector 中可配置串口名、波特率等串口配置,当开启 isConfigComName 选项后,可修改配置文件中的 COMName 为实际串口名。
+         - 组件可接收串口发来的消息,并且自动计算校验码解析命令(已做了错误命令过滤),在成功接收到完整命令后调用 ComReceiveCallBack 回调。
 
 ## 高级功能
    - **创建页面管理工具**