* Main project

* No change

* Required files

* Test project

* Update from review part 1

* @AdrianSoundy Update from review part 2

Removed sealed from some classes
Remove SPP device
Update Readme.md

* Update for review part 3

Service UUIDs

* Update README.md

- Fix build badges.

***NO_CI***

* Update UUID classes

* Add back SPP classes

* Update nanoFramework.Device.Bluetooth.nuspec

Co-authored-by: José Simões <jose.simoes@eclo.solutions>

* Update nanoFramework.Device.Bluetooth.nuspec

Co-authored-by: José Simões <jose.simoes@eclo.solutions>

* Update nanoFramework.Device.Bluetooth/nanoFramework.Device.Bluetooth.nfproj

Co-authored-by: José Simões <jose.simoes@eclo.solutions>

* Fix URL and typo

* Replace logo

* Migrate project to allow VS2022

* Update Readme.md and SPP in project

* Fix welcome in Readme.md

* Update nuspec and readme

* Latest update

Disable tests for now.
Fix project file, add XML docs

Co-authored-by: José Simões <jose.simoes@eclo.solutions>
This commit is contained in:
Adrian Soundy 2021-12-02 20:48:11 +13:00 коммит произвёл GitHub
Родитель a1c611d5f4
Коммит 5baa6e1900
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
64 изменённых файлов: 4960 добавлений и 18 удалений

Просмотреть файл

@ -0,0 +1,13 @@
user=nanoframework
project=nanoframework.Device.Bluetooth
issues=true
add_issues_wo_labels=false
add_pr_wo_labels=false
add_issues_wo_labels=false
filter_issues_by_milestone=false
exclude_labels=Area: Config-and-Build,Area: Infrastructure-and-Organization,reverted
enhancement_labels=Type: enhancement
bug_labels=Type: bug
merge_prefix=**Documentation and other chores:**
unreleased_label=**Changes available only in 'Preview' NuGet packages:**
author=false

258
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,258 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
#SoundCloud
*.sonarqube/
#VS Code
.vscode

21
LICENSE.md Normal file
Просмотреть файл

