BLE(心率)读取文件

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
你好,
我是新的!
需要帮助构建一个Windows应用程序来读取极地H10 HR测量频带。
我开始使用这个代码; 蓝牙通用属性配置文件 - 心率服务.ZIP
示例应用程序读取HR并向窗口显示为条形图和列表框。
我需要将读数导出到TXT文件甚至是虚拟COM端口。
无论如何,甚至不是文本文件创建/附加正在成功 :D.
我对C#的了解非常低......
下面的代码。有人可以帮忙吗?
所有和任何想法都将非常感谢。
谢谢!

async void instance_valuechangeChiteed:
private async void Instance_ValueChangeCompleted(HeartRateMeasurement heartRateMeasurementValue)

        {

            // Serialize UI update to the the main UI thread.

            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>

            {

                statusTextBlock.Text = "Latest received heart rate measurement: " +

                    heartRateMeasurementValue.HeartRateValue;


#if WINDOWS_APP

                outputDataChart.PlotChart(HeartRateService.Instance.DataPoints);

#endif


                outputListBox.Items.Insert(0, heartRateMeasurementValue);



                string path = @"C:\Users\eliseu.santos\Documents\file.txt";


                // convert string to stream

                byte[] byteArray = Encoding.UTF8.GetBytes(path);

                MemoryStream stream = new MemoryStream(byteArray);


                using (TextWriter tw = new StreamWriter(stream))

                {

                    tw.WriteLine("The next line!");

                    tw.WriteLine(heartRateMeasurementValue.HeartRateValue);

                    //tw.Dispose();

                }


            });

        }
 
Last edited:

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
嘿跳伞运动员,非常感谢你的帮助。

我尝试了各种各样的例子,始终收到错误:CS1503参数1:无法从“string”转换为'system.iostream'

C#:
private async void Instance_ValueChangeCompleted(HeartRateMeasurement heartRateMeasurementValue)
        {
            // Serialize UI update to the the main UI thread.
            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                statusTextBlock.Text = "Latest received heart rate measurement: " +
                    heartRateMeasurementValue.HeartRateValue;

#if WINDOWS_APP
                outputDataChart.PlotChart(HeartRateService.Instance.DataPoints);
#endif

                outputListBox.Items.Insert(0, heartRateMeasurementValue);




                string docpath = @"C:\Users\eliseu.santos\Documents\";

                

                // Append text to an existing file named "WriteLines.txt".
                using (StreamWriter outputFile = new StreamWriter(Path.Combine(docpath, "file.txt")))
                {
                    outputFile.WriteLine("The next line!");
                    outputFile.WriteLine(heartRateMeasurementValue.HeartRateValue);
                }


            });
        }

你能在这里帮助这个错误吗?

上面的代码在第一个帖子中没有显示任何错误,但它不会创建任何文件,也不会写入现有文件。
所有代码样本都来自github, 这里.

谢谢你。
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
你不应该手动编写路径,就是这样 环境.SpecialFolder. 是的。你会注意到这条线的位置:: swriter.writeline(ARRText.); - 如果您愿意,可以删除循环并仅在心率测量中写入。代码测试并工作,编辑到您自己的喜好。如果您陷入困境或有任何疑问,请张贴。代码有内联的评论,但非常自我解释。

Write a text file:
using System;
using System.IO;
using System.Windows.Forms;

namespace TestCSharpApp
{
    public partial class Form1 : Form
    {
        private readonly string pathOfAddress = Environment.GetFolderPath(环境.SpecialFolder..MyDocuments); //Use special folders instead of manually writing the file path
        private readonly string fileName = "VisualStudioFile";
        private readonly string extAttribute = ".txt";
        private readonly string[] arrOfstuff = { "Sheepings wrote this for me", "Because my dog eat my homework" };

        public Form1()
        {
            InitializeComponent();
            var fullPath = Path.Combine(pathOfAddress, string.Concat(fileName, extAttribute)); //Combine the path and concatenate the path with its file extension
            runArgs(fullPath, arrOfstuff); //Call runArgs by passing in our path and variables to write
        }

