|
| 1 | +// |
| 2 | +// Copyright (c) .NET Foundation and Contributors |
| 3 | +// See LICENSE file in the project root for full license information. |
| 4 | +// |
| 5 | + |
| 6 | +using System; |
| 7 | +using System.Diagnostics; |
| 8 | +using System.Threading; |
| 9 | + |
| 10 | +using nanoFramework.Device.Bluetooth; |
| 11 | +using nanoFramework.Device.Bluetooth.GenericAttributeProfile; |
| 12 | + |
| 13 | +/// <summary> |
| 14 | +/// Bluetooth Sample 1 is a custom service which shows the use of: |
| 15 | +/// |
| 16 | +/// - Read static value |
| 17 | +/// - Read a dynamic value using an event |
| 18 | +/// - Notifying clients of changed value |
| 19 | +/// |
| 20 | +/// You will be able to connect to the service and read values or subscribe to Notified every 10 seconds. |
| 21 | +/// Suitable Phone apps: "LightBlue" or "nRF Connect" |
| 22 | +/// </summary> |
| 23 | +namespace BluetoothLESample1 |
| 24 | +{ |
| 25 | + public class Program |
| 26 | + { |
| 27 | + static GattLocalCharacteristic _readCharacteristic; |
| 28 | + static GattLocalCharacteristic _readWriteCharacteristic; |
| 29 | + |
| 30 | + // Read/Write Characteristic value |
| 31 | + static byte _redValue = 128; |
| 32 | + static byte _greenValue = 128; |
| 33 | + static byte _blueValue = 128; |
| 34 | + |
| 35 | + public static void Main() |
| 36 | + { |
| 37 | + Debug.WriteLine("Hello from Bluetooth Sample 1"); |
| 38 | + |
| 39 | + // Define some custom Uuids |
| 40 | + Guid serviceUuid = new Guid("A7EEDF2C-DA87-4CB5-A9C5-5151C78B0057"); |
| 41 | + Guid readCharUuid = new Guid("A7EEDF2C-DA88-4CB5-A9C5-5151C78B0057"); |
| 42 | + Guid readStaticCharUuid = new Guid("A7EEDF2C-DA89-4CB5-A9C5-5151C78B0057"); |
| 43 | + Guid readWriteCharUuid = new Guid("A7EEDF2C-DA8A-4CB5-A9C5-5151C78B0057"); |
| 44 | + |
| 45 | + //The GattServiceProvider is used to create and advertise the primary service definition. |
| 46 | + //An extra device information service will be automatically created. |
| 47 | + GattServiceProviderResult result = GattServiceProvider.Create(serviceUuid); |
| 48 | + if (result.Error != BluetoothError.Success) |
| 49 | + { |
| 50 | + return; |
| 51 | + } |
| 52 | + |
| 53 | + GattServiceProvider serviceProvider = result.ServiceProvider; |
| 54 | + |
| 55 | + // Get created Primary service from provider |
| 56 | + GattLocalService service = serviceProvider.Service; |
| 57 | + |
| 58 | + #region Static read characteristic |
| 59 | + // Now we add an characteristic to service |
| 60 | + // If the read value is not going to change then you can just use a Static value |
| 61 | + DataWriter sw = new DataWriter(); |
| 62 | + sw.WriteString("This is Bluetooth sample 1"); |
| 63 | + |
| 64 | + GattLocalCharacteristicResult characteristicResult = service.CreateCharacteristic(readStaticCharUuid, |
| 65 | + new GattLocalCharacteristicParameters() |
| 66 | + { |
| 67 | + CharacteristicProperties = GattCharacteristicProperties.Read, |
| 68 | + UserDescription = "My Static Characteristic", |
| 69 | + StaticValue = sw.DetachBuffer() |
| 70 | + }); |
| 71 | + ; |
| 72 | + |
| 73 | + if (characteristicResult.Error != BluetoothError.Success) |
| 74 | + { |
| 75 | + // An error occurred. |
| 76 | + return; |
| 77 | + } |
| 78 | + #endregion |
| 79 | + |
| 80 | + #region Create Characteristic for dynamic Reads |
| 81 | + |
| 82 | + // Add Read Characteristic for data that changes to service |
| 83 | + // We also want the connected client to be notified when value changes so we add the notify property |
| 84 | + characteristicResult = service.CreateCharacteristic(readCharUuid, |
| 85 | + new GattLocalCharacteristicParameters() |
| 86 | + { |
| 87 | + CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Notify, |
| 88 | + UserDescription = "My Read Characteristic" |
| 89 | + }); |
| 90 | + |
| 91 | + if (characteristicResult.Error != BluetoothError.Success) |
| 92 | + { |
| 93 | + // An error occurred. |
| 94 | + return; |
| 95 | + } |
| 96 | + |
| 97 | + // Get reference to our read Characteristic |
| 98 | + _readCharacteristic = characteristicResult.Characteristic; |
| 99 | + |
| 100 | + // Every time the value is requested from a client this event is called |
| 101 | + _readCharacteristic.ReadRequested += ReadCharacteristic_ReadRequested; |
| 102 | + |
| 103 | + // To notify client when time changes we are going to use a timer |
| 104 | + Timer notifyTimer = new Timer(NotifyCallBack, null, 10000, 10000); |
| 105 | + |
| 106 | + #endregion |
| 107 | + |
| 108 | + #region Create Characteristic for RGB read/write |
| 109 | + characteristicResult = service.CreateCharacteristic(readWriteCharUuid, |
| 110 | + new GattLocalCharacteristicParameters() |
| 111 | + { |
| 112 | + CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Write, |
| 113 | + UserDescription = "My Read/Write Characteristic" |
| 114 | + }); |
| 115 | + |
| 116 | + if (characteristicResult.Error != BluetoothError.Success) |
| 117 | + { |
| 118 | + // An error occurred. |
| 119 | + return; |
| 120 | + } |
| 121 | + |
| 122 | + // Get reference to our read Characteristic |
| 123 | + _readWriteCharacteristic = characteristicResult.Characteristic; |
| 124 | + |
| 125 | + // Every time the value is requested from a client this event is called |
| 126 | + _readWriteCharacteristic.WriteRequested += _readWriteCharacteristic_WriteRequested; |
| 127 | + _readWriteCharacteristic.ReadRequested += _readWriteCharacteristic_ReadRequested; |
| 128 | + |
| 129 | + #endregion |
| 130 | + |
| 131 | + #region Start Advertising |
| 132 | + // Once all the Characteristics have been created you need to advertise the Service so |
| 133 | + // other devices can see it. Here we also say the device can be connected too and other |
| 134 | + // devices can see it. |
| 135 | + serviceProvider.StartAdvertising(new GattServiceProviderAdvertisingParameters() |
| 136 | + { |
| 137 | + DeviceName = "Sample 1 Device", |
| 138 | + IsConnectable = true, |
| 139 | + IsDiscoverable = true |
| 140 | + }); |
| 141 | + #endregion |
| 142 | + |
| 143 | + Thread.Sleep(Timeout.Infinite); |
| 144 | + } |
| 145 | + |
| 146 | + /// <summary> |
| 147 | + /// Timer callback for notifying any connected clients who have subscribed to this |
| 148 | + /// characteristic of changed value. |
| 149 | + /// </summary> |
| 150 | + /// <param name="state">Not used</param> |
| 151 | + private static void NotifyCallBack(object state) |
| 152 | + { |
| 153 | + if (_readCharacteristic.SubscribedClients.Length > 0) |
| 154 | + { |
| 155 | + _readCharacteristic.NotifyValue(GetTimeBuffer()); |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + /// <summary> |
| 160 | + /// Event handler for Read characteristic. |
| 161 | + /// </summary> |
| 162 | + /// <param name="sender">GattLocalCharacteristic object</param> |
| 163 | + /// <param name="ReadRequestEventArgs"></param> |
| 164 | + private static void ReadCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs) |
| 165 | + { |
| 166 | + GattReadRequest request = ReadRequestEventArgs.GetRequest(); |
| 167 | + |
| 168 | + // Get Buffer with hour/minute/second |
| 169 | + request.RespondWithValue(GetTimeBuffer()); |
| 170 | + } |
| 171 | + |
| 172 | + // Separate out the Creation of Time buffer so it can be used by read characteristic and Notify |
| 173 | + private static Buffer GetTimeBuffer() |
| 174 | + { |
| 175 | + // Create DataWriter and write the data into buffer |
| 176 | + // Write Hour/minute/second of current time |
| 177 | + DateTime dt = DateTime.UtcNow; |
| 178 | + |
| 179 | + // Write data in a Buffer object using DataWriter |
| 180 | + DataWriter dw = new DataWriter(); |
| 181 | + dw.WriteByte((Byte)dt.Hour); |
| 182 | + dw.WriteByte((Byte)dt.Minute); |
| 183 | + dw.WriteByte((Byte)dt.Second); |
| 184 | + |
| 185 | + // Detach Buffer object from DataWriter |
| 186 | + return dw.DetachBuffer(); |
| 187 | + } |
| 188 | + |
| 189 | + /// <summary> |
| 190 | + /// Read event handler for Read/Write characteristic. |
| 191 | + /// </summary> |
| 192 | + /// <param name="sender"></param> |
| 193 | + /// <param name="ReadRequestEventArgs"></param> |
| 194 | + private static void _readWriteCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs) |
| 195 | + { |
| 196 | + GattReadRequest request = ReadRequestEventArgs.GetRequest(); |
| 197 | + |
| 198 | + DataWriter dw = new DataWriter(); |
| 199 | + dw.WriteByte((Byte)_redValue); |
| 200 | + dw.WriteByte((Byte)_greenValue); |
| 201 | + dw.WriteByte((Byte)_blueValue); |
| 202 | + |
| 203 | + request.RespondWithValue(dw.DetachBuffer()); |
| 204 | + |
| 205 | + Debug.WriteLine($"RGB read"); |
| 206 | + } |
| 207 | + |
| 208 | + /// <summary> |
| 209 | + /// Write handler for Read/Write characteristic. |
| 210 | + /// </summary> |
| 211 | + /// <param name="sender"></param> |
| 212 | + /// <param name="WriteRequestEventArgs"></param> |
| 213 | + private static void _readWriteCharacteristic_WriteRequested(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs) |
| 214 | + { |
| 215 | + GattWriteRequest request = WriteRequestEventArgs.GetRequest(); |
| 216 | + |
| 217 | + // Check expected data length, we are expecting 3 bytes |
| 218 | + if (request.Value.Length != 3) |
| 219 | + { |
| 220 | + request.RespondWithProtocolError((byte)BluetoothError.NotSupported); |
| 221 | + return; |
| 222 | + } |
| 223 | + |
| 224 | + // Unpack data from buffer |
| 225 | + DataReader rdr = DataReader.FromBuffer(request.Value); |
| 226 | + _redValue = rdr.ReadByte(); |
| 227 | + _greenValue = rdr.ReadByte(); |
| 228 | + _blueValue = rdr.ReadByte(); |
| 229 | + |
| 230 | + // Respond if Write requires response |
| 231 | + if (request.Option == GattWriteOption.WriteWithResponse) |
| 232 | + { |
| 233 | + request.Respond(); |
| 234 | + } |
| 235 | + |
| 236 | + // Print new values, better to set a RGB led |
| 237 | + Debug.WriteLine($"Received RGB={_redValue}/{_greenValue}/{_blueValue}"); |
| 238 | + } |
| 239 | + } |
| 240 | +} |
0 commit comments