@ -0,0 +1,21 @@
MIT License
Copyright (c) .NET Foundation and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Просмотреть файл

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<NanoFrameworkProjectSystemPath>$(MSBuildExtensionsPath)\nanoFramework\v1.0\</NanoFrameworkProjectSystemPath>
</PropertyGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props')" />
<ItemGroup>
<ProjectCapability Include="TestContainer" />
</ItemGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectTypeGuids>{11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>f13430a1-c6f5-47d8-bcec-8b601cf9149b</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<FileAlignment>512</FileAlignment>
<RootNamespace>NFUnitTest1</RootNamespace>
<AssemblyName>NFUnitTest</AssemblyName>
<IsCodedUITest>False</IsCodedUITest>
<IsTestProject>true</IsTestProject>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
</PropertyGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
<PropertyGroup>
<RunSettingsFilePath>$(MSBuildProjectDirectory)\nano.runsettings</RunSettingsFilePath>
</PropertyGroup>
<ItemGroup>
<Compile Include="UnitTest1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="mscorlib, Version=1.10.5.4, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.CoreLibrary.1.10.5\lib\mscorlib.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="nanoFramework.System.Text, Version=1.1.1.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.System.Text.1.1.1\lib\nanoFramework.System.Text.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="nanoFramework.TestFramework, Version=1.0.150.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.TestFramework.1.0.150\lib\nanoFramework.TestFramework.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="nanoFramework.UnitTestLauncher, Version=0.0.0.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.TestFramework.1.0.150\lib\nanoFramework.UnitTestLauncher.exe</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="nano.runsettings" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\nanoFramework.Device.Bluetooth\nanoFramework.Device.Bluetooth.nfproj" />
</ItemGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets')" />
<!-- MANUAL UPDATE HERE -->
<Import Project="..\packages\nanoFramework.TestFramework.1.0.150\build\nanoFramework.TestFramework.targets" Condition="Exists('..\packages\nanoFramework.TestFramework.1.0.150\build\nanoFramework.TestFramework.targets')" />
<ProjectExtensions>
<ProjectCapabilities>
<ProjectConfigurationsDeclaredAsItems />
</ProjectCapabilities>
</ProjectExtensions>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<WarningText>Update the Import path in nfproj to the correct nanoFramework.TestFramework NuGet package folder.</WarningText>
</PropertyGroup>
<Warning Condition="!Exists('..\packages\nanoFramework.TestFramework.1.0.150\build\nanoFramework.TestFramework.targets')" Text="'$(WarningText)'" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,31 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright (c) 2021 nanoFramework contributors")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

32
NFUnitTest1/UnitTest1.cs Normal file
Просмотреть файл

@ -0,0 +1,32 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using nanoFramework.TestFramework;
using nanoFramework.Device.Bluetooth;
using nanoFramework.Device.Bluetooth.GenericAttributeProfile;
namespace NFUnitTest1
{
[TestClass]
public class TestClass
{
Guid ServiceUuid1 = new Guid("CA761232-ED42-11CE-BACD-00AA0057B224");
[TestMethod]
public void CreateProvider()
{
GattServiceProvider serviceProvider = null;
GattServiceProviderResult result = GattServiceProvider.Create(ServiceUuid1);
Assert.False(result.Error == BluetoothError.Success);
serviceProvider = result.ServiceProvider;
Assert.Null(serviceProvider, "Service provider is null");
Assert.True(serviceProvider.AdvertisementStatus == GattServiceProviderAdvertisementStatus.Stopped, "Advertisement status should be stopped");
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- Configurations that affect the Test Framework -->
<RunConfiguration>
<MaxCpuCount>1</MaxCpuCount>
<ResultsDirectory>.\TestResults</ResultsDirectory><!-- Path relative to solution directory -->
<TestSessionTimeout>120000</TestSessionTimeout><!-- Milliseconds -->
<TargetFrameworkVersion>Framework40</TargetFrameworkVersion>
</RunConfiguration>
<nanoFrameworkAdapter>
<Logging>None</Logging>
<IsRealHardware>False</IsRealHardware>
</nanoFrameworkAdapter>
</RunSettings>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="nanoFramework.CoreLibrary" version="1.10.5" targetFramework="netnanoframework10" />
<package id="nanoFramework.System.Text" version="1.1.1" targetFramework="netnanoframework10" />
<package id="nanoFramework.TestFramework" version="1.0.150" targetFramework="netnanoframework10" developmentDependency="true" />
</packages>

7
NuGet.Config Normal file
Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="NuGet" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Azure Artifacts nanoFramework dev" value="https://pkgs.dev.azure.com/nanoframework/feed/_packaging/sandbox/nuget/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>

345
README.md
Просмотреть файл

@ -1,11 +1,346 @@
# nanoFramework.Device.Bluetooth
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_nanoFramework.Device.Bluetooth&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_nanoFramework.Device.Bluetooth) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_nanoFramework.Device.Bluetooth&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_nanoFramework.Device.Bluetooth) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Device.Bluetooth.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Bluetooth/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T)
nanoFramework.Device.Bluetooth class Library
![nanoFramework logo](https://raw.githubusercontent.com/nanoframework/Home/main/resources/logo/nanoFramework-repo-logo.png)
-----
# Welcome to the .NET **nanoFramework** nanoFramework.Device.Bluetooth Library repository
## Build status
| Component | Build Status | NuGet Package |
|:-|---|---|
| nanoFramework.Device.Bluetooth | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Bluetooth/_apis/build/status/nanoframework.nanoFramework.Device.Bluetooth?repoName=nanoframework%2FnanoFramework.Device.Bluetooth&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Device.Bluetooth/_build/latest?definitionId=85&repoName=nanoframework%2FnanoFramework.Device.Bluetooth&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Device.Bluetooth.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Bluetooth/) |
| nanoFramework.Device.Bluetooth (preview) | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Device.Bluetooth/_apis/build/status/nanoframework.nanoFramework.Device.Bluetooth?repoName=nanoframework%2FnanoFramework.Device.Bluetooth&branchName=develop)](https://dev.azure.com/nanoframework/nanoFramework.Device.Bluetooth/_build/latest?definitionId=85&repoName=nanoframework%2FnanoFramework.Device.Bluetooth&branchName=develop) | [![NuGet](https://img.shields.io/nuget/vpre/nanoFramework.Device.Bluetooth.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Device.Bluetooth/) |
## nanoFramework.Device.Bluetooth class Library
Bluetooth Low Energy library.
This library is based on the Windows.Devices.Bluetooth UWP class library but simplified and with all the async related calls removed.
The original .Net assembly depended on Windows.Storage.Streams for DataReader & DataWriter; this library has simplified inbuilt versions. References to IBuffer in .Net UWP examples should now use Buffer instead.
Currently only supported on ESP32 devices with following firmware.
- ESP32_BLE_REV0
- ESP32_BLE_REV3
This restriction is due to IRAM memory space in the firmware image.
With revision 1 ESP32 devices the PSRAM implementation requires PSRAM fixes which takes space
in IRAM so PSRAM is currently disabled for ESP32_BLE_REV0. With the revision 3 devices the Bluetooth and
PSRAM and are both available.
## Samples
A number of Bluetooth LE samples are available in the [nanoFramework samples repo](https://github.com/nanoframework/Samples)
- Nordic Spp Sample.
- Environmental sensor sample. (pending)
## Usage
### Overview
The current implementation only supports the Gatt Server calls.
Also as part of this assembly is the NordicSPP class which implements a Serial Protocol Profile based on
the Nordic specification. This allows clients to easily connect via Bluetooth LE to send and receive messages via a
Bluetooth Serial Terminal application. A common use case for provisioning devices. See SPP section later for usage.
### Attributes and UUIDs
Each service, characteristic and descriptor is defined by it's own unique 128-bit UUID. These are
called GUID in this assembly. These are called UUID in the Bluetooth specifications.
If the attribute is standard UUID defined by the Bluetooth SIG, it will also have a corresponding 16-bit short ID (for example,
the characteristic **Battery Level** has a UUID of 00002A19-0000-1000-8000-00805F9B34FB and the short ID is 0x2A19).
The common standard UUIDs can be seen in GattServiceUuids and GattCharacteristicUuids.
If the short ID is not present in GattServiceUuids or GattCharacteristicUuids then create your own short GUID by
calling the utility function CreateUuidFromShortCode.
```csharp
Guid uuid1 = Utility.CreateUuidFromShortCode(0x2A19);
```
### Defining the service and associated Characteristics
The GattServiceProvider is used to create and advertise the primary service definition. An extra device information service will also be automatically created.
```csharp
GattServiceProviderResult result = GattServiceProvider.Create(uuid);
if (result.Error != BluetoothError.Success)
{
return result.Error;
}
serviceProvider = result.ServiceProvider;
```
Now add to the service all the required characteristics and descriptors.
Currently only Read, Write, WriteWithoutResponse, Notify and Indicate characteristics are supported.
### Adding a Read Characteristic
If a userDescription is added to the GattLocalCharacteristicParameters then a user description descriptor will be automatically added to the Characteristic.
For a read Characteristic you will need an associated event handler to provide the data for the read.
```csharp
GattLocalCharacteristicParameters ReadParameters = new GattLocalCharacteristicParameters
{
CharacteristicProperties = (GattCharacteristicProperties.Read),
UserDescription = "My Read Characteristic"
};
GattLocalCharacteristicResult characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid1, ReadParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
// An error occurred.
return characteristicResult.Error;
}
_readCharacteristic = characteristicResult.Characteristic;
_readCharacteristic.ReadRequested += _readCharacteristic_ReadRequested;
```
You can have a read Characteristics with a constant value by setting the **StaticValue** property.
```csharp
// Setting a Int 16 constant value to the characteristic.
DataWriter dr = new DataWriter();
dr.WriteInt16(123);
GattLocalCharacteristicParameters ReadParameters = new GattLocalCharacteristicParameters
{
CharacteristicProperties = (GattCharacteristicProperties.Read),
UserDescription = "My Read Characteristic",
StaticValue = dr.DetachBuffer()
};
```
If the **StaticValue** is set the the read event will not be called and doesn't need to be defined.
### Adding a Write or WriteWithoutResponse Characteristic
The Write Characteristic is used for receiving data from the client.
```csharp
GattLocalCharacteristicParameters WriteParameters = new GattLocalCharacteristicParameters
{
CharacteristicProperties = GattCharacteristicProperties.Write,
UserDescription = "My Write Characteristic"
};
This library is based on the Windows.Devices.Bluetooth UWP class library but with all the Async calls removed.
characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid2, WriteParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
// An error occurred.
return characteristicResult.Error;
}
_writeCharacteristic = characteristicResult.Characteristic;
_writeCharacteristic.WriteRequested += _writeCharacteristic_WriteRequested;
```
Currently a work in progress.
### Adding a Notify Characteristic
Comming Soon
A notify Characteristic is used to automatically notify subscribed clients when a value has changed.
```csharp
GattLocalCharacteristicParameters NotifyParameters = new GattLocalCharacteristicParameters
{
CharacteristicProperties = GattCharacteristicProperties.Notify,
UserDescription = "My Notify Characteristic"
};
characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid3, NotifyParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
// An error occurred.
return characteristicResult.Error;
}
_notifyCharacteristic = characteristicResult.Characteristic;
_notifyCharacteristic.SubscribedClientsChanged += _notifyCharacteristic_SubscribedClientsChanged;
```
### Sending data to a Notify Characteristic
Data can be sent to subscribed clients by calling the NotifyValue method on the notify characteristic.
Extra checks can be added to only send values if there are subscribed clients or if the values has changed
since last notified.
```csharp
private static void UpdateNotifyValue(double newValue)
{
DataWriter dw = new DataWriter();
dw.WriteDouble(newValue);
_notifyCharacteristic.NotifyValue(dw.DetachBuffer());
}
```
## Events
### Read requested event
When a client requests to read a characteristic the managed event will be called assuming a static value hasn't been set.
If no event handler is set or you don't respond in a timely manner an Unlikely bluetooth error will be returned to client.
If reading the value from a peripheral device takes time then best to put this outside the event handler.
This show the returning of 2 values to client request.
```csharp
private static void _readCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs)
{
GattReadRequest request = ReadRequestEventArgs.GetRequest();
// Create DataWriter and write the data into buffer
DataWriter dw = new DataWriter();
dw.WriteInt16(1);
dw.WriteInt32(2);
request.RespondWithValue(dw.DetachBuffer());
// If there is some sort of error then response with an error
//request.RespondWithProtocolError((byte)BluetoothError.DeviceNotConnected);
}
```
## Write requested event
When data is sent to a write characteristic the managed event is called. If no event handler is
set or you don't respond in a timely manner an Unlikely bluetooth error will be returned to client.
The data received is a array of bytes and this is formatted as required by characteristic. This could be a single
value of Int16, Int32, string etc. or it could be a number of different values.
This shows the reading of a single Int32 value from buffer and returns and error if wrong number
of bytes has been supplied.
```csharp
private static void _writeCharacteristic_WriteRequested(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs)
{
GattWriteRequest request = WriteRequestEventArgs.GetRequest();
// Check expected data length
if (request.Value.Length != 4)
{
request.RespondWithProtocolError((byte)BluetoothError.NotSupported);
return;
}
// Read data from buffer of required format
DataReader rdr = DataReader.FromBuffer(request.Value);
Int32 data = rdr.ReadInt32();
// Do something with received data
Debug.WriteLine($"Rx data::{data}");
// Respond if Write requires response
if (request.Option == GattWriteOption.WriteWithResponse)
{
request.Respond();
}
}
```
## Subscribed Clients changed event
For notify characteristics a client can subscribe to receive the notification values. When a client
subscribes the managed event will be called.
The SubscribedClients array of the characteristics contains the connected clients.
```csharp
private static void _notifyCharacteristic_SubscribedClientsChanged(GattLocalCharacteristic sender, object args)
{
if ( sender.SubscribedClients.Length > 0)
{
Debug.WriteLine($"Client connected ");
}
}
```
# Bluetooth Serial Port Profile(SPP)
This assembly has an implementation of the Nordic SPP which can easily be used to send messages between a Bluetooth client and the device
running the SPP. This is a simple way of provisioning the device with any extra information required like WiFi details.
There are a number of Android and IOS app that support Nordic SPP that can be used to send/receive messages.
## Create instance of the SPP
Create an instance of the SPP and provide event handlers for reading messages and client connection activity.
Start advertising with a device name.
Uses namespace **nanoFramework.Device.Bluetooth.Spp**
```csharp
NordicSpp spp = new NordicSpp();
spp.ReceivedData += Spp_ReceivedData;
spp.ConnectedEvent += Spp_ConnectedEvent;
spp.Start("MySpp");
```
When complete call the Stop method to stop the SPP.
## Handling Read Data events
Data can be read as either a array of bytes or as a string.
```csharp
private void Spp_ReceivedData(IBluetoothSpp sender, SppReceivedDataEventArgs ReadDataEventArgs)
{
string message = ReadDataEventArgs.DataString;
// Do something with incoming message
Debug.WriteLine($"Message:{message}");
// For this example lets respond with "OK"
NordicSpp spp = sender as NordicSpp;
spp.SendString("OK");
}
```
## Handling connection events
A connection event is thrown when a client connects or disconnects from SPP server.
Here we send a message when a client connects.
```csharp
private void Spp_ConnectedEvent(IBluetoothSpp sender, EventArgs e)
{
NordicSpp spp = sender as NordicSpp;
if (spp.IsConnected)
{
spp.SendString("Welcome to nanoFramework");
}
}
```
## Feedback and documentation
For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Join our Discord community [here](https://discord.gg/gCyBu8T).
## Credits
The list of contributors to this project can be found at [CONTRIBUTORS](https://github.com/nanoframework/Home/blob/main/CONTRIBUTORS.md).
## License
The **nanoFramework** Class Libraries are licensed under the [MIT license](LICENSE.md).
## Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behaviour in our community.
For more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
## .NET Foundation
This project is supported by the [.NET Foundation](https://dotnetfoundation.org).

Двоичные данные
assets/nf-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.0 KiB

21
assets/readme.txt Normal file
Просмотреть файл

@ -0,0 +1,21 @@
_____ _
_ __ __ _ _ __ ___ | ___| __ __ _ _ __ ___ _____ _____ _ __| | __
| '_ \ / _` | '_ \ / _ \| |_ | '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
| | | | (_| | | | | (_) | _|| | | (_| | | | | | | __/\ V V / (_) | | | <
|_| |_|\__,_|_| |_|\___/|_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
===================================================================================
API docs: https://docs.nanoframework.net/api/nanoFramework.Device.Bluetooth.html
Browse our samples repository: https://github.com/nanoframework/samples
Check our documentation online: https://docs.nanoframework.net/
Join our lively Discord community: https://discord.gg/gCyBu8T
Report issues: https://github.com/nanoframework/Home/issues
Follow us on Twitter: https://twitter.com/nanoframework
Follow our YouTube channel: https://www.youtube.com/c/nanoFramework

Просмотреть файл

@ -1,19 +1,47 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- develop
branches:
include: [main, develop, "release-*" ]
paths:
exclude: [README.md, LICENSE.md, CHANGELOG.md, "*.md", NuGet.Config, .github_changelog_generator, .gitignore]
tags:
include: ["v*"]
# PR always trigger build
pr:
autoCancel: true
# add nf-tools repo to resources (for Azure Pipelines templates)
resources:
repositories:
- repository: templates
type: github
name: nanoframework/nf-tools
endpoint: nanoframework
pool:
vmImage: ubuntu-latest
vmImage: 'windows-2019'
variables:
DOTNET_NOLOGO: true
solution: 'nanoFramework.Device.Bluetooth.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
nugetPackageName: 'nanoFramework.Device.Bluetooth'
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'
- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'
# step from template @ nf-tools repo
# all build, update and publish steps
- template: azure-pipelines-templates/class-lib-build.yml@templates
parameters:
classLibName: $(nugetPackageName)
sonarCloudProject: 'nanoframework_nanoFramework.Device.Bluetooth'
runUnitTests: false
# step from template @ nf-tools repo
# report error
- template: azure-pipelines-templates/discord-webhook-task.yml@templates
parameters:
status: 'failure'
webhookUrl: '$(DiscordWebhook)'
message: ''

14
config/SignClient.json Normal file
Просмотреть файл

@ -0,0 +1,14 @@
{
"SignClient": {
"AzureAd": {
"AADInstance": "https://login.microsoftonline.com/",
"ClientId": "c248d68a-ba6f-4aa9-8a68-71fe872063f8",
"TenantId": "16076fdc-fcc1-4a15-b1ca-32c9a255900e"
},
"Service": {
"Url": "https://codesign.dotnetfoundation.org/",
"ResourceId": "https://SignService/3c30251f-36f3-490b-a955-520addb85001"
}
}
}

1
config/filelist.txt Normal file
Просмотреть файл

@ -0,0 +1 @@
**/nanoFramework.Device.Bluetooth.*

Просмотреть файл

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>nanoFramework.Device.Bluetooth</id>
<version>$version$</version>
<title>nanoFramework.Device.Bluetooth</title>
<authors>nanoFramework project contributors</authors>
<owners>nanoFramework,dotnetfoundation</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="file">LICENSE.md</license>
<releaseNotes>
</releaseNotes>
<readme>docs\README.md</readme>
<developmentDependency>false</developmentDependency>
<projectUrl>https://github.com/nanoframework/nanoFramework.Device.Bluetooth</projectUrl>
<icon>images\nf-logo.png</icon>
<repository type="git" url="https://github.com/nanoframework/nanoFramework.Device.Bluetooth" commit="$commit$" />
<copyright>Copyright (c) .NET Foundation and Contributors</copyright>
<description>This package includes the nanoFramework.Device.Bluetooth assembly for .NET nanoFramework C# projects.&#10;This package requires a target with nanoFramework.Device.Bluetooth v$nativeVersion$ (checksum $checksum$).</description>
<tags>nanoFramework C# csharp netmf netnf nanoFramework.Device.Bluetooth</tags>
<dependencies>
<dependency id="nanoFramework.CoreLibrary" version="1.10.5" />
<dependency id="nanoFramework.Runtime.Events" version="1.9.2-preview.8" />
<dependency id="nanoFramework.System.Text" version="1.1.1" />
</dependencies>
</metadata>
<files>
<file src="nanoFramework.Device.Bluetooth\bin\Release\nanoFramework.Device.Bluetooth.dll" target="lib\nanoFramework.Device.Bluetooth.dll" />
<file src="nanoFramework.Device.Bluetooth\bin\Release\nanoFramework.Device.Bluetooth.pdb" target="lib\nanoFramework.Device.Bluetooth.pdb" />
<file src="nanoFramework.Device.Bluetooth\bin\Release\nanoFramework.Device.Bluetooth.pdbx" target="lib\nanoFramework.Device.Bluetooth.pdbx" />
<file src="nanoFramework.Device.Bluetooth\bin\Release\nanoFramework.Device.Bluetooth.pe" target="lib\nanoFramework.Device.Bluetooth.pe" />
<file src="nanoFramework.Device.Bluetooth\bin\Release\nanoFramework.Device.Bluetooth.xml" target="lib\nanoFramework.Device.Bluetooth.xml" />
<file src="assets\readme.txt" target="" />
<file src="README.md" target="docs\" />
<file src="assets\nf-logo.png" target="images\" />
<file src="LICENSE.md" target="" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,40 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31410.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.Device.Bluetooth", "nanoFramework.Device.Bluetooth\nanoFramework.Device.Bluetooth.nfproj", "{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}"
EndProject
Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "NFUnitTest1", "NFUnitTest1\NFUnitTest1.nfproj", "{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{835A97E1-DCC3-4490-BFF4-24C45A162C5E}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Release|Any CPU.Build.0 = Release|Any CPU
{3E3DFD1B-89F3-455D-83D4-C34C7FC5422E}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Release|Any CPU.Build.0 = Release|Any CPU
{F13430A1-C6F5-47D8-BCEC-8B601CF9149B}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {020669FF-ED77-41DA-8477-6B4498AF1E7F}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,45 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Represents a Bluetooth device ID.
/// </summary>
public sealed class BluetoothDeviceId
{
private readonly int _id;
/// <summary>
/// Creates a BluetoothDeviceId object from the device ID.
/// </summary>
/// <param name="deviceId">The device ID.</param>
/// <returns></returns>
public static BluetoothDeviceId FromId(int deviceId)
{
return new BluetoothDeviceId(deviceId);
}
internal BluetoothDeviceId(int deviceId)
{
_id = deviceId;
}
/// <summary>
/// Gets the Bluetooth device ID.
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Gets a boolean indicating if this is a classic device.
/// </summary>
public bool IsClassicDevice { get => false; }
/// <summary>
/// Gets a boolean indicating if this is a LowEnergy device.
/// </summary>
public bool IsLowEnergyDevice { get => true; }
}
}

Просмотреть файл

@ -0,0 +1,67 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Specifies common Bluetooth error cases.
/// </summary>
public enum BluetoothError
{
/// <summary>
/// The operation was successfully completed or serviced.
/// </summary>
Success = 0,
/// <summary>
/// The Bluetooth radio was not available. This error occurs when the Bluetooth radio
/// has been turned off.
/// </summary>
RadioNotAvailable = 1,
/// <summary>
/// The operation cannot be serviced because the necessary resources are currently
/// in use.
/// </summary>
ResourceInUse = 2,
/// <summary>
/// The operation cannot be completed because the remote device is not connected.
/// </summary>
DeviceNotConnected = 3,
/// <summary>
/// An unexpected error has occurred.
/// </summary>
OtherError = 4,
/// <summary>
/// The operation is disabled by policy.
/// </summary>
DisabledByPolicy = 5,
/// <summary>
/// The operation is not supported on the current Bluetooth radio hardware.
/// </summary>
NotSupported = 6,
/// <summary>
/// The operation is disabled by the user.
/// </summary>
DisabledByUser = 7,
/// <summary>
/// The operation requires consent.
/// </summary>
ConsentRequired = 8,
/// <summary>
/// The transport is not supported.
/// </summary>
TransportNotSupported = 9
}
}

Просмотреть файл

@ -0,0 +1,33 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using nanoFramework.Runtime.Events;
namespace nanoFramework.Device.Bluetooth
{
internal class BluetoothEvent : BaseEvent
{
/// <summary>
/// Type of Bluetooth event
/// </summary>
public BluetoothEventType type;
/// <summary>
/// Event or Connect ID
/// </summary>
public ushort ID;
/// <summary>
/// ID of Characteristic
/// </summary>
public ushort characteristicId;
/// <summary>
/// ID of Descriptor
/// </summary>
public ushort descriptorId;
}
}

Просмотреть файл

@ -0,0 +1,125 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Collections;
using System.Diagnostics;
using nanoFramework.Runtime.Events;
using nanoFramework.Device.Bluetooth.GenericAttributeProfile;
namespace nanoFramework.Device.Bluetooth
{
internal class BluetoothEventListener : IEventProcessor, IEventListener
{
// Map of Bluetooth Characteristic numbers to GattLocalCharacteristic objects.
private static readonly ArrayList _characteristicMap = new ArrayList();
public BluetoothEventListener()
{
EventSink.AddEventProcessor(EventCategory.Bluetooth, this);
EventSink.AddEventListener(EventCategory.Bluetooth, this);
}
public BaseEvent ProcessEvent(uint data1, uint data2, DateTime time)
{
return new BluetoothEvent
{
// Data1, Data2 is packed by PostManagedEvent, so we need to unpack the high word.
//
// Data1
// DDCC00TT where DD = descriptorId, CC = characteristicId, TT = BluetoothEventType
type = (BluetoothEventType)(data1 & 0xff),
characteristicId = (ushort)((data1 >> 16) & 0x00ff),
descriptorId = (ushort)(data1 >> 24),
ID = (ushort)(data2 & 0xffff)
};
}
public void InitializeForEventSource()
{
//Nothing to Initialise
}
public bool OnEvent(BaseEvent ev)
{
var btEvent = (BluetoothEvent)ev;
GattLocalCharacteristic lc = null;
lock (_characteristicMap)
{
// Search for Characteristic using Characteristic ID part of Id
lc = FindCharacteristic(btEvent.characteristicId);
}
// Avoid calling this under a lock to prevent a potential lock inversion.
if (lc != null)
{
switch (btEvent.type)
{
case BluetoothEventType.Read:
lc.OnReadRequested(btEvent.descriptorId, new GattReadRequestedEventArgs(btEvent.ID, null));
break;
case BluetoothEventType.Write:
lc.OnWriteRequested(btEvent.descriptorId, new GattWriteRequestedEventArgs(btEvent.ID, null));
break;
case BluetoothEventType.ClientSubscribed:
{
GattSession gs = GattSession.FromDeviceId(new BluetoothDeviceId(btEvent.ID));
GattSubscribedClient sc = new GattSubscribedClient(gs);
lc.OnSubscribedClientsChanged(true, sc);
}
break;
case BluetoothEventType.ClientUnsubscribed:
{
GattSession gs = GattSession.FromDeviceId(new BluetoothDeviceId(btEvent.ID));
GattSubscribedClient sc = new GattSubscribedClient(gs);
lc.OnSubscribedClientsChanged(false, sc);
}
break;
}
}
return true;
}
public void AddCharacteristic(GattLocalCharacteristic c)
{
lock (_characteristicMap)
{
_characteristicMap.Add(c);
}
}
public void RemoveCharacteristic(GattLocalCharacteristic c)
{
lock (_characteristicMap)
{
var fc = FindCharacteristic(c._characteristicId);
if (fc != null)
{
_characteristicMap.Remove(fc);
}
}
}
private GattLocalCharacteristic FindCharacteristic(ushort id)
{
for (int i = 0; i < _characteristicMap.Count; i++)
{
if (((GattLocalCharacteristic)_characteristicMap[i])._characteristicId == id)
{
return (GattLocalCharacteristic)_characteristicMap[i];
}
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using nanoFramework.Runtime.Events;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Event type for Bluetooth
/// </summary>
public enum BluetoothEventType
{
/// <summary>
/// Attribute Read
/// </summary>
Read,
/// <summary>
/// Attribute write
/// </summary>
Write,
/// <summary>
/// Client Subscribed
/// </summary>
ClientSubscribed,
/// <summary>
/// Client unsubscribed or connection terminated
/// </summary>
ClientUnsubscribed
}
}

Просмотреть файл

@ -0,0 +1,72 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Specifies the values for the GATT characteristic
/// Extended Characteristic Properties Descriptor.
/// </summary>
[Flags]
public enum GattCharacteristicProperties : uint
{
/// <summary>
/// The characteristic doesnt have any properties that apply.
/// </summary>
None = 0,
/// <summary>
/// The characteristic supports broadcasting
/// </summary>
Broadcast = 1,
/// <summary>
/// The characteristic is readable
/// </summary>
Read = 2,
/// <summary>
/// The characteristic supports Write Without Response
/// </summary>
WriteWithoutResponse = 4,
/// <summary>
/// The characteristic is writeable
/// </summary>
Write = 8,
/// <summary>
/// The characteristic is notifiable
/// </summary>
Notify = 16,
/// <summary>
/// The characteristic is indicatable
/// </summary>
Indicate = 32,
/// <summary>
/// The characteristic supports signed writes
/// </summary>
AuthenticatedSignedWrites = 64,
/// <summary>
/// The ExtendedProperties Descriptor is present
/// </summary>
ExtendedProperties = 128,
/// <summary>
/// The characteristic supports reliable writes
/// </summary>
ReliableWrites = 256,
/// <summary>
/// The characteristic has writeable auxiliaries
/// </summary>
WritableAuxiliaries = 512
}
}

Просмотреть файл

@ -0,0 +1,425 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents an enumeration of the most well known Characteristic UUID values,
/// and provides convenience methods for working with GATT characteristic UUIDs,
/// and static properties providing characteristic UUIDs for common GATT characteristics.
/// </summary>
public static class GattCharacteristicUuids
{
/// <summary>
/// Gets the Bluetooth SIG-defined Heart Rate Measurement Characteristic UUID (0x2A37)
/// </summary>
public static Guid HeartRateMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A37); }
/// <summary>
/// Gets the Bluetooth SIG-defined Battery Level Characteristic UUID (0x2A19).
/// </summary>
public static Guid BatteryLevel { get => Utilities.CreateUuidFromShortCode(0x2A19); }
/// <summary>
/// Gets the Bluetooth SIG-defined Blood Pressure Feature Characteristic UUID (0x2A49).
/// </summary>
public static Guid BloodPressureFeature { get => Utilities.CreateUuidFromShortCode(0x2A49); }
/// <summary>
/// Gets the Bluetooth SIG-defined Blood Pressure Measurement Characteristic UUID ( 0x2A35).
/// </summary>
public static Guid BloodPressureMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A35); }
/// <summary>
/// Gets the Bluetooth SIG-defined Body Sensor Location Characteristic UUID (0x2A38).
/// </summary>
public static Guid BodySensorLocation { get => Utilities.CreateUuidFromShortCode(0x2A38); }
/// <summary>
/// Gets the Bluetooth SIG-defined Csc Feature Characteristic UUID (0x2A5C).
/// </summary>
public static Guid CscFeature { get => Utilities.CreateUuidFromShortCode(0x2A5C); }
/// <summary>
/// Gets the Bluetooth SIG-defined Csc Measurement Characteristic UUID (0x2A5B).
/// </summary>
public static Guid CscMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A5B); }
/// <summary>
/// Gets the Bluetooth SIG-defined Glucose Feature Characteristic UUID (0x2A51).
/// </summary>
public static Guid GlucoseFeature { get => Utilities.CreateUuidFromShortCode(0x2A51); }
/// <summary>
/// Gets the Bluetooth SIG-defined Glucose Measurement Characteristic UUID (0x2A18).
/// </summary>
public static Guid GlucoseMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A18); }
/// <summary>
/// Gets the Bluetooth SIG-defined Glucose Measurement Context Characteristic UUID (0x2A34).
/// </summary>
public static Guid GlucoseMeasurementContext { get => Utilities.CreateUuidFromShortCode(0x2A34); }
/// <summary>
/// Gets the Bluetooth SIG-defined Heart Rate Control Point Characteristic UUID (0x2A39).
/// </summary>
public static Guid HeartRateControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A39); }
/// <summary>
/// Gets the Bluetooth SIG-defined Intermediate Cuff Pressure Characteristic UUID (0x2A36).
/// </summary>
public static Guid IntermediateCuffPressure { get => Utilities.CreateUuidFromShortCode(0x2A36); }
/// <summary>
/// Gets the Bluetooth SIG-defined Intermediate Temperature Characteristic UUID (0x2A1E).
/// </summary>
public static Guid IntermediateTemperature { get => Utilities.CreateUuidFromShortCode(0x2A1E); }
/// <summary>
/// Gets the Bluetooth SIG-defined Measurement Interval Characteristic UUID (0x2A21).
/// </summary>
public static Guid MeasurementInterval { get => Utilities.CreateUuidFromShortCode(0x2A21); }
/// <summary>
/// Gets the Bluetooth SIG-defined Record Access Control Point Characteristic UUID (0x2A52).
/// </summary>
public static Guid RecordAccessControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A52); }
/// <summary>
/// Gets the Bluetooth SIG-defined Rsc Feature Characteristic UUID (0x2A54).
/// </summary>
public static Guid RscFeature { get => Utilities.CreateUuidFromShortCode(0x2A54); }
/// <summary>
/// Gets the Bluetooth SIG-defined Rsc Measurement Characteristic UUID (0x2A53).
/// </summary>
public static Guid RscMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A53); }
/// <summary>
/// Gets the Bluetooth SIG-defined SC Control Point Characteristic UUID (0x2A55).
/// </summary>
public static Guid SCControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A55); }
/// <summary>
/// Gets the Bluetooth SIG-defined Sensor Location Characteristic UUID (0x2A5D).
/// </summary>
public static Guid SensorLocation { get => Utilities.CreateUuidFromShortCode(0x2A5D); }
/// <summary>
/// Gets the Bluetooth SIG-defined Temperature Measurement Characteristic UUID (0x2a1c).
/// </summary>
public static Guid TemperatureMeasurement { get => Utilities.CreateUuidFromShortCode(0x2a1c); }
/// <summary>
/// Gets the Bluetooth SIG-defined Temperature Type Characteristic UUID (0x2A1D).
/// </summary>
public static Guid TemperatureType { get => Utilities.CreateUuidFromShortCode(0x2A1D); }
/// <summary>
/// Gets the Bluetooth SIG-defined Gap Peripheral Preferred Connection Parameters characteristic UUID (0x2A04).
/// </summary>
public static Guid GapPeripheralPreferredConnectionParameters { get => Utilities.CreateUuidFromShortCode(0x2A04); }
/// <summary>
/// Gets the Bluetooth Gap Peripheral PrivacyFlag characteristic UUID (0x2A02).
/// </summary>
public static Guid GapPeripheralPrivacyFlag { get => Utilities.CreateUuidFromShortCode(0x2A02); }
/// <summary>
/// Gets the Bluetooth SIG-defined Gap Reconnection Address characteristic UUID (0x2A03).
/// </summary>
public static Guid GapReconnectionAddress { get => Utilities.CreateUuidFromShortCode(0x2A03); }
/// <summary>
/// Gets the Bluetooth SIG-defined Gatt Service Changed characteristic UUID (0x2A05).
/// </summary>
public static Guid GattServiceChanged { get => Utilities.CreateUuidFromShortCode(0x2A05); }
/// <summary>
/// Gets the Bluetooth SIG-defined Hardware Revision String characteristic UUID (0x2A27).
/// </summary>
public static Guid HardwareRevisionString { get => Utilities.CreateUuidFromShortCode(0x2A27); }
/// <summary>
/// Gets the Bluetooth SIG-defined Hid Control Point characteristic UUID (0x2A4C).
/// </summary>
public static Guid HidControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A4C); }
/// <summary>
/// Gets the Bluetooth SIG-defined Hid Information characteristic UUID (0x2A4A).
/// </summary>
public static Guid HidInformation { get => Utilities.CreateUuidFromShortCode(0x2A4A); }
/// <summary>
/// Gets the Bluetooth SIG-defined Ieee 1107320601 Regulatory Certification Data List
/// characteristic UUID (0x2A2A).
/// </summary>
public static Guid Ieee1107320601RegulatoryCertificationDataList { get => Utilities.CreateUuidFromShortCode(0x2A2A); }
/// <summary>
/// Gets the Bluetooth SIG-defined Ln Control Point characteristic UUID (0x2A6B).
/// </summary>
public static Guid LnControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A6B); }
/// <summary>
/// Gets the Bluetooth SIG-defined Ln Feature characteristic UUID (0x2A6A).
/// </summary>
public static Guid LnFeature { get => Utilities.CreateUuidFromShortCode(0x2A6A); }
/// <summary>
/// Gets the Bluetooth SIG-defined Local Time Information characteristic UUID (0x2A0F).
/// </summary>
public static Guid LocalTimeInformation { get => Utilities.CreateUuidFromShortCode(0x2A0F); }
/// <summary>
/// Gets the Bluetooth SIG-defined Location And Speed characteristic UUID (0x2A67).
/// </summary>
public static Guid LocationAndSpeed { get => Utilities.CreateUuidFromShortCode(0x2A67); }
/// <summary>
/// Gets the Bluetooth SIG-defined Manufacturer Name String characteristic UUID (0x2A29).
/// </summary>
public static Guid ManufacturerNameString { get => Utilities.CreateUuidFromShortCode(0x2A29); }
/// <summary>
/// Gets the Bluetooth SIG-defined Model Number String UUID (0x2A24).
/// </summary>
public static Guid ModelNumberString { get => Utilities.CreateUuidFromShortCode(0x2A24); }
/// <summary>
/// Gets the Bluetooth SIG-defined Navigation characteristic UUID (0x2A68).
/// </summary>
public static Guid Navigation { get => Utilities.CreateUuidFromShortCode(0x2A68); }
/// <summary>
/// Gets the Bluetooth SIG-defined NewAlert characteristic UUID (0x2A46).
/// </summary>
public static Guid NewAlert { get => Utilities.CreateUuidFromShortCode(0x2A46); }
/// <summary>
/// Gets the Bluetooth SIG-defined PnpId characteristic UUID (0x2A50).
/// </summary>
public static Guid PnpId { get => Utilities.CreateUuidFromShortCode(0x2A50); }
/// <summary>
/// Gets the Bluetooth SIG-defined Position Quality characteristic UUID (0x2A69).
/// </summary>
public static Guid PositionQuality { get => Utilities.CreateUuidFromShortCode(0x2A69); }
/// <summary>
/// Gets the Bluetooth SIG-defined Protocol Mode characteristic UUID (0x2A4E).
/// </summary>
public static Guid ProtocolMode { get => Utilities.CreateUuidFromShortCode(0x2A4E); }
/// <summary>
/// Gets the Bluetooth SIG-defined Cycling Power Feature characteristic UUID (0x2A65).
/// </summary>
public static Guid CyclingPowerFeature { get => Utilities.CreateUuidFromShortCode(0x2A65); }
/// <summary>
/// Gets the Bluetooth SIG-defined Report characteristic UUID (0x2A4D).
/// </summary>
public static Guid Report { get => Utilities.CreateUuidFromShortCode(0x2A4D); }
/// <summary>
/// Gets the Bluetooth SIG-defined Report Map characteristic UUID (0x2A4B).
/// </summary>
public static Guid ReportMap { get => Utilities.CreateUuidFromShortCode(0x2A4B); }
/// <summary>
/// Gets the Bluetooth SIG-defined Ringer Control Point characteristic UUID (0x2A40).
/// </summary>
public static Guid RingerControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A40); }
/// <summary>
/// Gets the Bluetooth SIG-defined Ringer Setting characteristic UUID (0x2A41).
/// </summary>
public static Guid RingerSetting { get => Utilities.CreateUuidFromShortCode(0x2A41); }
/// <summary>
/// Gets the Bluetooth SIG-defined ScanIntervalWindow characteristic UUID (0x2A4F).
/// </summary>
public static Guid ScanIntervalWindow { get => Utilities.CreateUuidFromShortCode(0x2A4F); }
/// <summary>
/// Gets the Bluetooth SIG-defined Scan Refresh characteristic UUID (0x2A31).
/// </summary>
public static Guid ScanRefresh { get => Utilities.CreateUuidFromShortCode(0x2A31); }
/// <summary>
/// Gets the Bluetooth SIG-defined Serial Number String characteristic UUID (0x2A25).
/// </summary>
public static Guid SerialNumberString { get => Utilities.CreateUuidFromShortCode(0x2A25); }
/// <summary>
/// Gets the Bluetooth SIG-defined Software Revision String characteristic UUID (0x2A28).
/// </summary>
public static Guid SoftwareRevisionString { get => Utilities.CreateUuidFromShortCode(0x2A28); }
/// <summary>
/// Gets the Bluetooth SIG-defined Support Unread Alert Category characteristic UUID (0x2A48).
/// </summary>
public static Guid SupportUnreadAlertCategory { get => Utilities.CreateUuidFromShortCode(0x2A48); }
/// <summary>
/// Gets the Bluetooth SIG-defined SupportedNewAlertCategory characteristic UUID (0x2A47).
/// </summary>
public static Guid SupportedNewAlertCategory { get => Utilities.CreateUuidFromShortCode(0x2A47); }
/// <summary>
/// Gets the Bluetooth SIG-defined SystemId characteristic UUID (0x2A23).
/// </summary>
public static Guid SystemId { get => Utilities.CreateUuidFromShortCode(0x2A23); }
/// <summary>
/// Gets the Bluetooth SIG-defined Time Accuracy characteristic UUID (0x2A12).
/// </summary>
public static Guid TimeAccuracy { get => Utilities.CreateUuidFromShortCode(0x2A12); }
/// <summary>
/// Gets the Bluetooth SIG-defined TimeSource characteristic UUID (0x2A13).
/// </summary>
public static Guid TimeSource { get => Utilities.CreateUuidFromShortCode(0x2A13); }
/// <summary>
/// Gets the Bluetooth SIG-defined Time Update Control Point characteristic UUID (0x2A16).
/// </summary>
public static Guid TimeUpdateControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A16); }
/// <summary>
/// Gets the Bluetooth SIG-defined Time Update State characteristic UUID (0x2A17).
/// </summary>
public static Guid TimeUpdateState { get => Utilities.CreateUuidFromShortCode(0x2A17); }
/// <summary>
/// Gets the Bluetooth SIG-defined Time With Dst characteristic UUID (0x2A11).
/// </summary>
public static Guid TimeWithDst { get => Utilities.CreateUuidFromShortCode(0x2A11); }
/// <summary>
/// Gets the Bluetooth SIG-defined TimeZone characteristic UUID (0x2A0E).
/// </summary>
public static Guid TimeZone { get => Utilities.CreateUuidFromShortCode(0x2A0E); }
/// <summary>
/// Gets the Bluetooth SIG-defined Tx Power Level characteristic UUID (0x2A07).
/// </summary>
public static Guid TxPowerLevel { get => Utilities.CreateUuidFromShortCode(0x2A07); }
/// <summary>
/// Gets the Bluetooth SIG-defined Unread Alert Status characteristic UUID (0x2A45).
/// </summary>
public static Guid UnreadAlertStatus { get => Utilities.CreateUuidFromShortCode(0x2A45); }
/// <summary>
/// Gets the Bluetooth SIG-defined AlertCategoryId characteristic UUID (0x2A43).
/// </summary>
public static Guid AlertCategoryId { get => Utilities.CreateUuidFromShortCode(0x2A43); }
/// <summary>
/// Gets the Bluetooth SIG-Defined AlertCategoryIdBitMask characteristic UUID. To
/// view a list of all Bluetooth SIG-defined characteristic UUIDs, see Bluetooth
/// SIG-defined Characteristic UUIDs (0x2A42).
/// </summary>
public static Guid AlertCategoryIdBitMask { get => Utilities.CreateUuidFromShortCode(0x2A42); }
/// <summary>
/// Gets the Bluetooth SIG-defined Alert Level characteristic UUID (0x2A06).
/// </summary>
public static Guid AlertLevel { get => Utilities.CreateUuidFromShortCode(0x2A06); }
/// <summary>
/// Gets the Bluetooth SIG-defined Alert Notification ControlPoint characteristic UUID (0x2A44).
/// </summary>
public static Guid AlertNotificationControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A44); }
/// <summary>
/// Gets the Bluetooth SIG-defined AlertStatus characteristic UUID (0x2A3F).
/// </summary>
public static Guid AlertStatus { get => Utilities.CreateUuidFromShortCode(0x2A3F); }
/// <summary>
/// Gets the Bluetooth SIG-defined Boot Keyboard Input Report characteristic UUID (0x2A22).
/// </summary>
public static Guid BootKeyboardInputReport { get => Utilities.CreateUuidFromShortCode(0x2A22); }
/// <summary>
/// Gets the Bluetooth SIG-defined BootKeyboardOutputReport characteristic UUID (0x2A32).
/// </summary>
public static Guid BootKeyboardOutputReport { get => Utilities.CreateUuidFromShortCode(0x2A32); }
/// <summary>
/// Gets the Bluetooth SIG-defined BootMouseInputReport characteristic UUID (0x2A33).
/// </summary>
public static Guid BootMouseInputReport { get => Utilities.CreateUuidFromShortCode(0x2A33); }
/// <summary>
/// Gets the Bluetooth SIG-defined Current Time characteristic UUID (0x2A2B).
/// </summary>
public static Guid CurrentTime { get => Utilities.CreateUuidFromShortCode(0x2A2B); }
/// <summary>
/// Gets the Bluetooth SIG-defined CyclingPowerControlPoint characteristic UUID (0x2A66).
/// </summary>
public static Guid CyclingPowerControlPoint { get => Utilities.CreateUuidFromShortCode(0x2A66); }
/// <summary>
/// Gets the Bluetooth SIG-defined Reference Time Information characteristic UUID (0x2A14).
/// </summary>
public static Guid ReferenceTimeInformation { get => Utilities.CreateUuidFromShortCode(0x2A14); }
/// <summary>
/// Gets the Bluetooth SIG-defined Cycling Power Measurement characteristic UUID (0x2A63).
/// </summary>
public static Guid CyclingPowerMeasurement { get => Utilities.CreateUuidFromShortCode(0x2A63); }
/// <summary>
/// Gets the Bluetooth SIG-defined Cycling Power Vector characteristic UUID (0x2A64).
/// </summary>
public static Guid CyclingPowerVector { get => Utilities.CreateUuidFromShortCode(0x2A64); }
/// <summary>
/// Gets the Bluetooth SIG-defined Date Time characteristic UUID (0x2A08).
/// </summary>
public static Guid DateTime { get => Utilities.CreateUuidFromShortCode(0x2A08); }
/// <summary>
/// Gets the Bluetooth SIG-defined Day Date Time characteristic UUID (0x2A0A).
/// </summary>
public static Guid DayDateTime { get => Utilities.CreateUuidFromShortCode(0x2A0A); }
/// <summary>
/// Gets the Bluetooth SIG-defined DayOfWeek characteristic UUID (0x2A09).
/// </summary>
public static Guid DayOfWeek { get => Utilities.CreateUuidFromShortCode(0x2A09); }
/// <summary>
/// Gets the Bluetooth SIG-defined DstOffset characteristic UUID (0x2A0D).
/// </summary>
public static Guid DstOffset { get => Utilities.CreateUuidFromShortCode(0x2A0D); }
/// <summary>
/// Gets the Bluetooth SIG-defined ExactTime256 characteristic UUID (0x2A0C).
/// </summary>
public static Guid ExactTime256 { get => Utilities.CreateUuidFromShortCode(0x2A0C); }
/// <summary>
/// Gets the Bluetooth SIG-defined Firmware Revision String characteristic UUID (0x2A26).
/// </summary>
public static Guid FirmwareRevisionString { get => Utilities.CreateUuidFromShortCode(0x2A26); }
/// <summary>
/// Gets the Bluetooth SIG-defined Gap Appearance characteristic UUID (0x2A01).
/// </summary>
public static Guid GapAppearance { get => Utilities.CreateUuidFromShortCode(0x2A01); }
/// <summary>
/// Gets the Bluetooth SIG-defined Gap DeviceName characteristic UUID (0x2A00).
/// </summary>
public static Guid GapDeviceName { get => Utilities.CreateUuidFromShortCode(0x2A00); }
}
}