        private void runArgs(string path, string[] arrText) //This method takes two parameters, which are fullPath, and arrOfStuff
        {
            try
            {
                using (StreamWriter sWriter = new StreamWriter(path)) //Use using blocks as they are self disposing as well as the resources used within. Pass in your path to the writer
                {
                    for (int i = 0; i < 2; i++) //Loop the strings in arrText
                    {
                        swriter.writeline(ARRText.[i]);
                    }
                }
            }
            catch (Exception x)
            {
                //Handle any errors if any
            }
            finally
            {
                //Finnish up any work here
            }
        }
    }
}

你甚至不需要StreamWriter,你可以用它来做 文件写入所有行。希望你发现这很有用。

编辑::修复了拼写错误
 
Last edited:

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
嗨毛皮,谢谢你的帮助。

我应该如何使用该代码?
尝试使用该代码进行新类文件,但获取错误......
特别是这个;
Environment.getFolderPath,给我错误CS0117“环境”不包含'getfolderpath'的定义

我非常基本的C#......很可能是在这里做错了什么。

甚至尝试使用该代码部分,插入到异步空白;

(几乎相同的错误......)

C#:
private async void Instance_ValueChangeCompleted(HeartRateMeasurement heartRateMeasurementValue)
        {
            // Serialize UI update to the the main UI thread.
            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                statusTextBlock.Text = "Latest received heart rate measurement: " +
                    heartRateMeasurementValue.HeartRateValue;

#if WINDOWS_APP
                outputDataChart.PlotChart(HeartRateService.Instance.DataPoints);
#endif

                outputListBox.Items.Insert(0, heartRateMeasurementValue);
            });
        }

我只需要这堂课来放入文本文件心率测量....该死的,这应该很容易。 :D.
 
Last edited:

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+
原因是因为您绑架的示例代码是针对Windows运行时的目标,但剪毛呈现的代码是用于Windows窗体的代码。
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
嗯,你说:: 需要帮助构建Windows应用程序 - 你能澄清吗?这是UWP / Windows商店吗?还是什么?我假设一个桌面应用程序,对不起,我应该问。

无论@Filipesantos.,是的,您仍然可以使用我的代码,调整它以满足您的需求。如果您正在构建商店应用程序或跨平台应用程序,则在标准桌面环境应用程序(如WinForms)中提供的某些事情将无法使用。
 

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
哦,是的,我也很抱歉缺乏澄清。
我需要一个独立的桌面应用程序确实需要。
一直从我在寻找BLE HR阅读器时发现的许多网站的许多代码样本,到目前为止,此示例是我唯一一个在编码(VB之外)的知识的唯一一个,可以管理工作和查看一些结果...... :D.

感谢两者,无论如何,分享您的代码/帮助,但似乎现在在我身边时似乎更加强硬,对吧?
所以现在,我有什么机会让这些读数导出到文本文件,或者到COM端口,或者从vb6中正在做的另一个应用程序抓住它们的任何其他意味着什么?
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+
如果您的主应用程序在VB6中?为什么不简单地为您的应用程序添加代码以阅读表格大多数蓝牙设备暴露的虚拟通讯端口?如果您已经修改了VB6程序以从一些文本文件中读取,为什么不直接到源?

我模糊地回想一下,从VB6中读取从蓝牙阅读,你需要MSComm.ocx,但它真的很久以前,我尽力冲洗所有的VB6记忆。
 

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
:D.
嘿,跳伞运动员,希望我能做到这一点......冲洗我对VB6的回忆。但没有太多时间来学习其他语言和新的开发技巧/语法/等。
无论如何,AFAIK,BLE设备不会构建虚拟通讯端口,这将是这里的另一个大愿望。但会确认这些机会。
现在,回到我的旧路径,不介意有一个运行的第二个应用程序来收集这些HR测量。
它有什么机会工作?
 

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
嗨跳伞运动员,非常感谢你。
发展平台选项现在如此多,我迷失在他们身上。
需要了解这一点...... :D.
我不能在那个论坛上发布。这么多规则和新手的限制。
无论如何,我想在划痕中建立一个桌面表单应用程序,使用到目前为止的所有信息。
也许将从VB6迁移到C#的主要应用程序,同时学习如何在此处代码...
从您的经验中,您认为有可能(意味着BLE - 心率测量读取)吗?
 
Last edited:

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+
是的,有可能。 Demo应用程序提供的Microsoft的事实显示,可以从设备中获取数据。

