lvjincheng 3 年之前
父节点
当前提交
2f05307b53

+ 0 - 0
代码备份/2022-7-15/AimHandler.cs → 代码备份/2022-7-15/修改前/AimHandler.cs


+ 484 - 0
代码备份/2022-7-15/修改前/BluetoothAim.cs

@@ -0,0 +1,484 @@
+using ArduinoBluetoothAPI;
+using System;
+using UnityEngine;
+using System.Collections.Generic;
+using UnityEngine.UI;
+using DG.Tweening;
+using UnityEngine.SceneManagement;
+/* 蓝牙瞄准模块 */
+public class BluetoothAim : MonoBehaviour
+{
+    BluetoothHelper bluetoothHelper;
+    BluetoothHelperCharacteristic characteristicWrite;
+    BluetoothHelperService bluetoothService;
+    string targetDeviceName = "Bbow_20210501";
+    string deviceName = "";
+    bool canConnect = true;
+    [SerializeField] Text textUI;
+    public BluetoothStatusEnum status = BluetoothStatusEnum.Connect;
+    public bool hasData = false;
+    public long hasDataTime;
+    public static bool scanLock = false; //防止同时扫描冲突
+    public static BluetoothAim ins;
+
+    void Start()
+    {
+        ins = this;
+        InitAutoDormancy();
+
+#if UNITY_STANDALONE_WIN
+        new GameObject("BleUDP").AddComponent<BleUDP>();
+#endif
+    }
+
+    void OnDestroy()
+    {
+        DisconnectBleHelper();
+    }
+
+    private bool userDoConnect = false;
+    private bool doConnect = false;
+    public void DoConnect()
+    {
+        if (status == BluetoothStatusEnum.Connect)
+        {
+            userDoConnect = true;
+            doConnect = true;
+            SetStatus(BluetoothStatusEnum.Connecting);
+        }
+        else if (status == BluetoothStatusEnum.ConnectSuccess)
+        {
+            userDoConnect = false;
+            doConnect = false;
+            OnDisconnect();
+#if UNITY_ANDROID
+            DisconnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+            BleUDP.ins.Disconnect();
+#endif
+        }
+    }
+
+    void OnDisconnect()
+    {
+        hasData = false;
+        canConnect = true;
+        SetStatus(BluetoothStatusEnum.ConnectFail);
+        BowCamera.isTouchMode = true;
+        DestroyWhenDisconenct();
+    }
+
+    void Update()
+    {
+        if (userDoConnect && status == BluetoothStatusEnum.Connect)
+        {
+            DoConnect();
+        }
+        if (doConnect) Connect();
+    }
+
+    void SetStatus(BluetoothStatusEnum statusValue)
+    {
+        status = statusValue;
+        if (status == BluetoothStatusEnum.ConnectFail)
+        {
+            Sequence sequence = DOTween.Sequence();
+            sequence.AppendInterval(2f);
+            sequence.AppendCallback(delegate ()
+            {
+                if (status == BluetoothStatusEnum.ConnectFail)
+                {
+                    status = BluetoothStatusEnum.Connect;
+                }
+            });
+            sequence.SetUpdate(true);
+            DeviceReconnectView.Show();
+        }
+    }
+
+    void DisconnectBleHelper()
+    {
+        if (bluetoothHelper != null) bluetoothHelper.Disconnect();
+    }
+
+    void Connect()
+    {
+        if (BluetoothShoot.scanLock)
+        {
+            return;
+        }
+        if (!canConnect)
+        {
+            return;
+        }
+        doConnect = false;
+        scanLock = true;
+        canConnect = false;
+        SetStatus(BluetoothStatusEnum.Connecting);
+#if UNITY_ANDROID
+        ConnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+        ConnectBleByUDP();
+#endif
+    }
+
+    void ConnectBleHelper()
+    {
+        try
+        {
+            BluetoothHelper.BLE = true;
+            bluetoothHelper = BluetoothHelper.GetNewInstance();
+
+            bluetoothHelper.OnConnected += (BluetoothHelper helper) =>
+            {
+                Log("连接成功\n" + helper.getDeviceName());
+                SetStatus(BluetoothStatusEnum.ConnectSuccess);
+                BowCamera.isTouchMode = false;
+                foreach (BluetoothHelperService service in helper.getGattServices())
+                {
+
+                    if (service.getName().ToLower().StartsWith("0000fff0"))
+                    {
+                        bluetoothService = service;
+
+                        foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics())
+                        {
+                            if (characteristic.getName().ToLower().StartsWith("0000fff2"))
+                            {
+                                characteristicWrite = characteristic;
+                            }
+                            else if (characteristic.getName().ToLower().StartsWith("0000fff1"))
+                            {
+
+                                BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName());
+                                ch.setService(bluetoothService.getName());
+                                bluetoothHelper.Subscribe(ch);
+                            }
+                        }
+                    }
+                }
+                // CallDelay(1, OpenInfrared);
+                // CallDelay(2, OpenReceiveData);
+                // CallDelay(3, RequestBattery);
+                CallDelay(2, () =>
+                {
+                    if (status != BluetoothStatusEnum.ConnectSuccess) return;
+                    InitWhenConenct();
+                });
+            };
+            bluetoothHelper.OnConnectionFailed += (BluetoothHelper helper) =>
+            {
+                Log("连接失败\n" + helper.getDeviceName());
+                OnDisconnect();
+            };
+            bluetoothHelper.OnCharacteristicChanged += (helper, value, characteristic) =>
+            {
+                if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
+                hasData = true;
+                byte[] bytes = value;
+                // Log(String.Join(",", bytes));
+                BluetoothClient.UploadData(0, bytes);
+                if (AimHandler.ins)
+                {
+                    AimHandler.ins.OnDataReceived(bytes);
+                }
+            };
+            int scanCount = 0;
+            bluetoothHelper.OnScanEnded += (BluetoothHelper helper, LinkedList<BluetoothDevice> nearbyDevices) =>
+            {
+                scanLock = false;
+                foreach (BluetoothDevice device in nearbyDevices)
+                {
+                    if (device.DeviceName == targetDeviceName)
+                    {
+                        deviceName = device.DeviceName;
+                        bluetoothHelper.setDeviceName(deviceName);
+                        bluetoothHelper.Connect();
+                        Log("发现设备\n" + device.DeviceName);
+                        return;
+                    }
+                }
+                if (scanCount < 3)
+                { //如果没扫描到,则重新扫描,达到延迟提示失败的效果
+                    scanCount++;
+                    scanLock = true;
+                    bluetoothHelper.ScanNearbyDevices();
+                }
+                else
+                {
+                    canConnect = true;
+                    Log("没有发现设备");
+                    SetStatus(BluetoothStatusEnum.ConnectFail);
+                }
+            };
+
+            bluetoothHelper.ScanNearbyDevices();
+            Log("正在扫描设备");
+        }
+        catch (Exception e)
+        {
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
+            canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
+            Log("请打开蓝牙");
+        }
+    }
+
+    void ConnectBleByUDP()
+    {
+        try
+        {
+            BleUDP.ins.OnConnected = () =>
+            {
+                Log("连接成功\n" + deviceName);
+                SetStatus(BluetoothStatusEnum.ConnectSuccess);
+                BowCamera.isTouchMode = false;
+                InitWhenConenct();
+            };
+            BleUDP.ins.OnConnectionFailed = () =>
+            {
+                Log("连接失败\n" + deviceName);
+                OnDisconnect();
+            };
+            BleUDP.ins.OnCharacteristicChanged = (byte[] value) =>
+            {
+                if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
+                hasData = true;
+                byte[] bytes = value;
+                // Log(String.Join(",", bytes));
+                BluetoothClient.UploadData(0, bytes);
+                if (AimHandler.ins)
+                {
+                    AimHandler.ins.OnDataReceived(bytes);
+                }
+            };
+            BleUDP.ins.OnScanEnded = () =>
+            {
+                scanLock = false;
+                deviceName = targetDeviceName;
+                BleUDP.ins.Connect();
+                Log("发现设备\n" + deviceName);
+            };
+
+            BleUDP.ins.ScanNearbyDevices();
+        }
+        catch (Exception e)
+        {
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
+            canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
+        }
+    }
+
+    #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来
+    class CmdToSend
+    {
+        public string[] cmds;
+        public Action onComplete;
+        public Func<bool> canDo;
+        public CmdToSend(string[] cmds, Action onComplete, Func<bool> canDo)
+        {
+            this.cmds = cmds;
+            this.onComplete = onComplete;
+            this.canDo = canDo;
+        }
+    }
+    Queue<CmdToSend> cmdWaitingList = new Queue<CmdToSend>();
+    bool isSendCmdLocked = false;
+    bool canAutoDormancy = false;
+    bool isStartUp = false;
+    JC.CS.CountLocker needModularAwake = new JC.CS.CountLocker();
+    void CheckAndStartUp()
+    {
+        if (needModularAwake.IsLocked())
+        {
+            StartUp();
+        }
+        else
+        {
+            Dormancy();
+        }
+    }
+    void InitAutoDormancy()
+    {
+        // GlobalEventCenter.ins.onGameSceneLoad += () => { 
+        //     needModularAwake.Lock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onGameSceneDestroy += () => { 
+        //     needModularAwake.Unlock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        //暂时关闭自动休眠,默认是需要模块保持激活
+        needModularAwake.Lock();
+    }
+    void InitWhenConenct()
+    {
+        canAutoDormancy = true;
+        List<string> cmds = new List<string>();
+        cmds.Add("b"); //确保开启stm32
+        cmds.Add("b"); //获取初始电量
+        cmds.Add("1"); //开启发送逻辑
+        Action onComplete = null;
+        if (needModularAwake.IsLocked())
+        {
+            cmds.Add("w"); //红外灯开启
+            cmds.Add("3"); //九轴开启
+            onComplete = () =>
+            {
+                isStartUp = true;
+            };
+        }
+        else
+        {
+            cmds.Add("s"); //红外灯关闭
+            cmds.Add("S"); //Stm32关闭
+            cmds.Add("4"); //九轴关闭
+            onComplete = () =>
+            {
+                isStartUp = false;
+            };
+        }
+        SendCDM(null, onComplete, cmds.ToArray());
+    }
+    void DestroyWhenDisconenct()
+    {
+        canAutoDormancy = false;
+        sendCMD_CheckAndDoStop(null);
+
+    }
+    //启动
+    void StartUp()
+    {
+        SendCDM(() =>
+        {
+            return !isStartUp;
+        }, () =>
+        {
+            isStartUp = true;
+        }, "b", "w", "3");
+    }
+    //休眠
+    void Dormancy()
+    {
+        SendCDM(() =>
+        {
+            return isStartUp;
+        }, () =>
+        {
+            isStartUp = false;
+        }, "4", "s", "S");
+    }
+    void SendCDM(Func<bool> canDo, Action onComplete, params string[] cmds)
+    {
+        CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo);
+        if (isSendCmdLocked)
+        {
+            cmdWaitingList.Enqueue(cmdToSend);
+            return;
+        }
+        sendCMD_NotCheck(cmdToSend);
+    }
+    void sendCMD_NotCheck(CmdToSend cmdToSend)
+    {
+        if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke())
+        {
+            sendCMD_CheckNext();
+            return;
+        }
+        isSendCmdLocked = true;
+        Sequence sequence = DOTween.Sequence();
+        sequence.PrependInterval(0.3f);
+        foreach (var cmd in cmdToSend.cmds)
+        {
+            sequence.AppendCallback(() =>
+            {
+                bool stopped = sendCMD_CheckAndDoStop(sequence);
+                if (!stopped) WriteData(cmd);
+            });
+            sequence.AppendInterval(0.5f);
+        }
+        sequence.AppendCallback(() =>
+        {
+            bool stopped = sendCMD_CheckAndDoStop(sequence);
+            if (!stopped)
+            {
+                isSendCmdLocked = false;
+                cmdToSend.onComplete?.Invoke();
+                sendCMD_CheckNext();
+            }
+        });
+        sequence.SetUpdate(true);
+    }
+    void sendCMD_CheckNext()
+    {
+        if (cmdWaitingList.Count <= 0) return;
+        CmdToSend cmdToSend = cmdWaitingList.Dequeue();
+        sendCMD_NotCheck(cmdToSend);
+    }
+    bool sendCMD_CheckAndDoStop(Sequence sequence)
+    {
+        if (canAutoDormancy) return false;
+        isStartUp = false;
+        isSendCmdLocked = false;
+        cmdWaitingList.Clear();
+        if (sequence != null) sequence.Kill();
+        return true;
+    }
+    #endregion
+
+    public void RequestBattery()
+    {
+        if (!isStartUp) return;
+        if (isSendCmdLocked) return;
+        WriteData("b");
+    }
+
+    public void ReplyInfraredShoot()
+    {
+        if (isSendCmdLocked) return;
+        WriteData("I");
+    }
+
+    void CallDelay(float delayTime, TweenCallback callback)
+    {
+        Sequence sequence = DOTween.Sequence();
+        sequence.PrependInterval(delayTime).AppendCallback(callback);
+        sequence.SetUpdate(true);
+    }
+
+    public void WriteData(string data)
+    {
+#if UNITY_ANDROID
+        if (DebugDeviceCMD.ins) DebugDeviceCMD.ins.ShowCMD(data);
+        BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName());
+        ch.setService(bluetoothService.getName());
+        bluetoothHelper.WriteCharacteristic(ch, data);
+#elif UNITY_STANDALONE_WIN
+        BleUDP.ins.SendMsg(data);
+#endif
+
+    }
+
+    void Log(string text)
+    {
+        if (textUI)
+        {
+            textUI.text = text;
+        }
+    }
+}

