Unity VR Exergame Bluetooth Help

I am building a VR cycling application in Unity. In my project I need to be able to connect the exercise bike and the heartrate monitor via Bluetooth concurrently, however I am experiencing a weird problem when I do that.

Both devices work fine when connected on their own, however the received data goes all wrong when I connect them both at the same time.

When the exercise bike is receiving data on its own it receives Speed, Cadence, Power. However when I connect the heartrate monitor at the same time it receives Speed, Distance, and Expended Energy.

I have attached my relevant code scripts, any help would be greatly appreciated I am genuinely clueless as to why this is happening as I have little experience with Bluetooth.

Scripts:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using UnityEngine;


public class BleApi
{
    // dll calls
    public enum ScanStatus { PROCESSING, AVAILABLE, FINISHED };

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DeviceUpdate
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string id;
        [MarshalAs(UnmanagedType.I1)]
        public bool isConnectable;
        [MarshalAs(UnmanagedType.I1)]
        public bool isConnectableUpdated;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
        public string name;
        [MarshalAs(UnmanagedType.I1)]
        public bool nameUpdated;
    }

    [DllImport("BleWinrtDll.dll", EntryPoint = "StartDeviceScan")]
    public static extern void StartDeviceScan();

    [DllImport("BleWinrtDll.dll", EntryPoint = "PollDevice")]
    public static extern ScanStatus PollDevice(ref DeviceUpdate device, bool block);

    [DllImport("BleWinrtDll.dll", EntryPoint = "StopDeviceScan")]
    public static extern void StopDeviceScan();

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct Service
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string uuid;
    };

    [DllImport("BleWinrtDll.dll", EntryPoint = "ScanServices", CharSet = CharSet.Unicode)]
    public static extern void ScanServices(string deviceId);

    [DllImport("BleWinrtDll.dll", EntryPoint = "PollService")]
    public static extern ScanStatus PollService(out Service service, bool block);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct Characteristic
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string uuid;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string userDescription;
    };

    [DllImport("BleWinrtDll.dll", EntryPoint = "ScanCharacteristics", CharSet = CharSet.Unicode)]
    public static extern void ScanCharacteristics(string deviceId, string serviceId);

    [DllImport("BleWinrtDll.dll", EntryPoint = "PollCharacteristic")]
    public static extern ScanStatus PollCharacteristic(out Characteristic characteristic, bool block);

    [DllImport("BleWinrtDll.dll", EntryPoint = "SubscribeCharacteristic_Read", CharSet = CharSet.Unicode)]
    public static extern bool SubscribeCharacteristic_Read(string deviceId, string serviceId, string characteristicId, bool block);

    [DllImport("BleWinrtDll.dll", EntryPoint = "SubscribeCharacteristic_Write", CharSet = CharSet.Unicode)]
    public static extern bool SubscribeCharacteristic_Write(string deviceId, string serviceId, string characteristicId, bool block);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct BLEData
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
        public byte[] buf;
        [MarshalAs(UnmanagedType.I2)]
        public short size;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string deviceId;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string serviceUuid;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string characteristicUuid;
    };

    [DllImport("BleWinrtDll.dll", EntryPoint = "PollData")]
    public static extern bool PollData(out BLEData data, bool block);

    [DllImport("BleWinrtDll.dll", EntryPoint = "SendData")]
    public static extern bool SendData(in BLEData data, bool block);

    [DllImport("BleWinrtDll.dll", EntryPoint = "Quit")]
    public static extern void Quit();

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct ErrorMessage
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
        public string msg;
    };

    [DllImport("BleWinrtDll.dll", EntryPoint = "GetError")]
    public static extern void GetError(out ErrorMessage buf);
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FTMS_IndoorBike
{
    string device_name;
    string service_id;
    string read_characteristic;
    string write_characteristic;

    public bool want_connect = true;
    Dictionary<string, Dictionary<string, string>> devices = new Dictionary<string, Dictionary<string, string>>();
    string selectedDeviceId = "";
    string selectedServiceId = "";
    string selectedCharacteristicId = "";

    bool isSubscribed = false;

    public string output;
    public float speed; public bool has_speed = false;
    public float average_speed; public bool has_average_speed = false;
    public float rpm; public bool has_rpm = false;
    public float average_rpm; public bool has_average_rpm = false;
    public float distance; public bool has_distance = false;
    public float resistance; public bool has_resistance = false;
    public float power; public bool has_power = false;
    public float average_power; public bool has_average_power = false;
    public float expended_energy; public bool has_expended_energy = false;

    string lastError;

    float last_write_time = 0.0f;
    int sended_resistance = 0;

    MonoBehaviour mono;
    FTMS_UI ui;
    public FTMS_IndoorBike(MonoBehaviour _mono, FTMS_UI _ui)
    {
        mono = _mono;
        ui = _ui;
    }

    // Start is called before the first frame update
    public IEnumerator connect(string _device_name = "WattbikePT28004316", string _service_id = "{babf1723-cedb-444c-88c3-c672c7a59806}", string _read_characteristic = "{babf1724-cedb-444c-88c3-c672c7a59806}", string _write_characteristic = "{babf1725-cedb-444c-88c3-c672c7a59806}")
    {
        if (!want_connect) yield break;

        device_name = _device_name;
        service_id = _service_id;
        read_characteristic = _read_characteristic;
        write_characteristic = _write_characteristic;

        quit();

        yield return mono.StartCoroutine(connect_device());
        if (selectedDeviceId.Length == 0) yield break;

        Debug.Log("connecting device finish");

        yield return mono.StartCoroutine(connect_service());
        if (selectedServiceId.Length == 0) yield break;

        Debug.Log("connecting service finish");

        yield return mono.StartCoroutine(connect_read_characteristic());
        if (selectedCharacteristicId.Length == 0) yield break;

        Debug.Log("connecting read characteristic finish");

        read_subscribe();

        ui.connected = true;
    }

    IEnumerator connect_device()
    {
        Debug.Log("connecting device...");
        BleApi.StartDeviceScan();
        BleApi.ScanStatus status = BleApi.ScanStatus.AVAILABLE;
        BleApi.DeviceUpdate device_res = new BleApi.DeviceUpdate();
        do
        {
            status = BleApi.PollDevice(ref device_res, false);
            //Debug.Log(count++);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (!devices.ContainsKey(device_res.id))
                    devices[device_res.id] = new Dictionary<string, string>() {
                            { "name", "" },
                            { "isConnectable", "False" }
                        };
                if (device_res.nameUpdated)
                    devices[device_res.id]["name"] = device_res.name;
                if (device_res.isConnectableUpdated)
                    devices[device_res.id]["isConnectable"] = device_res.isConnectable.ToString();
                // consider only devices which have a name and which are connectable
                if (devices[device_res.id]["name"] == device_name && devices[device_res.id]["isConnectable"] == "True")
                {
                    //BleApi.Connect(device_res.id);
                    selectedDeviceId = device_res.id;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {

                if (selectedDeviceId.Length == 0)
                {
                    Debug.LogError("device " + device_name + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    IEnumerator connect_service()
    {
        Debug.Log("connecting service...");
        BleApi.ScanServices(selectedDeviceId);
        BleApi.ScanStatus status;
        BleApi.Service service_res = new BleApi.Service();
        do
        {
            status = BleApi.PollService(out service_res, false);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (service_res.uuid == service_id)
                {
                    selectedServiceId = service_res.uuid;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {
                if (selectedServiceId.Length == 0)
                {
                    Debug.LogError("service " + service_id  + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    IEnumerator connect_read_characteristic()
    {
        Debug.Log("connecting characteristic...");
        BleApi.ScanCharacteristics(selectedDeviceId, selectedServiceId);
        BleApi.ScanStatus status;
        BleApi.Characteristic characteristics_res = new BleApi.Characteristic();

        do
        {
            status = BleApi.PollCharacteristic(out characteristics_res, false);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (characteristics_res.uuid == read_characteristic)
                {
                    selectedCharacteristicId = characteristics_res.uuid;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {
                if (selectedCharacteristicId.Length == 0)
                {
                    Debug.LogError("characteristic " + read_characteristic + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    void read_subscribe()
    {
        Debug.Log("Subscribe...");
        BleApi.SubscribeCharacteristic_Read(selectedDeviceId, selectedServiceId, selectedCharacteristicId, false);
        isSubscribed = true;
    }


    public void quit()
    {
        BleApi.Quit();
    }


    // Update is called once per frame
    public void Update()
    {


        if (isSubscribed)
        {

            BleApi.BLEData res = new BleApi.BLEData();
            while (BleApi.PollData(out res, false))
            {
                {
                    has_speed = false;
                    has_average_speed = false;
                    has_rpm = false;
                    has_average_rpm = false;
                    has_distance = false;
                    has_resistance = false;
                    has_power = false;
                    has_average_power = false;
                    has_expended_energy = false;
                }

                output = String.Empty;
                int index = 0;
                int flags = BitConverter.ToUInt16(res.buf, index);
                index += 2;
                if ((flags & 0) == 0)
                {
                    has_speed = true;
                    float value = (float)BitConverter.ToUInt16(res.buf, index);
                    speed = (value * 1.0f) / 100.0f;
                    output += "Speed: " + speed + "\n";
                    index += 2;
                }
                if ((flags & 2) > 0)
                {
                    //??
                    has_average_speed = true;
                    average_speed = BitConverter.ToUInt16(res.buf, index);
                    output += "Average Speed: " + average_speed + "\n";
                    index += 2;
                }
                if ((flags & 4) > 0)
                {
                    rpm = (BitConverter.ToUInt16(res.buf, index) * 1.0f) / 2.0f;
                    output += "RPM: (rev/min): " + rpm + "\n";
                    index += 2;
                }
                if ((flags & 8) > 0)
                {
                    average_rpm = (BitConverter.ToUInt16(res.buf, index) * 1.0f) / 2.0f;
                    output += "Average RPM: " + average_rpm + "\n";
                    index += 2;
                }
                if ((flags & 16) > 0)
                {
                    distance = BitConverter.ToUInt16(res.buf, index); // ?????s
                    output += "Distance (meter): " + distance + "\n";
                    index += 2;
                }
                if ((flags & 32) > 0)
                {
                    resistance = BitConverter.ToInt16(res.buf, index);
                    output += "Resistance: " + resistance + "\n";
                    index += 2;
                }
                if ((flags & 64) > 0)
                {
                    power = BitConverter.ToInt16(res.buf, index);
                    output += "Power (Watt): " + power + "\n";
                    index += 2;
                }
                if ((flags & 128) > 0)
                {
                    average_power = BitConverter.ToInt16(res.buf, index);
                    output += "AveragePower: " + average_power + "\n";
                    index += 2;
                }
                if ((flags & 256) > 0)
                {
                    expended_energy = BitConverter.ToUInt16(res.buf, index);
                    output += "ExpendedEnergy: " + expended_energy + "\n";
                    index += 2;
                }
                
                //output += "Resistance: " + sended_resistance + "\n";
            }

            // log potential errors
            BleApi.ErrorMessage res_err = new BleApi.ErrorMessage();
            BleApi.GetError(out res_err);
            if (lastError != res_err.msg)
            {
                Debug.LogError(res_err.msg);
                lastError = res_err.msg;
            }
        }


    }

    private byte[] Convert16(string strText)
    {
        strText = strText.Replace(" ", "");
        byte[] bText = new byte[strText.Length / 2];
        for (int i = 0; i < strText.Length / 2; i++)
        {
            bText[i] = Convert.ToByte(Convert.ToInt32(strText.Substring(i * 2, 2), 16));
        }
        return bText;
    }

    public void Write(string msg)
    {
        
        byte[] payload22 = Convert16(msg);
        BleApi.BLEData data = new BleApi.BLEData();
        data.buf = new byte[512];
        data.size = (short)payload22.Length;
        data.deviceId = selectedDeviceId;
        data.serviceUuid = selectedServiceId;
        data.characteristicUuid = write_characteristic;
        for (int i = 0; i < payload22.Length; i++)
        {
            data.buf[i] = payload22[i];
        }
        BleApi.SendData(in data, false);
    }

    public void write_resistance(float val)
    {
        write_resistance(Mathf.FloorToInt(val));
    }
    public void write_resistance(int val)
    {
        if (Time.time - last_write_time < 0.1f)
        {
            return;
        }
        else {
            last_write_time = Time.time;
        }

        Debug.Log("write resistance: " + val);

        BleApi.SubscribeCharacteristic_Write(selectedDeviceId, selectedServiceId, write_characteristic, false);
        Write("00");
        byte resistance1 = Convert.ToByte(val % 256);
        byte resistance2 = Convert.ToByte(val / 256);
        byte[] payload = { 0x11, 0x00, 0x00, resistance1, resistance2, 0x00, 0x00 };
        BleApi.BLEData data = new BleApi.BLEData();
        data.buf = new byte[512];
        data.deviceId = selectedDeviceId;
        data.serviceUuid = selectedServiceId;
        data.characteristicUuid = write_characteristic;
        for (int i = 0; i < payload.Length; i++){
            data.buf[i] = payload[i];
        }
        data.size = (short)payload.Length;
        BleApi.SendData(in data, false);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FTMS_UI : MonoBehaviour
{
    // Start is called before the first frame update
    public bool connected = false;
    public FTMS_IndoorBike connector;
    public string infoText;
    public Text resistance_show;
    [SerializeField] private DataManager dataManager;


    public string device_name = "WattbikePT28004316";
    public string service_id = "{00001826-0000-1000-8000-00805f9b34fb}";
    public string read_characteristic = "{00002ad2-0000-1000-8000-00805f9b34fb}";
    public string write_characteristic= "{00002ad9-0000-1000-8000-00805f9b34fb}";
    public void BeginConnection()
    {
        connector = new FTMS_IndoorBike(this, this);
        connect();
    }

    public void connect() {



        if (device_name.Length > 0 && service_id.Length > 0 && read_characteristic.Length > 0 && write_characteristic.Length > 0)
        {
            StartCoroutine(connector.connect(device_name, service_id, read_characteristic, write_characteristic));
        }
    }

    public void write_resistance(float val) {
        if (connected)
        {
            connector.write_resistance(val);
            resistance_show.text = "Resistance: " + Mathf.FloorToInt(val).ToString();
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (connected)
        {

            connector.Update();
            infoText = connector.output;
        }
    }
    private void OnApplicationQuit()
    {
        connector.quit();
    }

    public void change_device_name(string _device_name) {
        device_name = _device_name;
    }
    public void change_service_id(string _service_id)
    {
        service_id = _service_id;
    }
    public void change_read_characteristic(string _read_characteristic)
    {
        read_characteristic = _read_characteristic;
    }
    public void change_write_characteristic(string _write_characteristic)
    {
        write_characteristic = _write_characteristic;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class HeartRateMonitor
{
    string device_name;
    string service_id;
    string read_characteristic;

    public bool want_connect = true;
    Dictionary<string, Dictionary<string, string>> devices = new Dictionary<string, Dictionary<string, string>>();
    string selectedDeviceId = "";
    string selectedServiceId = "";
    string selectedCharacteristicId = "";

    bool isSubscribed = false;

    public string output;
    public int heartRate; public bool has_heartRate = false;
    public bool contact_detected; public bool has_contact = false;
    public bool rr_interval_present; public bool has_rr_interval = false;
    public List<int> rr_intervals = new List<int>(); // RR intervals in ms

    string lastError;

    MonoBehaviour mono;
    HeartRateMonitor_UI ui;
    public HeartRateMonitor(MonoBehaviour _mono, HeartRateMonitor_UI _ui)
    {
        mono = _mono;
        ui = _ui;
    }

    // Start is called before the first frame update
    public IEnumerator connect(string _device_name = "Polar H10 D7E96D26", string _service_id = "{0000180d-0000-1000-8000-00805f9b34fb}", string _read_characteristic = "{00002A37-0000-1000-8000-00805f9b34fb}")
    {
        if (!want_connect) yield break;

        device_name = _device_name;
        service_id = _service_id;
        read_characteristic = _read_characteristic;

        quit();

        yield return mono.StartCoroutine(connect_device());
        if (selectedDeviceId.Length == 0) yield break;

        Debug.Log("connecting device finish");

        yield return mono.StartCoroutine(connect_service());
        if (selectedServiceId.Length == 0) yield break;

        Debug.Log("connecting service finish");

        yield return mono.StartCoroutine(connect_read_characteristic());
        if (selectedCharacteristicId.Length == 0) yield break;

        Debug.Log("connecting read characteristic finish");

        read_subscribe();
        ui.connected = true;
    }

    IEnumerator connect_device()
    {
        Debug.Log("connecting device...");
        BleApi.StartDeviceScan();
        BleApi.ScanStatus status = BleApi.ScanStatus.AVAILABLE;
        BleApi.DeviceUpdate device_res = new BleApi.DeviceUpdate();
        do
        {
            status = BleApi.PollDevice(ref device_res, false);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (!devices.ContainsKey(device_res.id))
                    devices[device_res.id] = new Dictionary<string, string>() {
                            { "name", "" },
                            { "isConnectable", "False" }
                        };
                if (device_res.nameUpdated)
                    devices[device_res.id]["name"] = device_res.name;
                if (device_res.isConnectableUpdated)
                    devices[device_res.id]["isConnectable"] = device_res.isConnectable.ToString();
                // consider only devices which have a name and which are connectable
                if (devices[device_res.id]["name"] == device_name && devices[device_res.id]["isConnectable"] == "True")
                {
                    selectedDeviceId = device_res.id;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {
                if (selectedDeviceId.Length == 0)
                {
                    Debug.LogError("device " + device_name + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    IEnumerator connect_service()
    {
        Debug.Log("connecting service...");
        BleApi.ScanServices(selectedDeviceId);
        BleApi.ScanStatus status;
        BleApi.Service service_res = new BleApi.Service();
        do
        {
            status = BleApi.PollService(out service_res, false);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (service_res.uuid == service_id)
                {
                    selectedServiceId = service_res.uuid;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {
                if (selectedServiceId.Length == 0)
                {
                    Debug.LogError("service " + service_id + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    IEnumerator connect_read_characteristic()
    {
        Debug.Log("connecting characteristic...");
        BleApi.ScanCharacteristics(selectedDeviceId, selectedServiceId);
        BleApi.ScanStatus status;
        BleApi.Characteristic characteristics_res = new BleApi.Characteristic();

        do
        {
            status = BleApi.PollCharacteristic(out characteristics_res, false);
            if (status == BleApi.ScanStatus.AVAILABLE)
            {
                if (characteristics_res.uuid == read_characteristic)
                {
                    selectedCharacteristicId = characteristics_res.uuid;
                    break;
                }
            }
            else if (status == BleApi.ScanStatus.FINISHED)
            {
                if (selectedCharacteristicId.Length == 0)
                {
                    Debug.LogError("characteristic " + read_characteristic + " not found!");
                }
            }
            yield return 0;
        } while (status == BleApi.ScanStatus.AVAILABLE || status == BleApi.ScanStatus.PROCESSING);
    }

    void read_subscribe()
    {
        Debug.Log("Subscribe...");
        BleApi.SubscribeCharacteristic_Read(selectedDeviceId, selectedServiceId, selectedCharacteristicId, false);
        isSubscribed = true;
    }

    public void quit()
    {
        BleApi.Quit();
    }

    // Update is called once per frame
    public void Update()
    {
        if (isSubscribed)
        {
            BleApi.BLEData res = new BleApi.BLEData();
            while (BleApi.PollData(out res, false))
            {
                has_heartRate = false;
                has_contact = false;
                has_rr_interval = false;
                rr_intervals.Clear();

                output = String.Empty;
                int index = 0;

                // Read first byte for flags
                byte flags = res.buf[index++];

                // Heart Rate Value Format bit (0 = UINT8, 1 = UINT16)
                bool isUint16 = (flags & 0x01) != 0;

                // Sensor Contact Status bits
                bool contactSensorPresent = (flags & 0x04) != 0;
                if (contactSensorPresent)
                {
                    has_contact = true;
                    contact_detected = (flags & 0x02) != 0;
                    output += "Contact: " + (contact_detected ? "Detected" : "Not Detected") + "\n";
                }

                // Energy Expended Status bit
                bool energyExpendedPresent = (flags & 0x08) != 0;

                // RR-Interval bit
                rr_interval_present = (flags & 0x10) != 0;
                has_rr_interval = rr_interval_present;

                // Read the Heart Rate Measurement Value
                if (isUint16)
                {
                    heartRate = BitConverter.ToUInt16(res.buf, index);
                    index += 2;
                }
                else
                {
                    heartRate = res.buf[index++];
                }
                has_heartRate = true;
                output += "Heart Rate: " + heartRate + " bpm\n";

                // Skip Energy Expended field if present
                if (energyExpendedPresent)
                {
                    index += 2; // UINT16
                }

                // Read RR-Intervals if present
                if (rr_interval_present)
                {
                    // Calculate how many RR intervals are in the packet
                    // Each RR interval is 2 bytes (UINT16)
                    int remainingBytes = res.size - index;
                    int rrIntervalCount = remainingBytes / 2;

                    output += "RR Intervals: ";
                    for (int i = 0; i < rrIntervalCount; i++)
                    {
                        int rrInterval = BitConverter.ToUInt16(res.buf, index);
                        index += 2;
                        // RR intervals are in 1/1024 second units, convert to milliseconds
                        int rrIntervalMs = (int)Math.Round(rrInterval * 1000.0 / 1024.0);
                        rr_intervals.Add(rrIntervalMs);
                        output += rrIntervalMs + "ms ";
                    }
                    output += "\n";
                }
            }

            // log potential errors
            BleApi.ErrorMessage res_err = new BleApi.ErrorMessage();
            BleApi.GetError(out res_err);
            if (lastError != res_err.msg && !string.IsNullOrEmpty(res_err.msg))
            {
                Debug.LogError(res_err.msg);
                lastError = res_err.msg;
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HeartRateMonitor_UI : MonoBehaviour
{
    public bool connected = false;
    public HeartRateMonitor connector;
    [SerializeField] private DataManager dataManager;
    [SerializeField] private string infoText;

    // Default values for heart rate monitor - can be changed in inspector
    public string device_name = "Polar H10 D7E96D26";
    public string service_id = "{0000180d-0000-1000-8000-00805f9b34fb}"; // Standard Heart Rate Service UUID
    public string read_characteristic = "{00002a37-0000-1000-8000-00805f9b34fb}"; // Heart Rate Measurement characteristic

    private void Start()
    {
        dataManager = FindObjectOfType<DataManager>();
    }

    public void BeginConnection()
    {
        connector = new HeartRateMonitor(this, this);
        connect();
    }

    public void connect()
    {
        if (device_name.Length > 0 && service_id.Length > 0 && read_characteristic.Length > 0)
        {
            StartCoroutine(connector.connect(device_name, service_id, read_characteristic));
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (connected)
        {

            connector.Update();
            infoText = connector.output;

            if (connector.has_heartRate)
            {

            }
        }

    }

    private void OnApplicationQuit()
    {
        connector.quit();
    }

    // Methods to update device parameters from UI
    public void change_device_name(string _device_name)
    {
        device_name = _device_name;
    }

    public void change_service_id(string _service_id)
    {
        service_id = _service_id;
    }

    public void change_read_characteristic(string _read_characteristic)
    {
        read_characteristic = _read_characteristic;
    }

    // Method to reconnect with new parameters
    public void reconnect()
    {
        connected = false;
        connector.quit();
        connect();
    }


}