主要问题是,您只有两个明显的路线可以去获取数据。选项1是最简单的是编写UWP应用程序,因为BLE API被UWP框架曝光很好。选项2是在编写C ++ COM应用的中等难度之上,因为BLE API也被Windows作为Windows SDK / DDK的一部分。

不幸的是,我尚未找到一个中间地面,其中BLE API很好地包裹着常规的.NET框架应用程序。因此,我的链接了关于如何从常规的.NET框架应用程序到达UWP BLE API。

可以想象,由于BLE API暴露为COM对象,因此可以创建一个互操作组件以从.NET框架和/或使用P / Invoke访问它们。我现在并不是有时间或倾向于探索那个现在,但也许有人已经完成了它。只需要搜索合适的关键字。
 

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
嘿跳伞运动员,谢谢你的意见。
那么,如果我理解正确,最好的方法就是我在第一篇文章发布的那个吧?
关于您发布的链接,那个控制台选项似乎有希望......我通过其地址和名称获取我的设备,但难以获得其他任何东西,主要是因为缺乏所需的知识来提取人力资源的价值观。
 

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
再次问好,

我的最新尝试......
Console Writing:
private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
        {
            var HRm = new BluetoothGattHeartRate.HeartRateMeasurement();
            var HRmeasurement = HRm.HeartRateValue;

            if (eventArgs.Advertisement.LocalName == "Polar H10 1B80EF25")
            {
                // Tell the user we see an advertisement and print some properties
                Console.WriteLine(String.Format("Advertisement:"));
                Console.WriteLine(String.Format("  BT_ADDR: {0}", eventArgs.BluetoothAddress));
                Console.WriteLine(String.Format("  FR_NAME: {0}", eventArgs.Advertisement.LocalName));
                Console.WriteLine(String.Format("  TEST: {0}", HRmeasurement));
                Console.WriteLine();
            }
        }

hrmeasurment变量来自附加文件中的代码(项目添加文件);
HRMeasurese的读数总是0 ......
有任何想法吗?

谢谢。
Filipe Santos.

. untitled.png.
 

附件

  • 听到.zip
    3.3 KB · Views: 66

跳伞运动员

工作人员
加入
2019年4月6日
消息
2,893
地点
切萨皮克,va.
编程经验
10+
除非在该代码段的第3行上调用的构造函数呼叫不仅仅是构造一个空对象,否则为什么你期望0以外的任何值?换句话说,您是否知道该构造函数是否实际从蓝牙数据流读取?
 

Filipesantos.

成员
加入
2019年5月27日
消息
12
编程经验
1-3
是的跳伞运动员,了解你的观点。
我对C#的了解是杀了我...... :D.
心率服务文件有2个公共课程,但我认为的那个会给我一个人力资源价值观;"HeartRateService",不能从程序调用。错误说它受到保护,我没有为什么为什么。
您可以使用我的程序使用该文件,并管理控制台中的HR值吗?
谢谢你。

Filipe Santos.。
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
什么是确切的错误?如果您发布所讨论值的相对代码,也可能会有所帮助地从心率测量开始读取。

请在代码标签中发布代码,而不是附件,因为人们不太可能打扰下载它们。我已经为你提供了。
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage.Streams;

using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Devices.Enumeration.Pnp;

namespace BluetoothGattHeartRate
{
    public class HeartRateMeasurement
    {
        public ushort HeartRateValue { get; set; }
        public bool HasExpendedEnergy { get; set; }
        public ushort ExpendedEnergy { get; set; }
        public DateTimeOffset Timestamp { get; set; }

        public override string ToString()
        {
            return HeartRateValue.ToString() + " bpm @ " + Timestamp.ToString();
        }
    }

    public delegate void ValueChangeCompletedHandler(HeartRateMeasurement heartRateMeasurementValue);

    public delegate void DeviceConnectionUpdatedHandler(bool isConnected);

    public class HeartRateService
    {
        // Heart Rate Constants

        // The Characteristic we want to obtain measurements for is the Heart Rate Measurement characteristic
        private Guid CHARACTERISTIC_UUID = GattCharacteristicUuids.HeartRateMeasurement;
        // Heart Rate devices typically have only one Heart Rate Measurement characteristic.
        // Make sure to check your device's documentation to find out how many characteristics your specific device has.
        private const int CHARACTERISTIC_INDEX = 0;
        // The Heart Rate Profile specification requires that the Heart Rate Measurement characteristic is notifiable.
        private const GattClientCharacteristicConfigurationDescriptorValue CHARACTERISTIC_NOTIFICATION_TYPE =
            GattClientCharacteristicConfigurationDescriptorValue.Notify;