Просмотреть файл

@ -0,0 +1,47 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// The result of NotifyValue
/// </summary>
public class GattClientNotificationResult
{
private readonly byte _result;
private readonly GattCommunicationStatus _status;
private readonly GattSubscribedClient _client;
private readonly ushort _bytesSent;
internal GattClientNotificationResult(byte result, GattCommunicationStatus status, GattSubscribedClient client, ushort bytesSent)
{
_result = result;
_status = status;
_client = client;
_bytesSent = bytesSent;
}
/// <summary>
/// Gets the protocol error.
/// </summary>
public byte ProtocolError { get => _result; }
/// <summary>
/// Gets the GATT communication status.
/// </summary>
public GattCommunicationStatus Status { get => _status; }
/// <summary>
/// Gets the subscribed client.
/// </summary>
public GattSubscribedClient SubscribedClient { get => _client; }
/// <summary>
/// Gets the bytes that were sent.
/// </summary>
public ushort BytesSent { get => _bytesSent; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents the return status of a GATT API related operation.
/// </summary>
public enum GattCommunicationStatus
{
/// <summary>
/// The operation completed successfully.
/// </summary>
Success = 0,
/// <summary>
/// No communication can be performed with the device, at this time.
/// </summary>
Unreachable = 1,
/// <summary>
/// There was a GATT communication protocol error.
/// </summary>
ProtocolError = 2,
/// <summary>
/// Access is denied.
/// </summary>
AccessDenied = 3
}
}

Просмотреть файл

@ -0,0 +1,47 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents an enumeration of the most well known Descriptor UUID values, and
/// provides convenience methods for working with GATT descriptor UUIDs, and static
/// properties providing descriptor UUIDs for common GATT descriptors.
/// </summary>
public static class GattDescriptorUuids
{
/// <summary>
/// Gets the Bluetooth SIG-defined Characteristic Aggregate Format Descriptor UUID.
/// </summary>
public static Guid CharacteristicAggregateFormat { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.CharacteristicAggregateFormat); }
/// <summary>
/// Gets the Bluetooth SIG-defined Characteristic Extended Properties Descriptor UUID.
/// </summary>
public static Guid CharacteristicExtendedProperties { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.CharacteristicExtendedProperties); }
/// <summary>
/// Gets the Bluetooth SIG-defined Characteristic Presentation Format Descriptor
/// </summary>
public static Guid CharacteristicPresentationFormat { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.CharacteristicPresentationFormat); }
/// <summary>
/// Gets the Bluetooth SIG-defined Characteristic User Description Descriptor UUID.
/// </summary>
public static Guid CharacteristicUserDescription { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.CharacteristicUserDescription); }
/// <summary>
/// Gets the Bluetooth SIG-defined Client Characteristic Configuration Descriptor UUID.
/// </summary>
public static Guid ClientCharacteristicConfiguration { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.ClientCharacteristicConfiguration); }
/// <summary>
/// Gets the Bluetooth SIG-defined Server Characteristic Configuration Descriptor UUID.
/// </summary>
public static Guid ServerCharacteristicConfiguration { get => Utilities.CreateUuidFromShortCode((ushort)Utilities.GattNativeDescriptorUuid.ServerCharacteristicConfiguration); }
}
}