+ 369 - 0
代码备份/2022-7-15/修改后-新硬件1和2/AimHandler.cs

@@ -0,0 +1,369 @@
+using System;
+using UnityEngine;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.UI;
+using Newtonsoft.Json;
+/* 瞄准处理器 */
+public class AimHandler : MonoBehaviour
+{
+    Transform controlObj {
+        get {
+            if (CameraToLook.ins) {
+                return CameraToLook.ins.transform;
+            }
+            return null;
+        }
+    }
+    [SerializeField] Button SetIdentityButton;
+    [SerializeField] Button MagCalibrationButton;
+    [SerializeField] Button GyrCalibrationButton;
+    [SerializeField] Text MagScaleText;
+    [SerializeField] Text GyrScaleText;
+
+    //椭圆对象
+    [SerializeField] Ellipse ellipseScript;
+    [SerializeField] GameObject AccObj;
+    [SerializeField] GameObject MagObj;
+
+    [SerializeField] GameObject AccMesh;
+    [SerializeField] GameObject GryMesh;
+    [SerializeField] GameObject MagMesh;
+    [SerializeField] GameObject AMesh;
+    [SerializeField] Transform DebugTexts;
+    [SerializeField] Transform DrawImage;
+    
+    long TimeGap = default;
+    Vector3 Acc = default;
+    Vector3 Gyr = default;
+    Vector3 Mag = default;
+    o09Axis _9Axis = new o09Axis();
+
+    Vector3 cMaxVector = new Vector3(0,0,0);
+    Vector3 cMinVector = new Vector3(0, 0, 0);
+
+    public o0MagneticCalibraterEllipsoidFitting MagCalibrater;
+    o0GyrCalibrater GyrCalibrater;
+
+    //陀螺仪校准进度记录
+    public int gyrCalibrateCompleteCount = 0;
+    public int gyrCalibrateTotalCount = 300;
+
+    long msOld = 0;
+
+    public static AimHandler ins; 
+
+    void Start()
+    {
+        ins = this;
+        BluetoothDispatcher.aim = OnDataReceived;
+
+        //初始化
+        _9Axis.LoadIdentity();
+
+        _9Axis.AccMesh = AccMesh;
+        _9Axis.GryMesh = GryMesh;
+        _9Axis.MagMesh = MagMesh;
+
+        for (var i = 0; i < 9; ++i)
+        {
+            _9Axis.Tester.Add(DrawImage.Find(i.ToString()).gameObject.AddComponent<o0UIRawImageTester>());
+        }
+
+        for (var i = 0; i < 15; ++i)
+        {
+            _9Axis.TextTester.Add(DebugTexts.transform.Find("Text" + i.ToString()).gameObject.GetComponent<Text>());
+        }
+
+        if (SetIdentityButton) 
+        {
+            SetIdentityButton.onClick.AddListener(DoIdentity);
+        }
+        
+        try 
+        {  
+            string magDataStr = PlayerPrefs.GetString("o0MagneticCalibrater");
+            MagCalibrater = JsonConvert.DeserializeObject<o0MagneticCalibraterEllipsoidFitting>(magDataStr);
+        } 
+        catch(Exception) 
+        {
+            MagCalibrater = null;
+        }
+
+        if (MagCalibrater == null) 
+        {
+            MagCalibrater = new o0MagneticCalibraterEllipsoidFitting();
+        }
+        if (MagCalibrationButton)
+        {
+            MagCalibrationButton.onClick.AddListener(delegate {
+                CalibrateMag(!MagCalibrater.Calibration);
+            });
+        }
+
+        try {
+            string gyrDataStr = PlayerPrefs.GetString("o0GyrCalibrater");
+            GyrCalibrater = JsonConvert.DeserializeObject<o0GyrCalibrater>(gyrDataStr);
+            if (GyrCalibrater._Average != Vector3.zero) GyrScaleText.text = "已校准";
+        } catch(Exception) {
+            GyrCalibrater = null;
+        }
+        if (GyrCalibrater == null) 
+        {
+            GyrCalibrater = new o0GyrCalibrater();
+        }
+        if (GyrCalibrationButton)
+        {
+            GyrCalibrationButton.onClick.AddListener(delegate() {
+                CalibrateGyr(!GyrCalibrater.Calibration);
+            });
+        }
+    }
+
+    public void CalibrateGyr(bool calibration) {
+        try {
+            GyrCalibrater.Calibration = calibration;
+            if (calibration)
+            {
+                GyrCalibrationButton.GetComponentInChildren<Text>().text = "停止陀螺仪校准";
+            }
+            else
+            {
+                GyrCalibrationButton.GetComponentInChildren<Text>().text = "开始陀螺仪校准";
+                PlayerPrefs.SetString("o0GyrCalibrater", JsonConvert.SerializeObject(GyrCalibrater));            
+            }
+        } catch (Exception e) { Debug.LogError(e.Message); }
+    }
+
+     public void CalibrateMag(bool calibration) {
+        try {
+            if (calibration)
+            {
+                MagCalibrater.Calibration = calibration;
+                MagCalibrationButton.GetComponentInChildren<Text>().text = "停止地磁计校准";
+                this.cMaxVector = new Vector3(0, 0, 0);
+                this.cMinVector = new Vector3(0, 0, 0);
+                this.ellipseScript.ellipseTran.gameObject.SetActive(false);
+            }
+            else
+            {
+                List<Vector3> list = MagCalibrater.getRecords();
+                //停止校准时候,看看数组值
+                float maxDistance = 0f,ratio = 1f;
+                Vector3 maxVector3 = new Vector3(0,0,0);
+                List<Vector3> endRecords = new List<Vector3>();
+                foreach (Vector3 i in list)
+                {
+                    Vector3 v = i - MagCalibrater._Center;
+                    if (Math.Abs(v.magnitude) > maxDistance)
+                    {
+                        maxVector3 = v;
+                        maxDistance = Math.Abs(v.magnitude);
+                        if(Math.Abs(v.magnitude) < Math.Abs(MagCalibrater._Radius.magnitude))
+                            ratio = Math.Abs(v.magnitude) / Math.Abs(MagCalibrater._Radius.magnitude);
+                        else
+                            ratio = Math.Abs(MagCalibrater._Radius.magnitude) / Math.Abs(v.magnitude);
+                    }
+                }
+                Debug.LogWarning(maxDistance + " == " + Math.Abs(MagCalibrater._Radius.magnitude) + " == " + MagCalibrater._Radius + " = " + maxVector3);
+                //如果比例效果不理想。可以设置为ratio=0.5f 
+                foreach (Vector3 i in list)
+                {
+                    //- MagCalibrater._Center
+                    Vector3 v = i ;
+                    v *= ratio;
+                    if(endRecords.Count>3000)
+                    {
+                        endRecords.RemoveAt(0);
+                    }
+                    endRecords.Add(v);
+                }
+                this.ellipseScript.ClearAndUpdatePointArray();
+                this.ellipseScript.DrawPointCloud(endRecords);
+
+                MagCalibrater.Calibration = calibration;
+
+                this.ellipseScript.ellipseTran.gameObject.SetActive(true);
+                //绘制椭圆形
+                if (MagCalibrater._Radius != this.ellipseScript.ellipseTran.localScale)
+                {
+                    this.ellipseScript.setEllipseLocalScaleAndCenter(MagCalibrater._Radius, MagCalibrater._Center* ratio);
+                    //设置绘制图像相机的对应位置
+                    this.ellipseScript.setCameraPos(MagCalibrater._Center * 0.5f);
+                }
+
+                MagCalibrationButton.GetComponentInChildren<Text>().text = "开始地磁计校准";
+                PlayerPrefs.SetString("o0MagneticCalibrater", JsonConvert.SerializeObject(MagCalibrater));
+            }
+        } catch (Exception e) { Debug.LogError(e.Message); }
+    }
+
+    //转换读取的数据,无符号->有符号
+    float TwoByteToFloat(byte b1, byte b2) 
+    {
+        ushort twoByte = (ushort) (b1 * 256 + b2);
+        short shortNum = (short) twoByte;
+        return (float) shortNum; 
+    }
+
+    public void OnDataReceived(byte[] bytes)
+    {
+        // Debug.Log("瞄准模块数据长度" + bytes.Length);
+        if (bytes.Length != 27)
+        {
+            if (bytes.Length == 2) {
+                if (bytes[0] == 0x66 && bytes[1] == 0x31) {
+                    if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+                        //鼠标居中
+                        SB_EventSystem.ins.MakeMouseToScreenCenter(); 
+                    }
+                    //视角回正
+                    DoIdentity();
+                } else if (bytes[0] == 0x66 && bytes[1] == 0x32) {
+                    if (SB_EventSystem.ins) {
+                        //唤起/隐藏虚拟鼠标
+                        SB_EventSystem.ins.AwakenSimulateMouse(); 
+                    }
+                } else if (bytes[1] == 10) {
+                    //显示电量
+                    DeviceBatteryView.ins.RenderBattery(1, bytes[0]); 
+                }
+            } else if (bytes[0] == 0x5b) {
+                if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+                    //点击鼠标
+                    SB_EventSystem.ins.ClickMouse(); 
+                } else {
+                    //红外射击检测
+                    ShootCheck.ins.ShootByInfrared(bytes); 
+                }
+            }
+            return;
+        }
+        if (bytes[7] == 0 && bytes[8] == 0 && bytes[9] == 0 && bytes[10] == 0 && bytes[11] == 0 && bytes[12] == 0)
+            return;
+        if (bytes[19] == 0 && bytes[20] == 0 && bytes[21] == 0 && bytes[22] == 0 && bytes[23] == 0 && bytes[24] == 0)
+            return;
+
+        float ax = TwoByteToFloat(bytes[7], bytes[8]);
+        float ay = TwoByteToFloat(bytes[9], bytes[10]);
+        float az = TwoByteToFloat(bytes[11], bytes[12]);
+
+        float roll = TwoByteToFloat(bytes[13], bytes[14]);
+        float pitch = TwoByteToFloat(bytes[15], bytes[16]);
+        float yaw = TwoByteToFloat(bytes[17], bytes[18]);
+
+        float x = TwoByteToFloat(bytes[19], bytes[20]);
+        float y = TwoByteToFloat(bytes[21], bytes[22]);
+        float z = TwoByteToFloat(bytes[23], bytes[24]);
+
+        float mxr = TwoByteToFloat(bytes[20], bytes[19]);
+        float myr = TwoByteToFloat(bytes[22], bytes[21]);
+        float mzr = TwoByteToFloat(bytes[24], bytes[23]);
+
+
+        Acc = new Vector3(ax, ay, az) / 32768 * 16;
+        Gyr = new Vector3(roll, pitch, yaw) / 32768 * 2;
+        Mag = new Vector3(z, x, -y) / 32768 * 256;//第一个6+3硬件
+        //Acc = new Vector3(-az, ax, -ay) / 32768 * 16;
+        //Gyr = new Vector3(-yaw, roll, -pitch) / 32768 * 2;
+        //Mag = new Vector3(mzr, mxr, -myr) / 32768 * 256;//第二个6+3硬件
+
+
+        AccObj.transform.GetChild(0).localPosition = Acc;
+
+        Gyr = GyrCalibrater.Update(Gyr);
+
+        if (GyrCalibrater.Calibration) 
+        {
+            if (gyrCalibrateCompleteCount < gyrCalibrateTotalCount) {
+                gyrCalibrateCompleteCount++;
+            }
+        }
+        if (GyrScaleText && GyrCalibrater.Calibration) 
+        {    
+            GyrScaleText.text = "" + (_9Axis.getGyrOld() * 1000000).ToString();
+        }
+
+        if(Mag.x > -128 && Mag.y > -128 && Mag.z > -128 && Mag.x < 128 && Mag.y < 128 && Mag.z < 128)
+        {   
+            //绘制地磁计点
+            if (MagCalibrater.Calibration)
+            {
+                this.ellipseScript.AddAndUpdatePointArray(Mag);
+
+                if (Mag.magnitude > this.cMaxVector.magnitude)
+                {
+                    this.cMaxVector = Mag;
+                }
+                else if (Mag.magnitude < this.cMinVector.magnitude) {
+                    this.cMinVector = Mag;
+                }
+
+                Vector3 _center = this.cMaxVector - this.cMinVector;
+                Debug.LogWarning(_center + " == "+ _center.magnitude);
+                //设置绘制图像相机的对应位置
+                this.ellipseScript.setCameraPos(_center/2);
+            }
+            Mag = MagCalibrater.Update(Mag);
+
+            if (MagScaleText)
+            {
+                MagScaleText.text = MagCalibrater._Radius.ToString();
+            }
+           
+        }
+        MagObj.transform.GetChild(0).localPosition = Mag;
+
+        var ms = (((long)bytes[1]) *60 + bytes[2])*1000 + (long)TwoByteToFloat(bytes[3], bytes[4]);
+        if(msOld == default)
+        {
+            msOld = ms;
+            return;
+        }
+        TimeGap = ms - msOld;
+        msOld = ms;
+
+        AMesh.transform.localRotation = newRotation = _9Axis.update(Acc * 10, Gyr, Mag, TimeGap);
+
+        if (BowQuatDebug.ins) BowQuatDebug.ins.ShowModuleQuat(newRotation.eulerAngles);
+
+        if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+            SB_EventSystem.ins.MoveSimulateMouse(newRotation);
+        }
+    }
+
+    [NonSerialized] public bool lerpForRotation = true;
+    [NonSerialized] public float lerpTimeRate = 7;
+    public void Update()
+    {
+        if (controlObj && !banControlObjRotate)
+        {
+            if (lerpForRotation)
+            {
+                controlObj.localRotation = Quaternion.Lerp(controlObj.localRotation, newRotation, Time.deltaTime * lerpTimeRate);   
+            } 
+            else 
+            {
+                controlObj.localRotation = newRotation;
+            }
+        }
+    }
+
+    private bool banControlObjRotate = false;
+    public void BanControlObjRotate(bool ban) {
+        banControlObjRotate = ban;
+        if (!ban) {
+            if (controlObj) controlObj.localRotation = newRotation;
+        }
+    }
+
+    Quaternion newRotation = Quaternion.identity;
+
+    public void DoIdentity()
+    {
+        _9Axis.SetIdentityAndSave();
+        Quaternion qua = _9Axis.getLastState().Qua;
+        newRotation = qua;
+        if (controlObj) controlObj.localRotation = qua;
+    }
+}