        // A pointer back to the main page.  This is needed if you want to call methods in MainPage such
        // as NotifyUser().
        //MainPage rootPage = MainPage.Current;

        private static readonly HeartRateService instance = new HeartRateService();
        private GattDeviceService service;
        private GattCharacteristic characteristic;
        private List<HeartRateMeasurement> datapoints;
        private PnpObjectWatcher watcher;
        private String deviceContainerId;

        public event ValueChangeCompletedHandler ValueChangeCompleted;
        public event DeviceConnectionUpdatedHandler DeviceConnectionUpdated;

        public static HeartRateService Instance
        {
            get { return instance; }
        }

        public bool IsServiceInitialized { get; set; }

        public GattDeviceService Service
        {
            get { return service; }
        }

        public HeartRateMeasurement[] DataPoints
        {
            get
            {
                HeartRateMeasurement[] retval;
                lock (datapoints)
                {
                    retval = datapoints.ToArray();
                }

                return retval;
            }
        }

        private HeartRateService()
        {
            datapoints = new List<HeartRateMeasurement>();
            //App.Current.Suspending += App_Suspending;
            //App.Current.Resuming += App_Resuming;
        }

        private void App_Resuming(object sender, object e)
        {
            // Since the Windows Runtime will close resources to the device when the app is suspended,
            // the device needs to be reinitialized when the app is resumed.
        }

        private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
        {
            IsServiceInitialized = false;

            // This is an appropriate place to save to persistent storage any datapoint the application cares about.
            // For the purpose of this sample we just discard any values.
            datapoints.Clear();

            // Allow the GattDeviceService to get cleaned up by the Windows Runtime.
            // The Windows runtime will clean up resources used by the GattDeviceService object when the application is
            // suspended. The GattDeviceService object will be invalid once the app resumes, which is why it must be
            // marked as invalid, and reinitalized when the application resumes.
            if (service != null)
            {
                service.Dispose();
                service = null;
            }

            if (characteristic != null)
            {
                characteristic = null;
            }

            if (watcher != null)
            {
                watcher.Stop();
                watcher = null;
            }
        }

        public async Task InitializeServiceAsync(DeviceInformation device)
        {
            try
            {
                deviceContainerId = "{" + device.Properties["System.Devices.ContainerId"] + "}";

                service = await GattDeviceService.FromIdAsync(device.Id);
                if (service != null)
                {
                    IsServiceInitialized = true;
                    await ConfigureServiceForNotificationsAsync();
                }
            }
            catch (Exception e)
            {
            }
        }
 

sh

众所周知的成员
加入
2018年9月5日
消息
1,982
编程经验
10+
C#:
        /// <summary>

        /// Configure the Bluetooth device to send notifications whenever the Characteristic value changes

        /// </summary>

        private async Task ConfigureServiceForNotificationsAsync()

        {

            try

            {

                // Obtain the characteristic for which notifications are to be received

                characteristic = service.GetCharacteristics(CHARACTERISTIC_UUID)[CHARACTERISTIC_INDEX];



                // While encryption is not required by all devices, if encryption is supported by the device,

                // it can be enabled by setting the ProtectionLevel property of the Characteristic object.

                // All subsequent operations on the characteristic will work over an encrypted link.

                characteristic.ProtectionLevel = GattProtectionLevel.EncryptionRequired;



                // Register the event handler for receiving notifications

                characteristic.ValueChanged += Characteristic_ValueChanged;



                // In order to avoid unnecessary communication with the device, determine if the device is already

                // correctly configured to send notifications.

                // By default ReadClientCharacteristicConfigurationDescriptorAsync will attempt to get the current

                // value from the system cache and communication with the device is not typically required.

                var currentDescriptorValue = await characteristic.ReadClientCharacteristicConfigurationDescriptorAsync();



                if ((currentDescriptorValue.Status != GattCommunicationStatus.Success) ||

                    (currentDescriptorValue.ClientCharacteristicConfigurationDescriptor != CHARACTERISTIC_NOTIFICATION_TYPE))

                {

                    // Set the Client Characteristic Configuration Descriptor to enable the device to send notifications

                    // when the Characteristic value changes

                    GattCommunicationStatus status =

                        await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(

                        CHARACTERISTIC_NOTIFICATION_TYPE);



                    if (status == GattCommunicationStatus.Unreachable)

                    {

                        // Register a PnpObjectWatcher to detect when a connection to the device is established,

                        // such that the application can retry device configuration.

                        StartDeviceConnectionWatcher();

                    }

                }

            }

            catch (Exception e)

            {

            }

        }