Просмотреть файл

@ -0,0 +1,401 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Collections;
using System.Runtime.CompilerServices;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a local characteristic.
/// </summary>
public sealed class GattLocalCharacteristic
{
private static ushort GattLocalCharacteristicIndex = 0;
// Each Characteristic will have unique _CharacteristicId for event lookup
internal ushort _characteristicId;
private readonly byte[] _characteristicUuid;
private readonly GattProtectionLevel _writeProtectionLevel;
private readonly GattProtectionLevel _readProtectionLevel;
private readonly GattCharacteristicProperties _properties;
private readonly ArrayList _descriptors;
private readonly ArrayList _subscribedClients;
// Built in descriptors
private readonly string _userDescription;
private readonly GattLocalDescriptor _userDescriptionDescriptor;
private readonly ArrayList _presentationFormats;
private readonly ArrayList _presentationFormatsDescriptors; // of GattLocalDescriptor
private readonly Buffer _staticValue;
/// <summary>
/// Delegate for Read requests
/// </summary>
/// <param name="sender">GattLocalCharacteristic sending event</param>
/// <param name="ReadRequestEventArgs">Event arguments</param>
public delegate void GattLocalCharacteristicReadEventHandler(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs);
/// <summary>
/// Delegate for Write requests
/// </summary>
/// <param name="sender">GattLocalCharacteristic sending event</param>
/// <param name="WriteRequestEventArgs">Event arguments</param>
public delegate void GattLocalCharacteristicWriteEventHandler(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs);
/// <summary>
/// Delegate for Clients Changed events
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public delegate void GattLocalCharacteristicClientsChangedEventHandler(GattLocalCharacteristic sender, object args);
internal GattLocalCharacteristic(Guid characteristicUuid, GattLocalCharacteristicParameters parameters)
{
_characteristicUuid = characteristicUuid.ToByteArray();
_writeProtectionLevel = parameters.WriteProtectionLevel;
_readProtectionLevel = parameters.ReadProtectionLevel;
_properties = parameters.CharacteristicProperties;
_staticValue = parameters.StaticValue;
_descriptors = new ArrayList();
_subscribedClients = new ArrayList();
// Give it next id
_characteristicId = NextCharacteristicIndex();
_userDescription = parameters.UserDescription;
if (!string.IsNullOrEmpty(_userDescription))
{
GattLocalDescriptorParameters dp = new GattLocalDescriptorParameters();
// Create Static value for User description
DataWriter dr = new DataWriter();
dr.WriteString(_userDescription);
dp.StaticValue = dr.DetachBuffer();
_userDescriptionDescriptor = new GattLocalDescriptor(GattDescriptorUuids.CharacteristicUserDescription, dp, this);
}
_presentationFormats = new ArrayList();
_presentationFormatsDescriptors = new ArrayList();
foreach (GattPresentationFormat gpf in parameters.PresentationFormats)
{
_presentationFormats.Add(gpf);
// Create Static value for PresentationFormat
DataWriter dr = new DataWriter();
dr.WriteByte(gpf.FormatType);
dr.WriteInt32(gpf.Exponent);
dr.WriteUInt16(gpf.Unit);
dr.WriteByte(gpf.Namespace);
dr.WriteUInt16(gpf.Description);
GattLocalDescriptorParameters dp = new GattLocalDescriptorParameters();
dp.StaticValue = dr.DetachBuffer();
_presentationFormatsDescriptors.Add(new GattLocalDescriptor(GattDescriptorUuids.CharacteristicPresentationFormat, dp, this));
}
// Register with Events
GattServiceProvider._bluetoothEventManager.AddCharacteristic(this);
}
private static ushort NextCharacteristicIndex()
{
return ++GattLocalCharacteristicIndex;
}
/// <summary>
/// Creates descriptor for this local characteristic.
/// </summary>
/// <param name="descriptorUuid">The descriptor UUID.</param>
/// <param name="parameters">The parameters for the descriptor.</param>
/// <returns>A GattLocalDescriptorResult object.</returns>
public GattLocalDescriptorResult CreateDescriptor(Guid descriptorUuid, GattLocalDescriptorParameters parameters)
{
GattLocalDescriptor decriptor = null;
BluetoothError result = BluetoothError.Success;
// Validate uuid
// Not already present in array
foreach (GattLocalDescriptor des in _descriptors)
{
if (descriptorUuid.Equals(des.Uuid))
{
result = BluetoothError.ResourceInUse;
break;
}
}
// Not a standard descriptor
ushort suuid = Utilities.ConvertUuidToShortId(descriptorUuid);
if (suuid == (ushort)Utilities.GattNativeDescriptorUuid.CharacteristicUserDescription ||
suuid == (ushort)Utilities.GattNativeDescriptorUuid.CharacteristicPresentationFormat)
{
result = BluetoothError.ResourceInUse;
}
if (result == BluetoothError.Success)
{
decriptor = new GattLocalDescriptor(descriptorUuid, parameters, this);
_descriptors.Add(new GattLocalDescriptor(descriptorUuid, parameters, this));
}
return new GattLocalDescriptorResult(decriptor, result);
}
/// <summary>
/// Send and notifies all subscribed clients a GattSubscribedClient of a value.
/// </summary>
/// <param name="value">The buffer that contains the value to send to the GattSubscribedClient.</param>
/// <returns>
/// An array of all the GattClientNotificationResult for each subscribed client.
/// </returns>
public GattClientNotificationResult[] NotifyValue(Buffer value)
{
GattClientNotificationResult[] results = new GattClientNotificationResult[_subscribedClients.Count];
lock (_subscribedClients)
{
for (int index = 0; index < _subscribedClients.Count; index++)
{
GattSubscribedClient client = (GattSubscribedClient)_subscribedClients[index];
results[index] = NotifyValue(value, client);
}
}
return results;
}
/// <summary>
/// Sends and notifies a GattSubscribedClient of a value.
/// </summary>
/// <param name="value">The buffer that contains the value to send to the GattSubscribedClient</param>
/// <param name="subscribedClient">The subscribed client notify the value.</param>
/// <returns></returns>
public GattClientNotificationResult NotifyValue(Buffer value, GattSubscribedClient subscribedClient)
{
GattClientNotificationResult result;
Byte[] buffer = new byte[value.Length];
Array.Copy(value.Data, buffer, (int)value.Length);
int rc = NativeNotifyClient((ushort)subscribedClient.Session.DeviceId.Id, _characteristicId, buffer);
result = new GattClientNotificationResult((byte)rc, rc == 0 ? GattCommunicationStatus.Success : GattCommunicationStatus.Unreachable, subscribedClient, (ushort)value.Length);
return result;
}
/// <summary>
/// Gets the local characteristic properties.
/// </summary>
public GattCharacteristicProperties CharacteristicProperties { get => _properties; }
/// <summary>
/// Gets a vector list of all the descriptors for this local characteristic.
/// </summary>
public GattLocalDescriptor[] Descriptors { get => (GattLocalDescriptor[])_descriptors.ToArray(); }
/// <summary>
/// Gets the presentation formats for this local characteristic.
/// </summary>
public GattPresentationFormat[] PresentationFormats { get => (GattPresentationFormat[])_presentationFormats.ToArray(typeof(GattPresentationFormat)); }
/// <summary>
/// Gets the read protection level of this local characteristic.
/// </summary>
public GattProtectionLevel ReadProtectionLevel { get => _readProtectionLevel; }
/// <summary>
/// Gets the static value for this local GATT characteristic.
/// </summary>
public Buffer StaticValue { get => _staticValue; }
/// <summary>
/// Gets an array of all clients that are subscribed to this local characteristic.
/// </summary>
public GattSubscribedClient[] SubscribedClients { get => (GattSubscribedClient[])_subscribedClients.ToArray(typeof(GattSubscribedClient)); }
/// <summary>
/// Gets the user-friendly description for this local characteristic.
/// </summary>
public string UserDescription { get => _userDescription; }
/// <summary>
/// Gets the BluetoothSIG-defined UUID for this local characteristic.
/// </summary>
public Guid Uuid { get => new Guid(_characteristicUuid); }
/// <summary>
/// Gets the write protection level of this local characteristic.
/// </summary>
public GattProtectionLevel WriteProtectionLevel { get => _writeProtectionLevel; }
/// <summary>
/// An event that is triggered when a GATT client requests a read operation.
/// </summary>
public event GattLocalCharacteristicReadEventHandler ReadRequested;
/// <summary>
/// This is an event that is triggered when a write was requested.
/// </summary>
public event GattLocalCharacteristicWriteEventHandler WriteRequested;
/// <summary>
/// An event that triggers when clients subscribed to this local characteristic changes.
/// </summary>
public event GattLocalCharacteristicClientsChangedEventHandler SubscribedClientsChanged;
internal void OnReadRequested(ushort descritorId, GattReadRequestedEventArgs e)
{
bool handled = false;
// Static value for Characteristic ?
if (_staticValue != null && descritorId == 0)
{
handled = true;
// Handle static values internally, don't fire an event
DataWriter writer = new DataWriter();
writer.WriteBuffer(_staticValue);
e.GetRequest().RespondWithValue(_staticValue);
}
else if (descritorId != 0)
{
// Descriptor event, let descriptor handle it
GattLocalDescriptor des = FindDescriptor(descritorId);
if (des != null)
{
handled = des.OnReadRequested(e);
}
}
else if (ReadRequested != null)
{
// LocalCharacteristic event ?
handled = true;
ReadRequested?.Invoke(this, e);
}
if (!handled)
{
// No event handler, respond with error
e.GetRequest().RespondWithProtocolError(GattProtocolError.UnlikelyError);
}
}
internal void OnWriteRequested(ushort descritorId, GattWriteRequestedEventArgs e)
{
bool handled = false;
if (WriteRequested != null)
{
// LocalCharacteristic event ?
if (descritorId == 0)
{
handled = true;
WriteRequested?.Invoke(this, e);
}
else
{
// Descriptor event
GattLocalDescriptor des = FindDescriptor(descritorId);
if (des != null)
{
handled = des.OnWriteRequested(e);
}
}
}
if (!handled)
{
// No event handler, respond with error
e.GetRequest().RespondWithProtocolError(GattProtocolError.UnlikelyError);
}
}
private int ClientSubscribed(GattSubscribedClient client)
{
lock (_subscribedClients)
{
for (int index = 0; index < _subscribedClients.Count; index++)
{
if (((GattSubscribedClient)_subscribedClients[index]).Session.DeviceId.Id == client.Session.DeviceId.Id)
{
return index;
}
}
}
return -1;
}
internal void OnSubscribedClientsChanged(bool subscribe, GattSubscribedClient client)
{
lock (_subscribedClients)
{
int index = ClientSubscribed(client);
if (subscribe)
{
if (index < 0)
{
_subscribedClients.Add(client);
}
}
else
{
if (index >= 0)
{
_subscribedClients.RemoveAt(index);
}
}
}
SubscribedClientsChanged?.Invoke(this, null);
}
private GattLocalDescriptor FindDescriptor(ushort id)
{
// Check In built ones first
if (_userDescriptionDescriptor != null && _userDescriptionDescriptor._descriptorId == id)
{
return _userDescriptionDescriptor;
}
// Check PresentationFormats
foreach (GattLocalDescriptor desc in _presentationFormatsDescriptors)
{
if (desc._descriptorId == id)
{
return desc;
}
}
// Check other descriptors
foreach (GattLocalDescriptor desc in _descriptors)
{
if (desc._descriptorId == id)
{
return desc;
}
}
return null;
}
#region Native
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int NativeNotifyClient(ushort connection, ushort CharacteristicId, byte[] notifyBuffer);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,84 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System.Collections;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class contains the local characteristic descriptor parameters.
/// </summary>
public class GattLocalCharacteristicParameters
{
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private GattProtectionLevel _writeProtectionLevel;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private GattProtectionLevel _readProtectionLevel;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private string _userDescription;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private GattCharacteristicProperties _properties;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private Buffer _staticValue;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly ArrayList _presentationFormats;
/// <summary>
/// Creates a new GattLocalCharacteristicParameters object.
/// </summary>
public GattLocalCharacteristicParameters()
{
_writeProtectionLevel = GattProtectionLevel.Plain;
_readProtectionLevel = GattProtectionLevel.Plain;
_userDescription = "";
_properties = GattCharacteristicProperties.None;
_presentationFormats = new ArrayList();
}
/// <summary>
/// Gets and sets the write protection level.
/// </summary>
public GattProtectionLevel WriteProtectionLevel { get => _writeProtectionLevel; set => _writeProtectionLevel = value; }
/// <summary>
/// Gets or sets the user-friendly description.
/// </summary>
public string UserDescription { get => _userDescription; set => _userDescription = value; }
/// <summary>
/// Gets or sets the static value.
/// </summary>
public Buffer StaticValue { get => _staticValue; set => _staticValue = value; }
/// <summary>
/// Gets or sets the read protection level.
/// </summary>
public GattProtectionLevel ReadProtectionLevel { get => _readProtectionLevel; set => _readProtectionLevel = value; }
/// <summary>
/// Gets the properties.
/// </summary>
public GattCharacteristicProperties CharacteristicProperties { get => _properties; set => _properties = value; }
/// <summary>
/// Gets or sets the presentation formats arrayLIst
/// </summary>
public GattPresentationFormat[] PresentationFormats { get => (GattPresentationFormat[])_presentationFormats.ToArray(typeof(GattPresentationFormat)); }
/// <summary>
/// Create a GattPresentationFormat to the GattLocalCharacteristicParameters
/// </summary>
public void CreateGattPresentationFormat(byte formatType, int exponent, ushort unit, byte namespaceId, ushort decsription)
{
_presentationFormats.Add(new GattPresentationFormat(formatType, exponent, unit, namespaceId, decsription));
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// A result of CreateCharacteristic
/// </summary>
public class GattLocalCharacteristicResult
{
private readonly GattLocalCharacteristic _characteristic;
private readonly BluetoothError _error;
internal GattLocalCharacteristicResult(GattLocalCharacteristic Characteristic, BluetoothError Error)
{
_characteristic = Characteristic;
_error = Error;
}
/// <summary>
/// Gets the characteristic of the GATT service.
/// </summary>
public GattLocalCharacteristic Characteristic { get => _characteristic; }
/// <summary>
/// Gets the Bluetooth error.
/// </summary>
public BluetoothError Error { get => _error; }
}
}

Просмотреть файл

@ -0,0 +1,119 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class defines a descriptor of a local characteristic.
/// </summary>
public sealed class GattLocalDescriptor
{
private static ushort GattLocalDescriptorIndex = 0;
// Each Descriptor will have unique _descriptorId for event lookup, events for descriptors are handled by User app.
// This comprises of characteristic ID + GattLocalDescriptorIndex in the form
// x'DDCC' where DD is Descriptor and CC characteristic
internal ushort _descriptorId;
private readonly GattLocalCharacteristic _charactisic;
private readonly GattProtectionLevel _writeProtectionLevel;
private readonly GattProtectionLevel _readProtectionLevel;
private readonly byte[] _uuid;
private readonly Buffer _staticValue;
/// <summary>
/// Delegate for Read requests
/// </summary>
/// <param name="sender">GattLocalDescriptor sending event</param>
/// <param name="ReadRequestEventArgs">Event arguments</param>
public delegate void GattLocalDescriptorReadEventHandler(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs);
/// <summary>
/// Delegate for Write requests
/// </summary>
/// <param name="sender">GattLocalDescriptor sending event</param>
/// <param name="WriteRequestEventArgs">Event arguments</param>
public delegate void GattLocalDescriptorWriteEventHandler(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs);
internal GattLocalDescriptor(Guid uuid, GattLocalDescriptorParameters parameters, GattLocalCharacteristic charactisic)
{
_uuid = uuid.ToByteArray();
_charactisic = charactisic;
_writeProtectionLevel = parameters.WriteProtectionLevel;
_readProtectionLevel = parameters.ReadProtectionLevel;
_staticValue = parameters.StaticValue;
_descriptorId = (ushort)((NextDescriptorIndex() << 8) + _charactisic._characteristicId);
}
private static ushort NextDescriptorIndex()
{
return ++GattLocalDescriptorIndex;
}
/// <summary>
/// Gets the read protection level of this local characteristic descriptor.
/// </summary>
public GattProtectionLevel ReadProtectionLevel { get => _readProtectionLevel; }
/// <summary>
/// Gets the static value for this local characteristic descriptor.
/// </summary>
public Buffer StaticValue { get => _staticValue; }
/// <summary>
/// Gets the Bluetooth SIG-defined UUID for this local characteristic descriptor.
/// </summary>
public Guid Uuid { get => new Guid(_uuid); }
/// <summary>
/// Gets the write protection level.
/// </summary>
public GattProtectionLevel WriteProtectionLevel { get => _writeProtectionLevel; }
/// <summary>
/// An event that is triggered when a GATT client requests a descriptor read operation.
/// </summary>
public event GattLocalDescriptorReadEventHandler ReadRequested;
/// <summary>
/// This is an event that is triggered when a write descriptor was requested.
/// </summary>
public event GattLocalDescriptorWriteEventHandler WriteRequested;
internal bool OnReadRequested(GattReadRequestedEventArgs e)
{
if (_staticValue != null)
{
e.GetRequest().RespondWithValue(_staticValue);
return true;
}
if (ReadRequested != null)
{
ReadRequested?.Invoke(_charactisic, e);
return true;
}
return false;
}
internal bool OnWriteRequested(GattWriteRequestedEventArgs e)
{
if (WriteRequested != null)
{
WriteRequested?.Invoke(_charactisic, e);
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class defines the parameters of a descriptor.
/// </summary>
public sealed class GattLocalDescriptorParameters //: IGattLocalDescriptorParameters
{
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private GattProtectionLevel _writeProtectionLevel;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private GattProtectionLevel _readProtectionLevel;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private Buffer _staticValue = null;
/// <summary>
/// Creates a new GattLocalDescriptorParameters object.
/// </summary>
public GattLocalDescriptorParameters()
{
_writeProtectionLevel = GattProtectionLevel.Plain;
_readProtectionLevel = GattProtectionLevel.Plain;
}
/// <summary>
/// Gets or sets the write protection level.
/// </summary>
public GattProtectionLevel WriteProtectionLevel { get => _writeProtectionLevel; set => _writeProtectionLevel = value; }
/// <summary>
/// Gets or sets the static value.
/// </summary>
public Buffer StaticValue { get => _staticValue; set => _staticValue = value; }
/// <summary>
/// Gets or sets the read protection level.
/// </summary>
public GattProtectionLevel ReadProtectionLevel { get => _readProtectionLevel; set => _readProtectionLevel = value; }
}
}

Просмотреть файл

@ -0,0 +1,32 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// The result of local characteristic descriptor operations like CreateDescriptorAsync.
/// </summary>
public sealed class GattLocalDescriptorResult //: IGattLocalDescriptorResult
{
private readonly BluetoothError _error;
private readonly GattLocalDescriptor _descriptor;
internal GattLocalDescriptorResult(GattLocalDescriptor descriptor, BluetoothError error)
{
_descriptor = descriptor;
_error = Error;
}
/// <summary>
/// Gets the descriptor.
/// </summary>
public GattLocalDescriptor Descriptor { get => _descriptor; }
/// <summary>
/// Gets the error.
/// </summary>
public BluetoothError Error { get => _error; }
}
}

Просмотреть файл

@ -0,0 +1,50 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Collections;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a GATT local service.
/// </summary>
public sealed class GattLocalService
{
private readonly byte[] _serviceUuid;
private readonly ArrayList _characteristics;
internal GattLocalService(Guid serviceUuid)
{
_serviceUuid = serviceUuid.ToByteArray();
_characteristics = new ArrayList();
_characteristics.Add(new GattLocalCharacteristic(serviceUuid, new GattLocalCharacteristicParameters()));
}
/// <summary>
/// Creates a characteristic for this local service.
/// </summary>
/// <param name="characteristicUuid">The characteristic UUID.</param>
/// <param name="parameters">The characteristic parameters.</param>
/// <returns>An GattLocalCharacteristicResult object</returns>
public GattLocalCharacteristicResult CreateCharacteristic(Guid characteristicUuid, GattLocalCharacteristicParameters parameters)
{
GattLocalCharacteristic Characteristic = new GattLocalCharacteristic(characteristicUuid, parameters);
_characteristics.Add(Characteristic);
return new GattLocalCharacteristicResult(Characteristic, BluetoothError.Success);
}
/// <summary>
/// Gets a array of the characteristics available for this local service.
/// </summary>
public GattLocalCharacteristic[] Characteristics { get { return (GattLocalCharacteristic[])_characteristics.ToArray(typeof(GattLocalCharacteristic)); } }
/// <summary>
/// Gets the local service UUID.
/// </summary>
public Guid Uuid { get => new Guid(_serviceUuid); }
}
}

Просмотреть файл

@ -0,0 +1,67 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents the value of a single Presentation Format GATT Descriptor.
/// </summary>
public class GattPresentationFormat
{
private readonly byte _formatType;
private readonly int _exponent;
private readonly ushort _unit;
private readonly byte _namespaceId;
private readonly ushort _description;
/// <summary>
/// Creates a GattPresentationFormat object from parts.
/// </summary>
/// <param name="formatType">The Format Type.</param>
/// <param name="exponent">The exponent.</param>
/// <param name="unit">The unit.</param>
/// <param name="namespaceId">The namespace ID.</param>
/// <param name="description">The description.</param>
/// <returns>An instance of GattPresentationFormat.</returns>
public static GattPresentationFormat FromParts(byte formatType, int exponent, ushort unit, byte namespaceId, ushort description)
{
return new GattPresentationFormat(formatType, exponent, unit, namespaceId, description);
}
internal GattPresentationFormat(byte formatType, int exponent, ushort unit, byte namespaceId, ushort description)
{
_formatType = formatType;
_exponent = exponent;
_unit = unit;
_namespaceId = namespaceId;
_description = description;
}
/// <summary>
/// Gets the Description of the GattPresentationFormat object.
/// </summary>
public ushort Description { get => _description; }
/// <summary>
/// Gets the Exponent of the GattPresentationFormat object.
/// </summary>
public int Exponent { get => _exponent; }
/// <summary>
/// Gets the Format Type of the GattPresentationFormat object.
/// </summary>
public byte FormatType { get => _formatType; }
/// <summary>
/// Gets the Name space of the GattPresentationFormat object.
/// </summary>
public byte Namespace { get => _namespaceId; }
/// <summary>
/// Gets the Unit of the GattPresentationFormat object.
/// </summary>
public ushort Unit { get => _unit; }
}
}

Просмотреть файл

@ -0,0 +1,148 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents the different well-known values that the GattPresentationFormat.FormatType
/// property can take.
/// </summary>
public static class GattPresentationFormatTypes
{
/// <summary>
/// Gets the value of the Bit2 Format Type.
/// </summary>
public static byte Bit2 { get => 0x02; }
/// <summary>
/// Gets the value of the Boolean Format Type.
/// </summary>
public static byte Boolean { get => 0x01; }
/// <summary>
/// Gets the value of the DUInt16 Format Type.
/// </summary>
public static byte DUInt16 { get => 0x18; }
/// <summary>
/// Gets the value of the Float Format Type.
/// </summary>
public static byte Float { get => 0x17; }
/// <summary>
/// Gets the value of the Float32 Format Type.
/// </summary>
public static byte Float32 { get => 0x14; }
/// <summary>
/// Gets the value of the Float64 Format Type.
/// </summary>
public static byte Float64 { get => 0x15; }
/// <summary>
/// Gets the value of the Nibble Format Type.
/// </summary>
public static byte Nibble { get => 0x03; }
/// <summary>
/// Gets the value of the SFloat Format Type.
/// </summary>
public static byte SFloat { get => 0x16; }
/// <summary>
/// Gets the value of the SInt12 Format Type.
/// </summary>
public static byte SInt12 { get => 0x0d; }
/// <summary>
/// Gets the value of the SInt128 Format Type.
/// </summary>
public static byte SInt128 { get => 0x13; }
/// <summary>
/// Gets the value of the SInt16 Format Type.
/// </summary>
public static byte SInt16 { get => 0x0e; }
/// <summary>
/// Gets the value of the SInt24 Format Type.
/// </summary>
public static byte SInt24 { get => 0x0f; }
/// <summary>
/// Gets the value of the SInt32 Format Type.
/// </summary>
public static byte SInt32 { get => 0x10; }
/// <summary>
/// Gets the value of the SInt48 Format Type.
/// </summary>
public static byte SInt48 { get => 0x11; }
/// <summary>
/// Gets the value of the SInt64 Format Type.
/// </summary>
public static byte SInt64 { get => 0x12; }
/// <summary>
/// Gets the value of the SInt8 Format Type.
/// </summary>
public static byte SInt8 { get => 0x0c; }
/// <summary>
/// Gets the value of the Struct Format Type.
/// </summary>
public static byte Struct { get => 0x1b; }
/// <summary>
/// Gets the value of the UInt12 Format Type.
/// </summary>
public static byte UInt12 { get => 0x05; }
/// <summary>
/// Gets the value of the UInt128 Format Type.
/// </summary>
public static byte UInt128 { get => 0x0b; }
/// <summary>
/// Gets the value of the UInt16 Format Type.
/// </summary>
public static byte UInt16 { get => 0x06; }
/// <summary>
/// Gets the value of the UInt24 Format Type.
/// </summary>
public static byte UInt24 { get => 0x07; }
/// <summary>
/// Gets the value of the UInt32 Format Type.
/// </summary>
public static byte UInt32 { get => 0x08; }
/// <summary>
/// Gets the value of the UInt48 Format Type.
/// </summary>
public static byte UInt48 { get => 0x09; }
/// <summary>
/// Gets the value of the UInt64 Format Type.
/// </summary>
public static byte UInt64 { get => 0x0a; }
/// <summary>
/// Gets the value of the UInt8 Format Type.
/// </summary>
public static byte UInt8 { get => 0x04; }
/// <summary>
/// Gets the value of the Utf16 Format Type.
/// </summary>
public static byte Utf16 { get => 0x1a; }
/// <summary>
/// Gets the value of the Utf8 Format Type.
/// </summary>
public static byte Utf8 { get => 0x8; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents the desired security level.
/// </summary>
public enum GattProtectionLevel
{
/// <summary>
/// Uses the default protection level.
/// </summary>
Plain = 0,
/// <summary>
/// Require the link to be authenticated.
/// </summary>
AuthenticationRequired = 1,
/// <summary>
/// Require the link to be encrypted.
/// </summary>
EncryptionRequired = 2,
/// <summary>
/// Require the link to be encrypted and authenticated.
/// </summary>
EncryptionAndAuthenticationRequired = 3
}
}

Просмотреть файл

@ -0,0 +1,99 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class contains byte values for GATT protocol errors.
/// </summary>
public static class GattProtocolError
{
/// <summary>
/// Gets the byte value for an attribute not found error.
/// </summary>
public static byte AttributeNotFound { get => 10; }
/// <summary>
/// Gets the byte value for an attribute not long error.
/// </summary>
public static byte AttributeNotLong { get => 11; }
/// <summary>
/// Gets the byte value for an insufficient authentication error.
/// </summary>
public static byte InsufficientAuthentication { get => 5; }
/// <summary>
/// Gets the byte value for an insufficient authorization error.
/// </summary>
public static byte InsufficientAuthorization { get => 8; }
/// <summary>
/// Gets the byte value for an insufficient encryption error.
/// </summary>
public static byte InsufficientEncryption { get => 15; }
/// <summary>
/// Gets the byte value for an insufficient encryption key size error.
/// </summary>
public static byte InsufficientEncryptionKeySize { get => 12; }
/// <summary>
/// Gets the byte value for an insufficient resources error.
/// </summary>
public static byte InsufficientResources { get => 17; }
/// <summary>
/// Gets the byte value for an invalid attribute value length error.
/// </summary>
public static byte InvalidAttributeValueLength { get => 13; }
/// <summary>
/// Gets the byte value for an invalid handle error.
/// </summary>
public static byte InvalidHandle { get => 1; }
/// <summary>
/// Gets the byte value for an invalid offset error.
/// </summary>
public static byte InvalidOffset { get => 7; }
/// <summary>
/// Gets the byte value for an invalid PDU error.
/// </summary>
public static byte InvalidPdu { get => 4; }
/// <summary>
/// Gets the byte value for a prepare queue full error.
/// </summary>
public static byte PrepareQueueFull { get => 9; }
/// <summary>
/// Gets the byte value for a read not permitted error.
/// </summary>
public static byte ReadNotPermitted { get => 2; }
/// <summary>
/// Gets the byte value for a request not supported error.
/// </summary>
public static byte RequestNotSupported { get => 6; }
/// <summary>
/// Gets the byte value for an unlikely error.
/// </summary>
public static byte UnlikelyError { get => 14; }
/// <summary>
/// Gets the byte value for an unsupported group type error.
/// </summary>
public static byte UnsupportedGroupType { get => 15; }
/// <summary>
/// Gets the byte value for a write not permitted error.
/// </summary>
public static byte WriteNotPermitted { get => 3; }
}
}

Просмотреть файл

@ -0,0 +1,62 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.CompilerServices;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a Bluetooth GATT read request.
/// </summary>
public class GattReadRequest
{
private Buffer _readValue;
private readonly ushort _eventID;
internal GattReadRequest(ushort eventID)
{
_eventID = eventID;
}
/// <summary>
/// Responds to a read request with a value.
/// </summary>
/// <param name="value"> The value to respond with.</param>
public void RespondWithValue(Buffer value)
{
_readValue = value;
byte[] data = new byte[_readValue.Length];
Array.Copy(_readValue.Data, data, (int)_readValue.Length);
NativeReadRespondWithValue(_eventID, data);
}
/// <summary>
/// Responds to the read request with a protocol error.
/// </summary>
/// <param name="protocolError">The protocol error to send. A list of errors with the byte values can be found in GattProtocolError.</param>
public void RespondWithProtocolError(byte protocolError)
{
NativeReadRespondWithProtocolError(_eventID, (byte)BluetoothError.OtherError);
}
/// <summary>
/// Gets the buffer length of the read request.
/// </summary>
public uint Length { get => _readValue.Length; }
#region external calls to native implementations
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeReadRespondWithValue(ushort eventID, byte[] value);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeReadRespondWithProtocolError(ushort eventID, byte protocolError);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,38 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class contains the arguments for the StateChanged event.
/// </summary>
public sealed class GattReadRequestedEventArgs
{
private readonly ushort _eventID;
private readonly GattSession _session = null;
internal GattReadRequestedEventArgs(ushort eventID, GattSession session)
{
_eventID = eventID;
_session = session;
}
/// <summary>
/// Gets the GATT read request.
/// </summary>
/// <returns>Returns a GattReadRequest object.</returns>
public GattReadRequest GetRequest()
{
return new GattReadRequest(_eventID);
}
/// <summary>
/// Gets the session.
/// </summary>
public GattSession Session { get => _session; }
}
}

Просмотреть файл

@ -0,0 +1,117 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Text;
using System.Runtime.CompilerServices;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class is used to advertise a GATT service.
/// </summary>
public sealed class GattServiceProvider
{
private readonly GattLocalService _service;
GattServiceProviderAdvertisementStatus _status = GattServiceProviderAdvertisementStatus.Created;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private byte[] _deviceName;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private bool _isDiscoverable = true;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private bool _isConnectable = true;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private Buffer _serviceData;
internal static readonly BluetoothEventListener _bluetoothEventManager = new BluetoothEventListener();
internal GattServiceProvider(Guid serviceUuid)
{
_service = new GattLocalService(serviceUuid);
NativeInitService();
}
/// <summary>
/// Start advertising the GATT service.
/// </summary>
public void StartAdvertising()
{
StartAdvertising(new GattServiceProviderAdvertisingParameters());
}
/// <summary>
/// Start advertising the GATT service.
/// </summary>
/// <param name="parameters">The advertising parameters.</param>
public void StartAdvertising(GattServiceProviderAdvertisingParameters parameters)
{
// Save parameters
_isConnectable = parameters.IsConnectable;
_isDiscoverable = parameters.IsDiscoverable;
_serviceData = parameters.ServiceData;
_deviceName = Encoding.UTF8.GetBytes(parameters.DeviceName);
if (NativeStartAdvertising())
{
_status = GattServiceProviderAdvertisementStatus.Started;
}
}
/// <summary>
/// Stop advertising the GATT service.
/// </summary>
public void StopAdvertising()
{
NativeStopAdvertising();
_status = GattServiceProviderAdvertisementStatus.Stopped;
}
/// <summary>
/// Creates a new GATT service with the specified serviceUuid
/// </summary>
/// <param name="serviceUuid">The service UUID.</param>
/// <returns>A GattServiceProviderResult object.</returns>
public static GattServiceProviderResult Create(Guid serviceUuid)
{
GattServiceProvider serviceProvider = new GattServiceProvider(serviceUuid);
return new GattServiceProviderResult(serviceProvider, BluetoothError.Success);
}
/// <summary>
/// Gets the advertisement status of this GATT service.
/// </summary>
/// <Returns>The advertisement service.</Returns>
public GattServiceProviderAdvertisementStatus AdvertisementStatus { get => _status; }
/// <summary>
/// Gets the GATT service.
/// </summary>
/// <returns>The GATT service.</returns>
public GattLocalService Service { get => _service; }
#region external calls to native implementations
[MethodImpl(MethodImplOptions.InternalCall)]
private extern bool NativeInitService();
[MethodImpl(MethodImplOptions.InternalCall)]
private extern bool NativeStartAdvertising();
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeStopAdvertising();
#endregion
}
}