+ 484 - 0
代码备份/2022-7-15/修改后-新硬件1和2/BluetoothAim.cs

@@ -0,0 +1,484 @@
+using ArduinoBluetoothAPI;
+using System;
+using UnityEngine;
+using System.Collections.Generic;
+using UnityEngine.UI;
+using DG.Tweening;
+using UnityEngine.SceneManagement;
+/* 蓝牙瞄准模块 */
+public class BluetoothAim : MonoBehaviour
+{
+    BluetoothHelper bluetoothHelper;
+    BluetoothHelperCharacteristic characteristicWrite;
+    BluetoothHelperService bluetoothService;
+    string targetDeviceName = "Bbow_20210501";
+    string deviceName = "";
+    bool canConnect = true;
+    [SerializeField] Text textUI;
+    public BluetoothStatusEnum status = BluetoothStatusEnum.Connect;
+    public bool hasData = false;
+    public long hasDataTime;
+    public static bool scanLock = false; //防止同时扫描冲突
+    public static BluetoothAim ins;
+
+    void Start()
+    {
+        ins = this;
+        InitAutoDormancy();
+
+#if UNITY_STANDALONE_WIN
+        new GameObject("BleUDP").AddComponent<BleUDP>();
+#endif
+    }
+
+    void OnDestroy()
+    {
+        DisconnectBleHelper();
+    }
+
+    private bool userDoConnect = false;
+    private bool doConnect = false;
+    public void DoConnect()
+    {
+        if (status == BluetoothStatusEnum.Connect)
+        {
+            userDoConnect = true;
+            doConnect = true;
+            SetStatus(BluetoothStatusEnum.Connecting);
+        }
+        else if (status == BluetoothStatusEnum.ConnectSuccess)
+        {
+            userDoConnect = false;
+            doConnect = false;
+            OnDisconnect();
+#if UNITY_ANDROID
+            DisconnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+            BleUDP.ins.Disconnect();
+#endif
+        }
+    }
+
+    void OnDisconnect()
+    {
+        hasData = false;
+        canConnect = true;
+        SetStatus(BluetoothStatusEnum.ConnectFail);
+        BowCamera.isTouchMode = true;
+        DestroyWhenDisconenct();
+    }
+
+    void Update()
+    {
+        if (userDoConnect && status == BluetoothStatusEnum.Connect)
+        {
+            DoConnect();
+        }
+        if (doConnect) Connect();
+    }
+
+    void SetStatus(BluetoothStatusEnum statusValue)
+    {
+        status = statusValue;
+        if (status == BluetoothStatusEnum.ConnectFail)
+        {
+            Sequence sequence = DOTween.Sequence();
+            sequence.AppendInterval(2f);
+            sequence.AppendCallback(delegate ()
+            {
+                if (status == BluetoothStatusEnum.ConnectFail)
+                {
+                    status = BluetoothStatusEnum.Connect;
+                }
+            });
+            sequence.SetUpdate(true);
+            DeviceReconnectView.Show();
+        }
+    }
+
+    void DisconnectBleHelper()
+    {
+        if (bluetoothHelper != null) bluetoothHelper.Disconnect();
+    }
+
+    void Connect()
+    {
+        if (BluetoothShoot.scanLock)
+        {
+            return;
+        }
+        if (!canConnect)
+        {
+            return;
+        }
+        doConnect = false;
+        scanLock = true;
+        canConnect = false;
+        SetStatus(BluetoothStatusEnum.Connecting);
+#if UNITY_ANDROID
+        ConnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+        ConnectBleByUDP();
+#endif
+    }
+
+    void ConnectBleHelper()
+    {
+        try
+        {
+            BluetoothHelper.BLE = true;
+            bluetoothHelper = BluetoothHelper.GetNewInstance();
+
+            bluetoothHelper.OnConnected += (BluetoothHelper helper) =>
+            {
+                Log("连接成功\n" + helper.getDeviceName());
+                SetStatus(BluetoothStatusEnum.ConnectSuccess);
+                BowCamera.isTouchMode = false;
+                foreach (BluetoothHelperService service in helper.getGattServices())
+                {
+
+                    if (service.getName().ToLower().StartsWith("6e400001"))
+                    {
+                        bluetoothService = service;
+
+                        foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics())
+                        {
+                            if (characteristic.getName().ToLower().StartsWith("6e400002"))
+                            {
+                                characteristicWrite = characteristic;
+                            }
+                            else if (characteristic.getName().ToLower().StartsWith("6e400003"))
+                            {
+
+                                BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName());
+                                ch.setService(bluetoothService.getName());
+                                bluetoothHelper.Subscribe(ch);
+                            }
+                        }
+                    }
+                }
+                // CallDelay(1, OpenInfrared);
+                // CallDelay(2, OpenReceiveData);
+                // CallDelay(3, RequestBattery);
+                CallDelay(2, () =>
+                {
+                    if (status != BluetoothStatusEnum.ConnectSuccess) return;
+                    InitWhenConenct();
+                });
+            };
+            bluetoothHelper.OnConnectionFailed += (BluetoothHelper helper) =>
+            {
+                Log("连接失败\n" + helper.getDeviceName());
+                OnDisconnect();
+            };
+            bluetoothHelper.OnCharacteristicChanged += (helper, value, characteristic) =>
+            {
+                if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
+                hasData = true;
+                byte[] bytes = value;
+                // Log(String.Join(",", bytes));
+                BluetoothClient.UploadData(0, bytes);
+                if (AimHandler.ins)
+                {
+                    AimHandler.ins.OnDataReceived(bytes);
+                }
+            };
+            int scanCount = 0;
+            bluetoothHelper.OnScanEnded += (BluetoothHelper helper, LinkedList<BluetoothDevice> nearbyDevices) =>
+            {
+                scanLock = false;
+                foreach (BluetoothDevice device in nearbyDevices)
+                {
+                    if (device.DeviceName == targetDeviceName)
+                    {
+                        deviceName = device.DeviceName;
+                        bluetoothHelper.setDeviceName(deviceName);
+                        bluetoothHelper.Connect();
+                        Log("发现设备\n" + device.DeviceName);
+                        return;
+                    }
+                }
+                if (scanCount < 3)
+                { //如果没扫描到,则重新扫描,达到延迟提示失败的效果
+                    scanCount++;
+                    scanLock = true;
+                    bluetoothHelper.ScanNearbyDevices();
+                }
+                else
+                {
+                    canConnect = true;
+                    Log("没有发现设备");
+                    SetStatus(BluetoothStatusEnum.ConnectFail);
+                }
+            };
+
+            bluetoothHelper.ScanNearbyDevices();
+            Log("正在扫描设备");
+        }
+        catch (Exception e)
+        {
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
+            canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
+            Log("请打开蓝牙");
+        }
+    }
+
+    void ConnectBleByUDP()
+    {
+        try
+        {
+            BleUDP.ins.OnConnected = () =>
+            {
+                Log("连接成功\n" + deviceName);
+                SetStatus(BluetoothStatusEnum.ConnectSuccess);
+                BowCamera.isTouchMode = false;
+                InitWhenConenct();
+            };
+            BleUDP.ins.OnConnectionFailed = () =>
+            {
+                Log("连接失败\n" + deviceName);
+                OnDisconnect();
+            };
+            BleUDP.ins.OnCharacteristicChanged = (byte[] value) =>
+            {
+                if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
+                hasData = true;
+                byte[] bytes = value;
+                // Log(String.Join(",", bytes));
+                BluetoothClient.UploadData(0, bytes);
+                if (AimHandler.ins)
+                {
+                    AimHandler.ins.OnDataReceived(bytes);
+                }
+            };
+            BleUDP.ins.OnScanEnded = () =>
+            {
+                scanLock = false;
+                deviceName = targetDeviceName;
+                BleUDP.ins.Connect();
+                Log("发现设备\n" + deviceName);
+            };
+
+            BleUDP.ins.ScanNearbyDevices();
+        }
+        catch (Exception e)
+        {
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
+            canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
+        }
+    }
+
+    #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来
+    class CmdToSend
+    {
+        public string[] cmds;
+        public Action onComplete;
+        public Func<bool> canDo;
+        public CmdToSend(string[] cmds, Action onComplete, Func<bool> canDo)
+        {
+            this.cmds = cmds;
+            this.onComplete = onComplete;
+            this.canDo = canDo;
+        }
+    }
+    Queue<CmdToSend> cmdWaitingList = new Queue<CmdToSend>();
+    bool isSendCmdLocked = false;
+    bool canAutoDormancy = false;
+    bool isStartUp = false;
+    JC.CS.CountLocker needModularAwake = new JC.CS.CountLocker();
+    void CheckAndStartUp()
+    {
+        if (needModularAwake.IsLocked())
+        {
+            StartUp();
+        }
+        else
+        {
+            Dormancy();
+        }
+    }
+    void InitAutoDormancy()
+    {
+        // GlobalEventCenter.ins.onGameSceneLoad += () => { 
+        //     needModularAwake.Lock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onGameSceneDestroy += () => { 
+        //     needModularAwake.Unlock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        //暂时关闭自动休眠,默认是需要模块保持激活
+        needModularAwake.Lock();
+    }
+    void InitWhenConenct()
+    {
+        canAutoDormancy = true;
+        List<string> cmds = new List<string>();
+        cmds.Add("b"); //确保开启stm32
+        cmds.Add("b"); //获取初始电量
+        cmds.Add("1"); //开启发送逻辑
+        Action onComplete = null;
+        if (needModularAwake.IsLocked())
+        {
+            cmds.Add("w"); //红外灯开启
+            cmds.Add("3"); //九轴开启
+            onComplete = () =>
+            {
+                isStartUp = true;
+            };
+        }
+        else
+        {
+            cmds.Add("s"); //红外灯关闭
+            cmds.Add("S"); //Stm32关闭
+            cmds.Add("4"); //九轴关闭
+            onComplete = () =>
+            {
+                isStartUp = false;
+            };
+        }
+        SendCDM(null, onComplete, cmds.ToArray());
+    }
+    void DestroyWhenDisconenct()
+    {
+        canAutoDormancy = false;
+        sendCMD_CheckAndDoStop(null);
+
+    }
+    //启动
+    void StartUp()
+    {
+        SendCDM(() =>
+        {
+            return !isStartUp;
+        }, () =>
+        {
+            isStartUp = true;
+        }, "b", "w", "3");
+    }
+    //休眠
+    void Dormancy()
+    {
+        SendCDM(() =>
+        {
+            return isStartUp;
+        }, () =>
+        {
+            isStartUp = false;
+        }, "4", "s", "S");
+    }
+    void SendCDM(Func<bool> canDo, Action onComplete, params string[] cmds)
+    {
+        CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo);
+        if (isSendCmdLocked)
+        {
+            cmdWaitingList.Enqueue(cmdToSend);
+            return;
+        }
+        sendCMD_NotCheck(cmdToSend);
+    }
+    void sendCMD_NotCheck(CmdToSend cmdToSend)
+    {
+        if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke())
+        {
+            sendCMD_CheckNext();
+            return;
+        }
+        isSendCmdLocked = true;
+        Sequence sequence = DOTween.Sequence();
+        sequence.PrependInterval(0.3f);
+        foreach (var cmd in cmdToSend.cmds)
+        {
+            sequence.AppendCallback(() =>
+            {
+                bool stopped = sendCMD_CheckAndDoStop(sequence);
+                if (!stopped) WriteData(cmd);
+            });
+            sequence.AppendInterval(0.5f);
+        }
+        sequence.AppendCallback(() =>
+        {
+            bool stopped = sendCMD_CheckAndDoStop(sequence);
+            if (!stopped)
+            {
+                isSendCmdLocked = false;
+                cmdToSend.onComplete?.Invoke();
+                sendCMD_CheckNext();
+            }
+        });
+        sequence.SetUpdate(true);
+    }
+    void sendCMD_CheckNext()
+    {
+        if (cmdWaitingList.Count <= 0) return;
+        CmdToSend cmdToSend = cmdWaitingList.Dequeue();
+        sendCMD_NotCheck(cmdToSend);
+    }
+    bool sendCMD_CheckAndDoStop(Sequence sequence)
+    {
+        if (canAutoDormancy) return false;
+        isStartUp = false;
+        isSendCmdLocked = false;
+        cmdWaitingList.Clear();
+        if (sequence != null) sequence.Kill();
+        return true;
+    }
+    #endregion
+
+    public void RequestBattery()
+    {
+        if (!isStartUp) return;
+        if (isSendCmdLocked) return;
+        WriteData("b");
+    }
+
+    public void ReplyInfraredShoot()
+    {
+        if (isSendCmdLocked) return;
+        WriteData("I");
+    }
+
+    void CallDelay(float delayTime, TweenCallback callback)
+    {
+        Sequence sequence = DOTween.Sequence();
+        sequence.PrependInterval(delayTime).AppendCallback(callback);
+        sequence.SetUpdate(true);
+    }
+
+    public void WriteData(string data)
+    {
+#if UNITY_ANDROID
+        if (DebugDeviceCMD.ins) DebugDeviceCMD.ins.ShowCMD(data);
+        BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName());
+        ch.setService(bluetoothService.getName());
+        bluetoothHelper.WriteCharacteristic(ch, data);
+#elif UNITY_STANDALONE_WIN
+        BleUDP.ins.SendMsg(data);
+#endif
+
+    }
+
+    void Log(string text)
+    {
+        if (textUI)
+        {
+            textUI.text = text;
+        }
+    }
+}