        /// <summary>

        /// Register to be notified when a connection is established to the Bluetooth device

        /// </summary>

        private void StartDeviceConnectionWatcher()

        {

            watcher = PnpObject.CreateWatcher(PnpObjectType.DeviceContainer,

                new string[] { "System.Devices.Connected" }, String.Empty);



            watcher.Updated += DeviceConnection_Updated;

            watcher.Start();

        }



        /// <summary>

        /// Invoked when a connection is established to the Bluetooth device

        /// </summary>

        /// <param name="sender">The watcher object that sent the notification</param>

        /// <param name="args">The updated device object properties</param>

        private async void DeviceConnection_Updated(PnpObjectWatcher sender, PnpObjectUpdate args)

        {

            var connectedProperty = args.Properties["System.Devices.Connected"];

            bool isConnected = false;

            if ((deviceContainerId == args.Id) && Boolean.TryParse(connectedProperty.ToString(), out isConnected) &&

                isConnected)

            {

                var status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(

                    CHARACTERISTIC_NOTIFICATION_TYPE);



                if (status == GattCommunicationStatus.Success)

                {

                    IsServiceInitialized = true;



                    // Once the Client Characteristic Configuration Descriptor is set, the watcher is no longer required

                    watcher.Stop();

                    watcher = null;

                }



                // Notifying subscribers of connection state updates

                if (DeviceConnectionUpdated != null)

                {

                    DeviceConnectionUpdated(isConnected);

                }

            }

        }



        /// <summary>

        /// Invoked when Windows receives data from your Bluetooth device.

        /// </summary>

        /// <param name="sender">The GattCharacteristic object whose value is received.</param>

        /// <param name="args">The new characteristic value sent by the device.</param>

        private void Characteristic_ValueChanged(

            GattCharacteristic sender,

            GattValueChangedEventArgs args)

        {

            var data = new byte[args.CharacteristicValue.Length];



            DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);



            // Process the raw data received from the device.

            var value = ProcessData(data);

            value.Timestamp = args.Timestamp;



            lock (datapoints)

            {

                datapoints.Add(value);

            }



            if (ValueChangeCompleted != null)

            {

                ValueChangeCompleted(value);

            }

        }



        /// <summary>

        /// Process the raw data received from the device into application usable data,

        /// according the the Bluetooth Heart Rate Profile.

        /// </summary>

        /// <param name="data">Raw data received from the heart rate monitor.</param>

        /// <returns>The heart rate measurement value.</returns>

        private HeartRateMeasurement ProcessData(byte[] data)

        {

            // Heart Rate profile defined flag values

            const byte HEART_RATE_VALUE_FORMAT = 0x01;

            const byte ENERGY_EXPANDED_STATUS = 0x08;



            byte currentOffset = 0;

            byte flags = data[currentOffset];

            bool isHeartRateValueSizeLong = ((flags & HEART_RATE_VALUE_FORMAT) != 0);

            bool hasEnergyExpended = ((flags & ENERGY_EXPANDED_STATUS) != 0);



            currentOffset++;



            ushort heartRateMeasurementValue = 0;

            if (isHeartRateValueSizeLong)

            {

                heartRateMeasurementValue = (ushort)((data[currentOffset + 1] << 8) + data[currentOffset]);

                currentOffset += 2;

            }

            else

            {

                heartRateMeasurementValue = data[currentOffset];

                currentOffset++;

            }



            // The Heart Rate Bluetooth profile can also contain sensor contact status information,

            // and R-Wave interval measurements, which can also be processed here.

            // For the purpose of this sample, we don't need to interpret that data.



            return new HeartRateMeasurement

            {

                HeartRateValue = heartRateMeasurementValue,

            };

        }

    }

}
由于1000个发布限制,我必须拆分文件。
 
最佳 底部