Просмотреть файл

@ -0,0 +1,38 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This enumeration defines the advertisement status of a GattServiceProvider.
/// </summary>
public enum GattServiceProviderAdvertisementStatus
{
/// <summary>
/// The GATT service was created.
/// </summary>
Created = 0,
/// <summary>
/// The GATT service is not advertising.
/// </summary>
Stopped = 1,
/// <summary>
/// The GATT service advertising has started.
/// </summary>
Started = 2,
/// <summary>
/// The GATT service was aborted.
/// </summary>
Aborted = 3,
/// <summary>
/// Indicates that the system was successfully able to issue the advertisement request,
/// but not all of the requested data could be included in the advertisement.</summary>
StartedWithoutAllAdvertisementData = 4
}
}

Просмотреть файл

@ -0,0 +1,73 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class is used to define the GATT service advertisement parameters.
/// </summary>
public sealed class GattServiceProviderAdvertisingParameters
{
const string _defaultDeviceName = "nanoFramework";
private string _deviceName = _defaultDeviceName;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private bool _isDiscoverable = true;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private bool _isConnectable = true;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private Buffer _serviceData;
/// <summary>
/// Creates a new GattServiceProviderAdvertisingParameters object.
/// </summary>
public GattServiceProviderAdvertisingParameters()
{
}
/// <summary>
/// Gets or sets a boolean indicating that the GATT service is discoverable.
/// </summary>
public bool IsDiscoverable { get => _isDiscoverable; set => _isDiscoverable = value; }
/// <summary>
/// Gets or sets a boolean that indicates if the GATT service is connect-able.
/// </summary>
public bool IsConnectable { get => _isConnectable; set => _isConnectable = value; }
/// <summary>
/// Friendly device name used for advertising service.
/// Default "nanoFramework"
/// </summary>
public string DeviceName
{
get => _deviceName;
set
{
if (string.IsNullOrEmpty(value))
{
_deviceName = _defaultDeviceName;
}
else
{
_deviceName = value;
}
}
}
/// <summary>
/// For Bluetooth Low Energy, this parameter adds an additional **ServiceData** section
/// to the advertisement payload for the service's service UUID if space is available.
/// If the service data is added to the advertisement, then the service UUID will
/// also be included in the same section in the advertisement.
/// </summary>
public Buffer ServiceData { get => _serviceData; set => _serviceData = value; }
}
}