+ 381 - 0
代码备份/2022-7-15/修改后-旧版换方向/AimHandler.cs

@@ -0,0 +1,381 @@
+using System;
+using UnityEngine;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.UI;
+using Newtonsoft.Json;
+/* 瞄准处理器 */
+public class AimHandler : MonoBehaviour
+{
+    Transform controlObj {
+        get {
+            if (CameraToLook.ins) {
+                return CameraToLook.ins.transform;
+            }
+            return null;
+        }
+    }
+    [SerializeField] Button SetIdentityButton;
+    [SerializeField] Button MagCalibrationButton;
+    [SerializeField] Button GyrCalibrationButton;
+    [SerializeField] Text MagScaleText;
+    [SerializeField] Text GyrScaleText;
+
+    //椭圆对象
+    [SerializeField] Ellipse ellipseScript;
+    [SerializeField] GameObject AccObj;
+    [SerializeField] GameObject MagObj;
+
+    [SerializeField] GameObject AccMesh;
+    [SerializeField] GameObject GryMesh;
+    [SerializeField] GameObject MagMesh;
+    [SerializeField] GameObject AMesh;
+    [SerializeField] Transform DebugTexts;
+    [SerializeField] Transform DrawImage;
+    
+    long TimeGap = default;
+    Vector3 Acc = default;
+    Vector3 Gyr = default;
+    Vector3 Mag = default;
+    o09Axis _9Axis = new o09Axis();
+
+    Vector3 cMaxVector = new Vector3(0,0,0);
+    Vector3 cMinVector = new Vector3(0, 0, 0);
+
+    public o0MagneticCalibraterEllipsoidFitting MagCalibrater;
+    o0GyrCalibrater GyrCalibrater;
+
+    //陀螺仪校准进度记录
+    public int gyrCalibrateCompleteCount = 0;
+    public int gyrCalibrateTotalCount = 300;
+
+    long msOld = 0;
+
+    public static AimHandler ins; 
+
+    void Start()
+    {
+        ins = this;
+        BluetoothDispatcher.aim = OnDataReceived;
+
+        //初始化
+        _9Axis.LoadIdentity();
+
+        _9Axis.AccMesh = AccMesh;
+        _9Axis.GryMesh = GryMesh;
+        _9Axis.MagMesh = MagMesh;
+
+        for (var i = 0; i < 9; ++i)
+        {
+            _9Axis.Tester.Add(DrawImage.Find(i.ToString()).gameObject.AddComponent<o0UIRawImageTester>());
+        }
+
+        for (var i = 0; i < 15; ++i)
+        {
+            _9Axis.TextTester.Add(DebugTexts.transform.Find("Text" + i.ToString()).gameObject.GetComponent<Text>());
+        }
+
+        if (SetIdentityButton) 
+        {
+            SetIdentityButton.onClick.AddListener(DoIdentity);
+        }
+        
+        try 
+        {  
+            string magDataStr = PlayerPrefs.GetString("o0MagneticCalibrater");
+            MagCalibrater = JsonConvert.DeserializeObject<o0MagneticCalibraterEllipsoidFitting>(magDataStr);
+        } 
+        catch(Exception) 
+        {
+            MagCalibrater = null;
+        }
+
+        if (MagCalibrater == null) 
+        {
+            MagCalibrater = new o0MagneticCalibraterEllipsoidFitting();
+        }
+        if (MagCalibrationButton)
+        {
+            MagCalibrationButton.onClick.AddListener(delegate {
+                CalibrateMag(!MagCalibrater.Calibration);
+            });
+        }
+
+        try {
+            string gyrDataStr = PlayerPrefs.GetString("o0GyrCalibrater");
+            GyrCalibrater = JsonConvert.DeserializeObject<o0GyrCalibrater>(gyrDataStr);
+            if (GyrCalibrater._Average != Vector3.zero) GyrScaleText.text = "已校准";
+        } catch(Exception) {
+            GyrCalibrater = null;
+        }
+        if (GyrCalibrater == null) 
+        {
+            GyrCalibrater = new o0GyrCalibrater();
+        }
+        if (GyrCalibrationButton)
+        {
+            GyrCalibrationButton.onClick.AddListener(delegate() {
+                CalibrateGyr(!GyrCalibrater.Calibration);
+            });
+        }
+    }
+
+    public void CalibrateGyr(bool calibration) {
+        try {
+            GyrCalibrater.Calibration = calibration;
+            if (calibration)
+            {
+                GyrCalibrationButton.GetComponentInChildren<Text>().text = "停止陀螺仪校准";
+            }
+            else
+            {
+                GyrCalibrationButton.GetComponentInChildren<Text>().text = "开始陀螺仪校准";
+                PlayerPrefs.SetString("o0GyrCalibrater", JsonConvert.SerializeObject(GyrCalibrater));            
+            }
+        } catch (Exception e) { Debug.LogError(e.Message); }
+    }
+
+     public void CalibrateMag(bool calibration) {
+        try {
+            if (calibration)
+            {
+                MagCalibrater.Calibration = calibration;
+                MagCalibrationButton.GetComponentInChildren<Text>().text = "停止地磁计校准";
+                this.cMaxVector = new Vector3(0, 0, 0);
+                this.cMinVector = new Vector3(0, 0, 0);
+                this.ellipseScript.ellipseTran.gameObject.SetActive(false);
+            }
+            else
+            {
+                List<Vector3> list = MagCalibrater.getRecords();
+                //停止校准时候,看看数组值
+                float maxDistance = 0f,ratio = 1f;
+                Vector3 maxVector3 = new Vector3(0,0,0);
+                List<Vector3> endRecords = new List<Vector3>();
+                foreach (Vector3 i in list)
+                {
+                    Vector3 v = i - MagCalibrater._Center;
+                    if (Math.Abs(v.magnitude) > maxDistance)
+                    {
+                        maxVector3 = v;
+                        maxDistance = Math.Abs(v.magnitude);
+                        if(Math.Abs(v.magnitude) < Math.Abs(MagCalibrater._Radius.magnitude))
+                            ratio = Math.Abs(v.magnitude) / Math.Abs(MagCalibrater._Radius.magnitude);
+                        else
+                            ratio = Math.Abs(MagCalibrater._Radius.magnitude) / Math.Abs(v.magnitude);
+                    }
+                }
+                Debug.LogWarning(maxDistance + " == " + Math.Abs(MagCalibrater._Radius.magnitude) + " == " + MagCalibrater._Radius + " = " + maxVector3);
+                //如果比例效果不理想。可以设置为ratio=0.5f 
+                foreach (Vector3 i in list)
+                {
+                    //- MagCalibrater._Center
+                    Vector3 v = i ;
+                    v *= ratio;
+                    if(endRecords.Count>3000)
+                    {
+                        endRecords.RemoveAt(0);
+                    }
+                    endRecords.Add(v);
+                }
+                this.ellipseScript.ClearAndUpdatePointArray();
+                this.ellipseScript.DrawPointCloud(endRecords);
+
+                MagCalibrater.Calibration = calibration;
+
+                this.ellipseScript.ellipseTran.gameObject.SetActive(true);
+                //绘制椭圆形
+                if (MagCalibrater._Radius != this.ellipseScript.ellipseTran.localScale)
+                {
+                    this.ellipseScript.setEllipseLocalScaleAndCenter(MagCalibrater._Radius, MagCalibrater._Center* ratio);
+                    //设置绘制图像相机的对应位置
+                    this.ellipseScript.setCameraPos(MagCalibrater._Center * 0.5f);
+                }
+
+                MagCalibrationButton.GetComponentInChildren<Text>().text = "开始地磁计校准";
+                PlayerPrefs.SetString("o0MagneticCalibrater", JsonConvert.SerializeObject(MagCalibrater));
+            }
+        } catch (Exception e) { Debug.LogError(e.Message); }
+    }
+
+    //转换读取的数据,无符号->有符号
+    float TwoByteToFloat(byte b1, byte b2) 
+    {
+        ushort twoByte = (ushort) (b1 * 256 + b2);
+        short shortNum = (short) twoByte;
+        return (float) shortNum; 
+    }
+
+    public void OnDataReceived(byte[] bytes)
+    {
+        // Debug.Log("瞄准模块数据长度" + bytes.Length);
+        if (bytes.Length != 27)
+        {
+            if (bytes.Length == 2) {
+                if (bytes[0] == 0x66 && bytes[1] == 0x31) {
+                    if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+                        //鼠标居中
+                        SB_EventSystem.ins.MakeMouseToScreenCenter(); 
+                    }
+                    //视角回正
+                    DoIdentity();
+                } else if (bytes[0] == 0x66 && bytes[1] == 0x32) {
+                    if (SB_EventSystem.ins) {
+                        //唤起/隐藏虚拟鼠标
+                        SB_EventSystem.ins.AwakenSimulateMouse(); 
+                    }
+                } else if (bytes[1] == 10) {
+                    //显示电量
+                    DeviceBatteryView.ins.RenderBattery(1, bytes[0]); 
+                }
+            } else if (bytes[0] == 0x5b) {
+                if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+                    //点击鼠标
+                    SB_EventSystem.ins.ClickMouse(); 
+                } else {
+                    //红外射击检测
+                    ShootCheck.ins.ShootByInfrared(bytes); 
+                }
+            }
+            return;
+        }
+        if (bytes[7] == 0 && bytes[8] == 0 && bytes[9] == 0 && bytes[10] == 0 && bytes[11] == 0 && bytes[12] == 0)
+            return;
+        if (bytes[19] == 0 && bytes[20] == 0 && bytes[21] == 0 && bytes[22] == 0 && bytes[23] == 0 && bytes[24] == 0)
+            return;
+        
+        float ax = -TwoByteToFloat(bytes[7], bytes[8]);
+        float ay = -TwoByteToFloat(bytes[9], bytes[10]);
+        float az = -TwoByteToFloat(bytes[11], bytes[12]);
+        ax = ax / 32768 * 16;
+        ay = ay / 32768 * 16;
+        az = az / 32768 * 16;
+        Acc = new Vector3(az, ay, ax);
+        AccObj.transform.GetChild(0).localPosition = Acc;
+
+
+        float roll = TwoByteToFloat(bytes[13], bytes[14]);
+        float pitch = TwoByteToFloat(bytes[15], bytes[16]);
+        float yaw = TwoByteToFloat(bytes[17], bytes[18]);
+        roll = -roll / 32768 * 2000;
+        pitch = -pitch / 32768 * 2000;
+        yaw = -yaw / 32768 * 2000;
+        Gyr = new Vector3(yaw, pitch, roll) / 1000;
+        Gyr = GyrCalibrater.Update(Gyr);
+        if (GyrCalibrater.Calibration) 
+        {
+            if (gyrCalibrateCompleteCount < gyrCalibrateTotalCount) {
+                gyrCalibrateCompleteCount++;
+            }
+        }
+        if (GyrScaleText && GyrCalibrater.Calibration) 
+        {    
+            // GyrScaleText.text = GyrCalibrater._Average.x + "\n" + GyrCalibrater._Average.y + "\n" + GyrCalibrater._Average.z;
+            // GyrScaleText.text = "Gyr*1000,000:" + (_9Axis.GyrOld * 1000000).ToString();
+            GyrScaleText.text = "" + (_9Axis.getGyrOld() * 1000000).ToString();
+        }
+
+        float x = TwoByteToFloat(bytes[19], bytes[20]);
+        float y = TwoByteToFloat(bytes[21], bytes[22]);
+        float z = TwoByteToFloat(bytes[23], bytes[24]);
+        var mag = new Vector3(z, y, -x);
+        Mag = mag / 32768 * 256;
+    
+
+        if(Mag.x > -128 && Mag.y > -128 && Mag.z > -128 && Mag.x < 128 && Mag.y < 128 && Mag.z < 128)
+        {   
+            //绘制地磁计点
+            if (MagCalibrater.Calibration)
+            {
+                this.ellipseScript.AddAndUpdatePointArray(Mag);
+
+                if (Mag.magnitude > this.cMaxVector.magnitude)
+                {
+                    this.cMaxVector = Mag;
+                }
+                else if (Mag.magnitude < this.cMinVector.magnitude) {
+                    this.cMinVector = Mag;
+                }
+
+                Vector3 _center = this.cMaxVector - this.cMinVector;
+                Debug.LogWarning(_center + " == "+ _center.magnitude);
+                //设置绘制图像相机的对应位置
+                this.ellipseScript.setCameraPos(_center/2);
+            }
+            Mag = MagCalibrater.Update(Mag);
+
+            if (MagScaleText)
+            {
+                MagScaleText.text = MagCalibrater._Radius.ToString();
+            }
+           
+        }
+        MagObj.transform.GetChild(0).localPosition = Mag;
+
+        var ms = (((long)bytes[1]) *60 + bytes[2])*1000 + (long)TwoByteToFloat(bytes[3], bytes[4]);
+        if(msOld == default)
+        {
+            msOld = ms;
+            return;
+        }
+        TimeGap = ms - msOld;
+        msOld = ms;
+
+        var GyrOperator = new Quaternion();
+        GyrOperator.eulerAngles = Gyr * TimeGap;
+        AMesh.transform.localRotation *= GyrOperator;
+
+        newRotation = _9Axis.update(Acc * 10, Gyr, Mag, TimeGap);
+
+        if (BowQuatDebug.ins) BowQuatDebug.ins.ShowModuleQuat(newRotation.eulerAngles);
+
+        if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) {
+            SB_EventSystem.ins.MoveSimulateMouse(newRotation);
+        }
+        // 记录一些旋转角---start
+        // if (ArmBow.ins) {
+        //     for (int i = ArmBow.ins.recordRotations.Length - 1; i > 0 ; i--)
+        //     {
+        //         ArmBow.ins.recordRotations[i] = ArmBow.ins.recordRotations[i - 1];
+        //     }
+        //     ArmBow.ins.recordRotations[0] = newRotation;
+        //     ArmBow.ins.recordCount++;
+        // }
+        // 记录一些旋转角---end
+    }   
+
+    [NonSerialized] public bool lerpForRotation = true;
+    [NonSerialized] public float lerpTimeRate = 7;
+    public void Update()
+    {
+        if (controlObj && !banControlObjRotate)
+        {
+            if (lerpForRotation)
+            {
+                controlObj.localRotation = Quaternion.Lerp(controlObj.localRotation, newRotation, Time.deltaTime * lerpTimeRate);   
+            } 
+            else 
+            {
+                controlObj.localRotation = newRotation;
+            }
+        }
+    }
+
+    private bool banControlObjRotate = false;
+    public void BanControlObjRotate(bool ban) {
+        banControlObjRotate = ban;
+        if (!ban) {
+            if (controlObj) controlObj.localRotation = newRotation;
+        }
+    }
+
+    Quaternion newRotation = Quaternion.identity;
+
+    public void DoIdentity()
+    {
+        _9Axis.SetIdentityAndSave();
+        Quaternion qua = _9Axis.getLastState().Qua;
+        newRotation = qua;
+        if (controlObj) controlObj.localRotation = qua;
+    }
+}