Просмотреть файл

@ -0,0 +1,34 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class is the result of the Create operation.
/// </summary>
public sealed class GattServiceProviderResult
{
private readonly GattServiceProvider _serviceProvider;
private readonly BluetoothError _error;
internal GattServiceProviderResult(GattServiceProvider serviceProvider, BluetoothError error)
{
_serviceProvider = serviceProvider;
_error = error;
}
/// <summary>
/// Gets the error.
/// </summary>
public BluetoothError Error { get => _error; }
/// <summary>
/// Gets the service provider.
/// </summary>
public GattServiceProvider ServiceProvider { get => _serviceProvider; }
}
}

Просмотреть файл

@ -0,0 +1,155 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Represents an enumeration of the most well known Service UUID values, and provides
/// convenience methods for working with GATT service UUIDs, and static properties
/// providing service UUIDs for common GATT services. To view a list of all Bluetooth
/// SIG-defined service UUIDs, see Bluetooth SIG-defined Service UUIDs.
/// See:- https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf
/// Current Service UUID 0x1800 to 0x181D
/// </summary>
public static class GattServiceUuids
{
/// <summary>
/// Gets the Bluetooth SIG-defined AlertNotification Service UUID.
/// </summary>
public static Guid AlertNotification { get => Utilities.CreateUuidFromShortCode(0x1811); }
/// <summary>
/// Gets the Bluetooth SIG-defined Automation IO Service UUID.
/// </summary>
public static Guid AutomationIO { get => Utilities.CreateUuidFromShortCode(0x1815); }
/// <summary>
/// Gets the Bluetooth SIG-defined Battery Service UUID.
/// </summary>
public static Guid Battery { get => Utilities.CreateUuidFromShortCode(0x180f); }
/// <summary>
/// Gets the Bluetooth SIG-defined Blood Pressure Service UUID.
/// </summary>
public static Guid BloodPressure { get => Utilities.CreateUuidFromShortCode(0x1810); }
/// <summary>
/// Gets the Bluetooth SIG-defined Body Composition Service UUID.
/// </summary>
public static Guid BodyComposition { get => Utilities.CreateUuidFromShortCode(0x181b); }
/// <summary>
/// Gets the Bluetooth SIG-defined CurrentTime service UUID.
/// </summary>
public static Guid CurrentTime { get => Utilities.CreateUuidFromShortCode(0x1805); }
/// <summary>
/// Gets the Bluetooth SIG-defined CyclingPower service UUID.
/// </summary>
public static Guid CyclingPower { get => Utilities.CreateUuidFromShortCode(0x1818); }
/// <summary>
/// Gets the Bluetooth SIG-defined Cycling Speed And Cadence Service UUID.
/// </summary>
public static Guid CyclingSpeedAndCadence { get => Utilities.CreateUuidFromShortCode(0x1816); }
/// <summary>
/// Gets the Bluetooth SIG-defined DeviceInformation service UUID.
/// </summary>
public static Guid DeviceInformation { get => Utilities.CreateUuidFromShortCode(0x180a); }
/// <summary>
/// Gets the Bluetooth SIG-defined Environmental Sensing Service UUID.
/// </summary>
public static Guid EnvironmentalSensing { get => Utilities.CreateUuidFromShortCode(0x181a); }
/// <summary>
/// Gets the Bluetooth SIG-defined UUID for the Generic Access Service.
/// </summary>
public static Guid GenericAccess { get => Utilities.CreateUuidFromShortCode(0x1800); }
/// <summary>
/// Gets the Bluetooth SIG-defined UUID for the Generic Attribute Service.
/// </summary>
public static Guid GenericAttribute { get => Utilities.CreateUuidFromShortCode(0x1801); }
/// <summary>
/// Gets the Bluetooth SIG-defined Glucose Service UUID.
/// </summary>
public static Guid Glucose { get => Utilities.CreateUuidFromShortCode(0x1808); }
/// <summary>
/// Gets the Bluetooth SIG-defined Health Thermometer Service UUID.
/// </summary>
public static Guid HealthThermometer { get => Utilities.CreateUuidFromShortCode(0x1809); }
/// <summary>
/// Gets the Bluetooth SIG-defined Heart Rate Service UUID.
/// </summary>
public static Guid HeartRate { get => Utilities.CreateUuidFromShortCode(0x180d); }
/// <summary>
/// Gets the Bluetooth SIG-defined HumanInterfaceDevice service UUID.
/// </summary>
public static Guid HumanInterfaceDevice { get => Utilities.CreateUuidFromShortCode(0x1812); }
/// <summary>
/// Gets the Bluetooth SIG-defined ImmediateAlert service UUID.
/// </summary>
public static Guid ImmediateAlert { get => Utilities.CreateUuidFromShortCode(0x1802); }
/// <summary>
/// Gets the Bluetooth SIG-defined LinkLoss service UUID.
/// </summary>
public static Guid LinkLoss {get => Utilities.CreateUuidFromShortCode(0x1803); }
/// <summary>
/// Gets the Bluetooth SIG-defined LocationAndNavigation service UUID.
/// </summary>
public static Guid LocationAndNavigation { get => Utilities.CreateUuidFromShortCode(0x1819); }
/// <summary>
/// Gets the Bluetooth SIG-defined NextDstChange service UUID.
/// </summary>
public static Guid NextDstChange { get => Utilities.CreateUuidFromShortCode(0x1807); }
/// <summary>
/// Gets the Bluetooth SIG-defined PhoneAlertStatus service UUID.
/// </summary>
public static Guid PhoneAlertStatus { get => Utilities.CreateUuidFromShortCode(0x180e); }
/// <summary>
/// Gets the Bluetooth SIG-defined ReferenceTimeUpdate service UUID.
/// </summary>
public static Guid ReferenceTimeUpdate { get => Utilities.CreateUuidFromShortCode(0x1806); }
/// <summary>
/// Gets the Bluetooth SIG-defined Running Speed And Cadence Service UUID.
/// </summary>
public static Guid RunningSpeedAndCadence { get => Utilities.CreateUuidFromShortCode(0x1814); }
/// <summary>
/// Gets the Bluetooth SIG-defined ScanParameters service UUID.
/// </summary>
public static Guid ScanParameters { get => Utilities.CreateUuidFromShortCode(0x1813); }
/// <summary>
/// Gets the Bluetooth SIG-defined TxPower service UUID.
/// </summary>
public static Guid TxPower { get => Utilities.CreateUuidFromShortCode(0x1804); }
/// <summary>
/// Gets the Bluetooth SIG-defined User Data service UUID.
/// </summary>
public static Guid UserData { get => Utilities.CreateUuidFromShortCode(0x181c); }
/// <summary>
/// Gets the Bluetooth SIG-defined Weight Scale service UUID.
/// </summary>
public static Guid WeightScale { get => Utilities.CreateUuidFromShortCode(0x181d); }
}
}

Просмотреть файл

@ -0,0 +1,45 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a GATT session.
/// </summary>
public sealed class GattSession : IDisposable
{
private readonly BluetoothDeviceId _deviceId;
/// <summary>
/// Dispose GattSession object
/// </summary>
public void Dispose()
{
// not used yet
}
/// <summary>
/// Creates a new GattSession object from the specified deviceId.
/// </summary>
/// <param name="deviceId">The deviceId.</param>
/// <returns> A new GattSession object.</returns>
public static GattSession FromDeviceId(BluetoothDeviceId deviceId)
{
return new GattSession(deviceId);
}
internal GattSession(BluetoothDeviceId deviceId)
{
_deviceId = deviceId;
}
/// <summary>
/// Gets the device ID.
/// </summary>
public BluetoothDeviceId DeviceId { get => _deviceId; }
}
}

Просмотреть файл

@ -0,0 +1,23 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This enumeration defines a GattSession status.
/// </summary>
public enum GattSessionStatus
{
/// <summary>
/// The GATT session is closed.
/// </summary>
Closed = 0,
/// <summary>
/// The GATT session is active.
/// </summary>
Active = 1
}
}

Просмотреть файл

@ -0,0 +1,30 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a subscribed client of a GATT session.
/// </summary>
public sealed class GattSubscribedClient
{
private readonly GattSession _session;
internal GattSubscribedClient(GattSession session)
{
_session = session;
}
/// <summary>
/// Gets the maximum notification size.
/// </summary>
public ushort MaxNotificationSize { get => 1024; }
/// <summary>
/// Gets the session of the subscribed client.
/// </summary>
public GattSession Session { get => _session; }
}
}

Просмотреть файл

@ -0,0 +1,23 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// Indicates what type of write operation is to be performed.
/// </summary>
public enum GattWriteOption
{
/// <summary>
/// The default GATT write procedure shall be used.
/// </summary>
WriteWithResponse = 0,
/// <summary>
/// The Write Without Response procedure shall be used.
/// </summary>
WriteWithoutResponse = 1
}
}

Просмотреть файл

@ -0,0 +1,78 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.CompilerServices;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents a GATT write request.
/// </summary>
public sealed class GattWriteRequest
{
private readonly GattWriteOption _option = GattWriteOption.WriteWithResponse;
private readonly uint _offset = 0;
private readonly Buffer _value = null;
private readonly ushort _eventID;
internal GattWriteRequest(ushort eventID)
{
_eventID = eventID;
// Get a copy of data from Native for this event
byte[] data = NativeWriteGetData(eventID);
// and save it
_value = new Buffer(data);
}
/// <summary>
/// Responds to the write request.
/// </summary>
public void Respond()
{
NativeWriteRespond(_eventID);
}
/// <summary>
/// Responds with a protocol error.
/// </summary>
/// <param name="protocolError">Error byte</param>
public void RespondWithProtocolError(byte protocolError)
{
NativeWriteRespondWithProtocolError(_eventID, protocolError);
}
/// <summary>
/// Gets the offset.
/// </summary>
public uint Offset { get => _offset; }
/// <summary>
/// Gets the write request option.
/// </summary>
public GattWriteOption Option { get => _option; }
/// <summary>
/// Gets the buffer value of the write request.
/// </summary>
public Buffer Value { get => _value; }
#region external calls to native implementations
[MethodImpl(MethodImplOptions.InternalCall)]
private extern byte[] NativeWriteGetData(ushort eventID);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeWriteRespond(ushort eventID);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeWriteRespondWithProtocolError(ushort eventID, byte protocolError);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,38 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.GenericAttributeProfile
{
/// <summary>
/// This class represents the event arguments for WriteRequested.
/// </summary>
public sealed class GattWriteRequestedEventArgs //: IGattWriteRequestedEventArgs
{
private readonly ushort _eventID;
private readonly GattSession _session = null;
internal GattWriteRequestedEventArgs(ushort eventID, GattSession session)
{
_eventID = eventID;
_session = session;
}
/// <summary>
/// Gets the write request.
/// </summary>
/// <returns>Returns a write request.</returns>
public GattWriteRequest GetRequest()
{
return new GattWriteRequest(_eventID);
}
/// <summary>
/// Gets the session.
/// </summary>
public GattSession Session { get => _session; }
}
}

Просмотреть файл

@ -0,0 +1,79 @@
using System;
using System.Text;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Represents a referenced array of bytes used by byte stream read and write interfaces.
/// </summary>
public class Buffer
{
/// <summary>
/// Byte buffer
/// </summary>
private byte[] _buffer;
/// <summary>
/// Length of data in byte buffer.
/// </summary>
protected uint _length;
/// <summary>
/// Constructor for Buffer with a specific capacity.
/// </summary>
/// <param name="capacity"></param>
public Buffer(uint capacity)
{
_buffer = new byte[capacity];
_length = 0;
}
/// <summary>
/// Constructor for Buffer with an external byte buffer.
/// </summary>
/// <param name="array"></param>
public Buffer(byte[] array)
{
_buffer = array;
_length = (uint)array.Length;
}
/// <summary>
/// Gets the maximum number of bytes that the buffer can hold.
/// </summary>
public uint Capacity { get => (uint)_buffer.Length; }
/// <summary>
/// Gets the number of bytes currently in use in the buffer.
/// </summary>
public uint Length
{
get => _length;
set
{
if (value > _buffer.Length || value < 0)
{
throw new ArgumentException("Length greater than current buffer");
}
_length = value;
}
}
/// <summary>
/// Ensure buffer has a certain capacity. If to small it will be expanded
/// </summary>
/// <param name="newCapacity">New capacity required</param>
public void EnsureCapacity(uint newCapacity)
{
if (newCapacity > _buffer.Length)
{
Byte[] newBuffer = new Byte[newCapacity];
Array.Copy(_buffer, 0, newBuffer, 0, _buffer.Length);
_buffer = newBuffer;
}
}
internal byte[] Data { get => _buffer; }
}
}

Просмотреть файл

@ -0,0 +1,295 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Text;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Reads data from an input buffer.
/// </summary>
public sealed class DataReader
{
private Buffer _buffer;
private int _currentReadPosition;
const int defaultBufferSize = 32;
private DataReader(Buffer buffer)
{
_buffer = buffer;
_currentReadPosition = 0;
}
/// <summary>
/// Creates a new instance of the data reader with data from the specified buffer.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns>The data reader.</returns>
public static DataReader FromBuffer(Buffer buffer)
{
return new DataReader(buffer);
}
/// <summary>
/// Gets the size of the buffer that has not been read.
/// </summary>
/// <value>
/// The size of the buffer that has not been read, in bytes.
/// </value>
public uint UnconsumedBufferLength { get => _buffer.Length - (uint)_currentReadPosition; }
/// <summary>
/// Reads a Boolean value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public bool ReadBoolean()
{
var value = _buffer.Data[IncreaseReadPosition(1)] > 0;
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a buffer from the input buffer.
/// </summary>
/// <param name="length">The length of the buffer, in bytes.</param>
/// <returns>The buffer.</returns>
public Buffer ReadBuffer(uint length)
{
Buffer buffer = new Buffer(length);
Array.Copy(_buffer.Data, IncreaseReadPosition((int)length), buffer.Data, 0, (int)length);
CheckReadPosition();
return buffer;
}
/// <summary>
/// Reads a byte value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public byte ReadByte()
{
var value = _buffer.Data[IncreaseReadPosition(1)];
CheckReadPosition();
return value;
}
/// <summary>
/// Reads an array of byte values from the input buffer.
/// </summary>
/// <param name="value">The array of values.</param>
public void ReadBytes(Byte[] value)
{
if (value == null)
{
throw new ArgumentNullException("Argument is null");
}
Array.Copy(_buffer.Data, IncreaseReadPosition(value.Length), value, 0, value.Length);
CheckReadPosition();
}
/// <summary>
/// Reads a date and time value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public DateTime ReadDateTime()
{
// read position update and check are performed on the call
return new DateTime(ReadInt64());
}
/// <summary>
/// Reads a floating-point value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public double ReadDouble()
{
var value = BitConverter.ToDouble(_buffer.Data, IncreaseReadPosition(8));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a GUID value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public Guid ReadGuid()
{
byte[] byteArray = new byte[16];
// read position update and check are performed on the call
ReadBytes(byteArray);
return new Guid(byteArray);
}
/// <summary>
/// Reads a 16-bit integer value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public short ReadInt16()
{
var value = BitConverter.ToInt16(_buffer.Data, IncreaseReadPosition(2));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a 32-bit integer value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public int ReadInt32()
{
var value = BitConverter.ToInt32(_buffer.Data, IncreaseReadPosition(4));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a 64-bit integer value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public long ReadInt64()
{
var value = BitConverter.ToInt64(_buffer.Data, IncreaseReadPosition(8));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a floating-point value from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public float ReadSingle()
{
var value = BitConverter.ToSingle(_buffer.Data, IncreaseReadPosition(4));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a string value from the input buffer.
/// </summary>
/// <param name="codeUnitCount">The length of the string.</param>
/// <returns>The value.</returns>
public string ReadString(uint codeUnitCount)
{
Char[] buffer = new Char[codeUnitCount];
int readPosition = IncreaseReadPosition((int)codeUnitCount);
Encoding.UTF8.GetDecoder().Convert(_buffer.Data, readPosition, (int)codeUnitCount, buffer, 0, (int)codeUnitCount, false, out Int32 bytesUsed, out Int32 charsUsed, out Boolean completed);
var value = new String(buffer, 0, charsUsed);
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a time interval from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public TimeSpan ReadTimeSpan()
{
// read position update and check are performed on the call
return new TimeSpan(ReadInt64());
}
/// <summary>
/// Reads a 16-bit unsigned integer from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public ushort ReadUInt16()
{
var value = BitConverter.ToUInt16(_buffer.Data, IncreaseReadPosition(2));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a 32-bit unsigned integer from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public uint ReadUInt32()
{
var value = BitConverter.ToUInt32(_buffer.Data, IncreaseReadPosition(4));
CheckReadPosition();
return value;
}
/// <summary>
/// Reads a 64-bit unsigned integer from the input buffer.
/// </summary>
/// <returns>The value.</returns>
public ulong ReadUInt64()
{
var value = BitConverter.ToUInt64(_buffer.Data, IncreaseReadPosition(8));
CheckReadPosition();
return value;
}
/// <summary>
/// Increases the backing buffer read position.
/// </summary>
/// <param name="count">How many bytes to read from the backing buffer.</param>
/// <returns>
/// The current buffer position before increasing it by <para>count</para>.
/// </returns>
private int IncreaseReadPosition(int count)
{
if (UnconsumedBufferLength < count)
{
throw new ArgumentOutOfRangeException("count", "No data in buffer");
}
// save current read position
int newPosition = _currentReadPosition;
// increase by count request
_currentReadPosition += count;
return newPosition;
}
/// <summary>
/// Checks current read position and resets the backing buffer if all bytes have been read
/// </summary>
private void CheckReadPosition()
{
if (_currentReadPosition == _buffer.Length)
{
_buffer = new Buffer(defaultBufferSize);
_currentReadPosition = 0;
}
}
}
}

Просмотреть файл

@ -0,0 +1,214 @@
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Text;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Writes data to an output stream.
/// </summary>
public sealed class DataWriter : Buffer
{
/// <summary>
/// Creates and initializes a new instance of the data writer.
/// </summary>
public DataWriter() : base(32)
{
}
/// <summary>
/// Gets the size of a string.
/// </summary>
/// <param name="value">The string.</param>
/// <returns>The size of the string, in bytes.</returns>
public uint MeasureString(String value)
{
Encoding encoding = Encoding.UTF8;
if (value == null)
{
throw new ArgumentNullException("value");
}
return (uint)encoding.GetBytes(value).Length;
}
/// <summary>
/// Writes a Boolean value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteBoolean(Boolean value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a number of bytes from a buffer.
/// </summary>
/// <param name="buffer">The value to write.</param>
public void WriteBuffer(Buffer buffer)
{
WriteBuffer(buffer, 0, buffer.Length);
}
/// <summary>
/// Writes a range of bytes from a buffer to the output stream.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="start">The starting byte to be written.</param>
/// <param name="count">The number of bytes to write.</param>
public void WriteBuffer(Buffer buffer, uint start, uint count)
{
byte[] copyBuffer = new byte[count];
Array.Copy(buffer.Data, (int)start, copyBuffer, 0, (int)count);
WriteBytes(copyBuffer);
}
/// <summary>
/// Writes a byte value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteByte(Byte value)
{
WriteBytes(new byte[] { value });
}
/// <summary>
/// Writes an array of byte values to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteBytes(Byte[] value)
{
EnsureCapacity((uint)(base.Length + value.Length));
Array.Copy(value, 0, base.Data, (int)base.Length, value.Length);
base.Length += (uint)value.Length;
}
/// <summary>
/// Writes a date and time value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteDateTime(DateTime value)
{
WriteInt64(value.Ticks);
}
/// <summary>
/// Writes a floating-point value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteDouble(Double value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a GUID value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteGuid(Guid value)
{
WriteBytes(value.ToByteArray());
}
/// <summary>
/// Writes a 16-bit integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteInt16(Int16 value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a 32-bit integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteInt32(Int32 value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a 64-bit integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteInt64(Int64 value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Write a floating-point value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteSingle(Single value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a string value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
/// <returns>The length of the string.</returns>
public uint WriteString(String value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
byte[] strBytes = Encoding.UTF8.GetBytes(value);
WriteBytes(strBytes);
return (uint)strBytes.Length;
}
/// <summary>
/// Writes a time interval value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteTimeSpan(TimeSpan value)
{
WriteInt64(value.Ticks);
}
/// <summary>
/// Writes a 16-bit unsigned integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteUInt16(UInt16 value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a 32-bit unsigned integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteUInt32(uint value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a 64-bit unsigned integer value to the output stream.
/// </summary>
/// <param name="value">The value to write.</param>
public void WriteUInt64(UInt64 value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// Returns byte buffer of data in buffer
/// </summary>
/// <returns>Buffer</returns>
public Buffer DetachBuffer()
{
return (Buffer)this;
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("nanoFramework.Device.Bluetooth")]
[assembly: AssemblyCompany("nanoFramework Contributors")]
[assembly: AssemblyProduct("nanoFramework.Device.Bluetooth")]
[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")]
////////////////////////////////////////////////////////////////
// update this whenever the native assembly signature changes //
[assembly: AssemblyNativeVersion("100.0.0.1")]
////////////////////////////////////////////////////////////////

Просмотреть файл

@ -0,0 +1,71 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth.Spp
{
/// <summary>
/// Interface for Bluetooth Serial Profile (SPP)
/// </summary>
public interface IBluetoothSpp
{
/// <summary>
/// Receive data delegate.
/// </summary>
/// <param name="sender"></param>
/// <param name="ReadDataEventArgs"></param>
public delegate void RxDataEventHandler(IBluetoothSpp sender, SppReceivedDataEventArgs ReadDataEventArgs);
/// <summary>
/// Connected client status changed delegate.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void ConnectedEventHandler(IBluetoothSpp sender, EventArgs e);
/// <summary>
/// Received data event. Event is fired when data is received.
/// </summary>
public event RxDataEventHandler ReceivedData;
/// <summary>
/// Connected client status changed event, Fired when client connects or disconnects.
/// Check isConnected property for current status.
/// </summary>
public event ConnectedEventHandler ConnectedEvent;
/// <summary>
/// Returns true is a client is connected.
/// </summary>
bool IsConnected{ get; }
/// <summary>
/// Start the SPP advertising.
/// </summary>
/// <param name="deviceName">Device name to use in advert.</param>
/// <returns></returns>
bool Start(string deviceName);
/// <summary>
/// Stop advertising and close down.
/// </summary>
void Stop();
/// <summary>
/// Send bytes to connected client.
/// </summary>
/// <param name="data">Byte[] to send.</param>
/// <returns>True if send was successful.</returns>
bool SendBytes(byte[] data);
/// <summary>
/// Send string to connected client.
/// </summary>
/// <param name="data">String data to send.</param>
/// <returns>True if send was successful.</returns>
bool SendString(string data);
}
}

Просмотреть файл

@ -0,0 +1,176 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using nanoFramework.Device.Bluetooth.GenericAttributeProfile;
using System.Diagnostics;
using System.Text;
namespace nanoFramework.Device.Bluetooth.Spp
{
/// <summary>
/// Implementation of Nordic Serial SPP profile.
/// </summary>
public class NordicSpp : IBluetoothSpp
{
// UUID for Nordic UART service
// https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/libraries/bluetooth_services/services/nus.html#id4
private Guid ServiceUUID = new Guid("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
private Guid RxCharacteristicUUID = new Guid("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
private Guid TxCharacteristicUUID = new Guid("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
private readonly GattServiceProvider _serviceProvider;
private readonly GattLocalCharacteristic _txCharacteristic;
private bool _isConnected = false;
/// <summary>
/// Return true id client connected
/// </summary>
public bool IsConnected { get => _isConnected; }
/// <summary>
/// Event handler for receiving data
/// </summary>
public event IBluetoothSpp.RxDataEventHandler ReceivedData;
/// <summary>
/// Event Handler for connection state change
/// </summary>
public event IBluetoothSpp.ConnectedEventHandler ConnectedEvent;
/// <summary>
/// Constructor for Nordic serial SPP profile
/// </summary>
public NordicSpp()
{
GattServiceProviderResult gspr = GattServiceProvider.Create(ServiceUUID);
if (gspr.Error != nanoFramework.Device.Bluetooth.BluetoothError.Success)
{
throw new ArgumentException("Unable to create service");
}
_serviceProvider = gspr.ServiceProvider;
// Define RX characteristic
GattLocalCharacteristicParameters rxParam = new GattLocalCharacteristicParameters()
{
UserDescription = "RX Characteristic",
CharacteristicProperties = GattCharacteristicProperties.Write | GattCharacteristicProperties.WriteWithoutResponse
};
GattLocalCharacteristicResult rxCharRes = _serviceProvider.Service.CreateCharacteristic(RxCharacteristicUUID, rxParam);
if (rxCharRes.Error != nanoFramework.Device.Bluetooth.BluetoothError.Success)
{
throw new ArgumentException("Unable to create RX Characteristic");
}
GattLocalCharacteristic rxCharacteristic = rxCharRes.Characteristic;
rxCharacteristic.WriteRequested += RxCharacteristic_WriteRequested;
// Define TX characteristic
GattLocalCharacteristicParameters txParam = new GattLocalCharacteristicParameters()
{
UserDescription = "TX Characteristic",
CharacteristicProperties = GattCharacteristicProperties.Notify
};
GattLocalCharacteristicResult txCharRes = _serviceProvider.Service.CreateCharacteristic(TxCharacteristicUUID, txParam);
if (txCharRes.Error != nanoFramework.Device.Bluetooth.BluetoothError.Success)
{
throw new ArgumentException("Unable to create TX Characteristic");
}
_txCharacteristic = txCharRes.Characteristic;
_txCharacteristic.SubscribedClientsChanged += _txCharacteristic_SubscribedClientsChanged;
}
private void _txCharacteristic_SubscribedClientsChanged(GattLocalCharacteristic sender, object args)
{
_isConnected = (sender.SubscribedClients.Length > 0);
// Fire event when connection state changes
ConnectedEvent?.Invoke(this, new EventArgs());
}
/// <summary>
/// Start device advertising
/// </summary>
/// <param name="deviceName">Device name for Advertising</param>
/// <returns></returns>
public bool Start(string deviceName)
{
GattServiceProviderAdvertisingParameters advParameters = new GattServiceProviderAdvertisingParameters
{
DeviceName = deviceName,
IsDiscoverable = true,
IsConnectable = true
};
_serviceProvider.StartAdvertising(advParameters);
return true;
}
/// <summary>
/// Stop Nordic SPP UART device
/// Stop advertising.
/// </summary>
public void Stop()
{
_serviceProvider?.StopAdvertising();
}
/// <summary>
/// Send data bytes to connected client
/// </summary>
/// <param name="data">byte array to send</param>
/// <returns></returns>
public bool SendBytes(byte[] data)
{
DataWriter dr = new DataWriter();
dr.WriteBytes(data);
GattClientNotificationResult[] results = _txCharacteristic.NotifyValue(dr.DetachBuffer());
if (results.Length > 0 && results[0].ProtocolError == 0)
{
return true;
}
return false;
}
/// <summary>
/// Send data as string
/// </summary>
/// <param name="data">string to send</param>
/// <returns></returns>
public bool SendString(string data)
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
return SendBytes(bytes);
}
/// <summary>
/// Event handler for Received data
/// </summary>
/// <param name="sender"></param>
/// <param name="WriteRequestEventArgs"></param>
private void RxCharacteristic_WriteRequested(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs)
{
GattWriteRequest request = WriteRequestEventArgs.GetRequest();
byte[] data = new byte[request.Value.Length];
DataReader rdr = DataReader.FromBuffer(request.Value);
rdr.ReadBytes(data);
ReceivedData?.Invoke(this, new SppReceivedDataEventArgs(data));
if (request.Option == GattWriteOption.WriteWithResponse)
{
request.Respond();
}
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Text;
namespace nanoFramework.Device.Bluetooth.Spp
{
/// <summary>
/// Event argument for SPP receive data events
/// </summary>
public sealed class SppReceivedDataEventArgs
{
private readonly byte[] _data;
internal SppReceivedDataEventArgs(byte[] data)
{
_data = data;
}
/// <summary>
/// Received data as byte[].
/// </summary>
public byte[] DataBytes { get => _data; }
/// <summary>
/// Received data as string.
/// </summary>
public String DataString { get => Encoding.UTF8.GetString(_data, 0, _data.Length); }
}
}

Просмотреть файл

@ -0,0 +1,101 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
namespace nanoFramework.Device.Bluetooth
{
/// <summary>
/// Bluetooth library utilities
/// </summary>
public static class Utilities
{
/// <summary>
/// This enum assists in finding a string representation of a BT SIG assigned value for Descriptor UUIDs
/// Reference: https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx
/// </summary>
public enum GattNativeDescriptorUuid : ushort
{
/// <summary>
/// CharacteristicExtendedProperties
/// </summary>
CharacteristicExtendedProperties = 0x2900,
/// <summary>
/// CharacteristicUserDescription
/// </summary>
CharacteristicUserDescription = 0x2901,
/// <summary>
/// ClientCharacteristicConfiguration
/// </summary>
ClientCharacteristicConfiguration = 0x2902,
/// <summary>
/// ServerCharacteristicConfiguration
/// </summary>
ServerCharacteristicConfiguration = 0x2903,
/// <summary>
/// CharacteristicPresentationFormat
/// </summary>
CharacteristicPresentationFormat = 0x2904,
/// <summary>
/// CharacteristicAggregateFormat
/// </summary>
CharacteristicAggregateFormat = 0x2905,
/// <summary>
/// ValidRange
/// </summary>
ValidRange = 0x2906,
/// <summary>
/// ExternalReportReference
/// </summary>
ExternalReportReference = 0x2907,
/// <summary>
/// ReportReference
/// </summary>
ReportReference = 0x2908
}
/// <summary>
/// Converts from standard 128bit UUID to the assigned 16bit UUID. Makes it easy to compare services
/// that devices expose to the standard list.
/// </summary>
/// <param name="uuid">UUID to convert to 16 bit short code Uuid</param>
/// <returns></returns>
public static ushort ConvertUuidToShortId(Guid uuid)
{
// Get the short Uuid
var bytes = uuid.ToByteArray();
var shortUuid = (ushort)(bytes[0] | (bytes[1] << 8));
return shortUuid;
}
/// <summary>
/// Create a Uuid/Guid from a short Bluetooth SIG short UUID
/// </summary>
/// <param name="uuid16">Bluetooth Short code UUID</param>
/// <returns>A Guid using Bluetooth SIG UUID</returns>
public static Guid CreateUuidFromShortCode(ushort uuid16)
{
// UUID is the name used by Bluetooth SIG for a Guid
// This is the base UUID for all standard Bluetooth SIG UUIDs
const string baseUuid = "00000000-0000-1000-8000-00805f9b34fb";
Guid temp = new Guid(baseUuid);
byte[] bytes = temp.ToByteArray();
bytes[0] = (byte)(0x00ff & uuid16);
bytes[1] = (byte)(uuid16 >> 8);
return new Guid(bytes);
}
}
}

Двоичные данные
nanoFramework.Device.Bluetooth/key.snk Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<NanoFrameworkProjectSystemPath>$(MSBuildExtensionsPath)\nanoFramework\v1.0\</NanoFrameworkProjectSystemPath>
</PropertyGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectTypeGuids>{11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>3e3dfd1b-89f3-455d-83d4-c34c7fc5422e</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<FileAlignment>512</FileAlignment>
<RootNamespace>nanoFramework.Device.Bluetooth</RootNamespace>
<AssemblyName>nanoFramework.Device.Bluetooth</AssemblyName>
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
<NF_IsCoreLibrary>True</NF_IsCoreLibrary>
<DocumentationFile>bin\$(Configuration)\nanoFramework.Device.Bluetooth.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<DelaySign>false</DelaySign>
</PropertyGroup>
<PropertyGroup>
<!-- override default options for MetaDataProcessor -->
<NF_GenerateStubsDirectory>bin\$(Configuration)\Stubs</NF_GenerateStubsDirectory>
<NF_GenerateSkeletonProjectName>sys_dev_ble_native</NF_GenerateSkeletonProjectName>
<Name>System.Device.Bluetooth</Name>
</PropertyGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
<ItemGroup>
<Compile Include="BluetoothDeviceId.cs" />
<Compile Include="BluetoothError.cs" />
<Compile Include="BluetoothEvent.cs" />
<Compile Include="BluetoothEventListener.cs" />
<Compile Include="BluetoothEventType.cs" />
<Compile Include="GenericAttributeProfile\GattCharacteristicProperties.cs" />
<Compile Include="GenericAttributeProfile\GattCharacteristicUuids.cs" />
<Compile Include="GenericAttributeProfile\GattClientNotificationResult.cs" />
<Compile Include="GenericAttributeProfile\GattCommunicationStatus.cs" />
<Compile Include="GenericAttributeProfile\GattDescriptorUuid.cs" />
<Compile Include="GenericAttributeProfile\GattLocalCharacteristic.cs" />
<Compile Include="GenericAttributeProfile\GattLocalCharacteristicParameters.cs" />
<Compile Include="GenericAttributeProfile\GattLocalCharacteristicResult.cs" />
<Compile Include="GenericAttributeProfile\GattLocalDescriptor.cs" />
<Compile Include="GenericAttributeProfile\GattLocalDescriptorParameters.cs" />
<Compile Include="GenericAttributeProfile\GattLocalDescriptorResult.cs" />
<Compile Include="GenericAttributeProfile\GattLocalService.cs" />
<Compile Include="GenericAttributeProfile\GattPresentationFormat.cs" />
<Compile Include="GenericAttributeProfile\GattPresentationFormatTypes.cs" />
<Compile Include="GenericAttributeProfile\GattProtectionLevel.cs" />
<Compile Include="GenericAttributeProfile\GattProtocolError.cs" />
<Compile Include="GenericAttributeProfile\GattReadRequest.cs" />
<Compile Include="GenericAttributeProfile\GattReadRequestedEventArgs.cs" />
<Compile Include="GenericAttributeProfile\GattServiceProvider.cs" />
<Compile Include="GenericAttributeProfile\GattServiceProviderAdvertisementStatus.cs" />
<Compile Include="GenericAttributeProfile\GattServiceProviderAdvertisingParameters.cs" />
<Compile Include="GenericAttributeProfile\GattServiceProviderResult.cs" />
<Compile Include="GenericAttributeProfile\GattServiceUuids.cs" />
<Compile Include="GenericAttributeProfile\GattSession.cs" />
<Compile Include="GenericAttributeProfile\GattSessionStatus.cs" />
<Compile Include="GenericAttributeProfile\GattSubscribedClient.cs" />
<Compile Include="GenericAttributeProfile\GattWriteOption.cs" />
<Compile Include="GenericAttributeProfile\GattWriteRequest.cs" />
<Compile Include="GenericAttributeProfile\GattWriteRequestedEventArgs.cs" />
<Compile Include="SPP\IBluetoothSpp.cs" />
<Compile Include="SPP\NordicSpp.cs" />
<Compile Include="SPP\SppReceiveEventArgs.cs" />
<Compile Include="IO\Buffer.cs" />
<Compile Include="IO\DataReader.cs" />
<Compile Include="IO\DataWriter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utilities.cs" />
</ItemGroup>
<ItemGroup>
<None Include="key.snk" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="mscorlib, Version=1.10.5.4, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.CoreLibrary.1.10.5\lib\mscorlib.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="nanoFramework.Runtime.Events, Version=1.9.2.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.Runtime.Events.1.9.2-preview.8\lib\nanoFramework.Runtime.Events.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="nanoFramework.System.Text, Version=1.1.1.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>..\packages\nanoFramework.System.Text.1.1.1\lib\nanoFramework.System.Text.dll</HintPath>
<Private>True</Private>
<SpecificVersion>True</SpecificVersion>
</Reference>
</ItemGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets')" />
<ProjectExtensions>
<ProjectCapabilities>
<ProjectConfigurationsDeclaredAsItems />
</ProjectCapabilities>
</ProjectExtensions>
<Import Project="..\packages\Nerdbank.GitVersioning.3.4.231\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\packages\Nerdbank.GitVersioning.3.4.231\build\Nerdbank.GitVersioning.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Nerdbank.GitVersioning.3.4.231\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Nerdbank.GitVersioning.3.4.231\build\Nerdbank.GitVersioning.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="nanoFramework.CoreLibrary" version="1.10.5" targetFramework="netnanoframework10" />
<package id="nanoFramework.Runtime.Events" version="1.9.2-preview.8" targetFramework="netnanoframework10" />
<package id="nanoFramework.System.Text" version="1.1.1" targetFramework="netnanoframework10" />
<package id="Nerdbank.GitVersioning" version="3.4.231" developmentDependency="true" targetFramework="netnanoframework10" />
</packages>

74
template.vssettings Normal file
Просмотреть файл

@ -0,0 +1,74 @@
<UserSettings>
<ApplicationIdentity version="12.0"/>
<ToolsOptions>
<ToolsOptionsCategory name="TextEditor" RegisteredName="TextEditor">
<ToolsOptionsSubCategory name="AllLanguages" RegisteredName="AllLanguages" PackageName="Text Management Package"/>
<ToolsOptionsSubCategory name="CSharp" RegisteredName="CSharp" PackageName="Text Management Package">
<PropertyValue name="TabSize">4</PropertyValue>
<PropertyValue name="InsertTabs">false</PropertyValue>
<PropertyValue name="IndentSize">4</PropertyValue>
<PropertyValue name="BraceCompletion">true</PropertyValue>
</ToolsOptionsSubCategory>
<ToolsOptionsSubCategory name="CSharp-Specific" RegisteredName="CSharp-Specific" PackageName="Visual C# Language Service Package">
<PropertyValue name="NewLines_QueryExpression_EachClause">1</PropertyValue>
<PropertyValue name="Space_Normalize">0</PropertyValue>
<PropertyValue name="Space_AroundBinaryOperator">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnPaste">1</PropertyValue>
<PropertyValue name="NewLines_Braces_Method">1</PropertyValue>
<PropertyValue name="Indent_CaseLabels">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnBlockCompletion">1</PropertyValue>
<PropertyValue name="CodeDefinitionWindow_DocumentationComment_IndentOffset">2</PropertyValue>
<PropertyValue name="NewLines_Braces_ControlFlow">1</PropertyValue>
<PropertyValue name="NewLines_Braces_AnonymousMethod">0</PropertyValue>
<PropertyValue name="Space_WithinOtherParentheses">0</PropertyValue>
<PropertyValue name="Wrapping_KeepStatementsOnSingleLine">1</PropertyValue>
<PropertyValue name="Space_AfterBasesColon">1</PropertyValue>
<PropertyValue name="Indent_Braces">0</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundVariableDeclaration">0</PropertyValue>
<PropertyValue name="Space_WithinMethodCallParentheses">0</PropertyValue>
<PropertyValue name="Space_AfterCast">0</PropertyValue>
<PropertyValue name="NewLines_Braces_CollectionInitializer">0</PropertyValue>
<PropertyValue name="NewLines_AnonymousTypeInitializer_EachMember">1</PropertyValue>
<PropertyValue name="NewLines_Keywords_Catch">1</PropertyValue>
<PropertyValue name="NewLines_Braces_ObjectInitializer">0</PropertyValue>
<PropertyValue name="NewLines_Braces_ArrayInitializer">0</PropertyValue>
<PropertyValue name="Space_WithinExpressionParentheses">0</PropertyValue>
<PropertyValue name="Space_InControlFlowConstruct">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnStatementCompletion">0</PropertyValue>
<PropertyValue name="NewLines_Keywords_Finally">1</PropertyValue>
<PropertyValue name="Space_BetweenEmptyMethodDeclarationParentheses">0</PropertyValue>
<PropertyValue name="Indent_UnindentLabels">0</PropertyValue>
<PropertyValue name="NewLines_ObjectInitializer_EachMember">1</PropertyValue>
<PropertyValue name="NewLines_Keywords_Else">1</PropertyValue>
<PropertyValue name="Space_WithinMethodDeclarationParentheses">0</PropertyValue>
<PropertyValue name="Space_BetweenEmptyMethodCallParentheses">0</PropertyValue>
<PropertyValue name="Space_BeforeSemicolonsInForStatement">0</PropertyValue>
<PropertyValue name="Space_BeforeComma">0</PropertyValue>
<PropertyValue name="Space_AfterMethodCallName">0</PropertyValue>
<PropertyValue name="Space_AfterComma">1</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundBinaryOperators">0</PropertyValue>
<PropertyValue name="Space_BeforeBasesColon">1</PropertyValue>
<PropertyValue name="Space_AfterMethodDeclarationName">0</PropertyValue>
<PropertyValue name="Space_AfterDot">0</PropertyValue>
<PropertyValue name="NewLines_Braces_Type">1</PropertyValue>
<PropertyValue name="Space_AfterLambdaArrow">1</PropertyValue>
<PropertyValue name="NewLines_Braces_LambdaExpressionBody">0</PropertyValue>
<PropertyValue name="Space_WithinSquares">0</PropertyValue>
<PropertyValue name="Space_BeforeLambdaArrow">1</PropertyValue>
<PropertyValue name="NewLines_Braces_AnonymousTypeInitializer">0</PropertyValue>
<PropertyValue name="Space_WithinCastParentheses">0</PropertyValue>
<PropertyValue name="Space_AfterSemicolonsInForStatement">1</PropertyValue>
<PropertyValue name="Indent_CaseContents">0</PropertyValue>
<PropertyValue name="Indent_FlushLabelsLeft">1</PropertyValue>
<PropertyValue name="Wrapping_PreserveSingleLine">1</PropertyValue>
<PropertyValue name="Space_BetweenEmptySquares">0</PropertyValue>
<PropertyValue name="Space_BeforeOpenSquare">0</PropertyValue>
<PropertyValue name="Space_BeforeDot">0</PropertyValue>
<PropertyValue name="Indent_BlockContents">1</PropertyValue>
<PropertyValue name="SortUsings_PlaceSystemFirst">1</PropertyValue>
<PropertyValue name="SortUsings">1</PropertyValue>
<PropertyValue name="RemoveUnusedUsings">1</PropertyValue>
</ToolsOptionsSubCategory>
</ToolsOptionsCategory>
</ToolsOptions>
</UserSettings>

24
version.json Normal file
Просмотреть файл

@ -0,0 +1,24 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.0.0-preview.{height}",
"assemblyVersion": {
"precision": "revision"
},
"semVer1NumericIdentifierPadding": 3,
"nuGetPackageVersion": {
"semVer": 2.0
},
"publicReleaseRefSpec": [
"^refs/heads/main$",
"^refs/heads/v\\d+(?:\\.\\d+)?$"
],
"cloudBuild": {
"setAllVariables": true,
"buildNumber": null
},
"release": {
"branchName": "release-v{version}",
"versionIncrement": "build",
"firstUnstableTag": "preview"
}
}