Release 8.0.0.15764
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothGatt.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.Text;
21 using System.Threading.Tasks;
22
23 namespace Tizen.Network.Bluetooth
24 {
25     /// <summary>
26     /// The Bluetooth GATT server.
27     /// </summary>
28     /// <since_tizen> 3 </since_tizen>
29     public class BluetoothGattServer : IDisposable
30     {
31         private static BluetoothGattServer _instance;
32         private BluetoothGattServerImpl _impl;
33
34         private BluetoothGattServer()
35         {
36             _impl = new BluetoothGattServerImpl();
37             _impl._notificationSent += (s, e) =>
38             {
39                 e.Server = this;
40                 NotificationSent?.Invoke(this, e);
41             };
42         }
43
44         /// <summary>
45         /// (event) This event is called when the indication acknowledgement is received for each notified client.
46         /// </summary>
47         /// <since_tizen> 3 </since_tizen>
48         public event EventHandler<NotificationSentEventArg> NotificationSent;
49
50         /// <summary>
51         /// Creates the Bluetooth GATT server.
52         /// </summary>
53         /// <returns>The BluetoothGattServer instance.</returns>
54         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
55         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
56         /// <exception cref="InvalidOperationException">Thrown when the create GATT server fails.</exception>
57         /// <since_tizen> 3 </since_tizen>
58         public static BluetoothGattServer CreateServer()
59         {
60             if (_instance == null)
61             {
62                 BluetoothGattServer server = new BluetoothGattServer();
63                 if (server.IsValid())
64                 {
65                     _instance = server;
66                 }
67             }
68             return _instance;
69         }
70
71         /// <summary>
72         /// Registers the server along with the GATT services of the application it is hosting.
73         /// </summary>
74         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
75         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
76         /// <exception cref="InvalidOperationException">Thrown when the register server application fails.</exception>
77         /// <since_tizen> 3 </since_tizen>
78         public void Start()
79         {
80             _impl.Start();
81         }
82
83         /// <summary>
84         /// Registers a specified service to this server.
85         /// </summary>
86         /// <param name="service">The service, which needs to be registered with this server.</param>
87         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
88         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
89         /// <exception cref="InvalidOperationException">Thrown when the register service fails.</exception>
90         /// <since_tizen> 3 </since_tizen>
91         public void RegisterGattService(BluetoothGattService service)
92         {
93             if (service.IsRegistered())
94             {
95                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
96             }
97             _impl.RegisterGattService(this, service);
98         }
99
100         /// <summary>
101         /// Unregisters a specified service from this server.
102         /// </summary>
103         /// <param name="service">The service, which needs to be unregistered from this server.</param>
104         /// <remarks>
105         /// Once unregistered, the service object will become invalid and should not be used to access sevices or any children attribute's methods/members.
106         /// </remarks>
107         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
108         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
109         /// <exception cref="InvalidOperationException">Thrown when the unregister service fails.</exception>
110         /// <since_tizen> 3 </since_tizen>
111         public void UnregisterGattService(BluetoothGattService service)
112         {
113             if (service.GetGattServer() != this)
114             {
115                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
116             }
117
118             _impl.UnregisterGattService(service);
119         }
120
121         /// <summary>
122         /// Unregisters all services from this server.
123         /// </summary>
124         /// <remarks>
125         /// Once unregistered, servicees will become invalid and should not be used to access sevices or any children attribute's methods/members.
126         /// </remarks>
127         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
128         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
129         /// <exception cref="InvalidOperationException">Thrown when the unregister all services fail.</exception>
130         /// <since_tizen> 3 </since_tizen>
131         public void UnregisterGattServices()
132         {
133             _impl.UnregisterAllGattServices(this);
134         }
135
136         /// <summary>
137         /// Gets service with given UUID that belongs to this server.
138         /// </summary>
139         /// <param name="uuid">The UUID for the service to get.</param>
140         /// <returns>The Service with the given UUID if it exists, null otherwise.</returns>
141         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
142         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
143         /// <exception cref="InvalidOperationException">Thrown when the service is not registered.</exception>
144         /// <since_tizen> 3 </since_tizen>
145         public BluetoothGattService GetService(string uuid)
146         {
147             return _impl.GetService(this, uuid);
148         }
149
150         /// <summary>
151         /// Gets the list of services that belongs to this server.
152         /// </summary>
153         /// <returns>The list of services that belongs to this server.</returns>
154         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
155         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
156         /// <exception cref="InvalidOperationException">Thrown when the service is not registered.</exception>
157         /// <since_tizen> 3 </since_tizen>
158         public IEnumerable<BluetoothGattService> GetServices()
159         {
160             return _impl.GetServices(this);
161         }
162
163         /// <summary>
164         /// Sends indication for the value change of the characteristic to the remote devices.
165         /// </summary>
166         /// <param name="characteristic">The characteristic whose the value is changed.</param>
167         /// <param name="clientAddress">The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled.</param>
168         /// <returns>true on success, false otherwise.</returns>
169         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
170         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
171         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
172         /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled.</exception>
173         /// <since_tizen> 3 </since_tizen>
174         public async Task<bool> SendIndicationAsync(BluetoothGattCharacteristic characteristic, string clientAddress)
175         {
176             return await _impl.SendIndicationAsync(this, characteristic, clientAddress);
177         }
178
179         /// <summary>
180         /// Sends the notification for the value change of the characteristic to the remote devices.
181         /// </summary>
182         /// <param name="characteristic">The characteristic, which has a changed value.</param>
183         /// <param name="clientAddress">The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled.</param>
184         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
185         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
186         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
187         /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled.</exception>
188         /// <since_tizen> 3 </since_tizen>
189         public void SendNotification(BluetoothGattCharacteristic characteristic, string clientAddress)
190         {
191             _ = _impl.SendIndicationAsync(this, characteristic, clientAddress);
192         }
193
194         /// <summary>
195         /// Sends a response to the remote device as a result of a read/write request.
196         /// </summary>
197         /// <param name="requestId">The identification of a read/write request.</param>
198         /// <param name="type">The request type for read/write.</param>
199         /// <param name="status">The error value in case of failure, 0 for success.</param>
200         /// <param name="value">The value to be sent.</param>
201         /// <param name="offset">The offset from where the value is read.</param>
202         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
203         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
204         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
205         /// or when the remote device is disconnected, or the send response procedure fails.</exception>
206         /// <since_tizen> 3 </since_tizen>
207         public void SendResponse(int requestId, BluetoothGattRequestType type, int status, byte[] value, int offset)
208         {
209             _impl.SendResponse(requestId, (int)type, status, value, offset);
210         }
211
212         internal bool IsValid()
213         {
214             return _impl.GetHandle().IsInvalid == false;
215         }
216
217         /// <summary>
218         /// Destroys the current object.
219         /// </summary>
220         ~BluetoothGattServer()
221         {
222             Dispose(false);
223         }
224
225         /// <summary>
226         /// Destroys the current object.
227         /// </summary>
228         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
229         /// <since_tizen> 6 </since_tizen>
230         public void Dispose()
231         {
232             Dispose(true);
233             GC.SuppressFinalize(this);
234         }
235
236         /// <summary>
237         /// Releases all the resources currently used by this instance.
238         /// </summary>
239         /// <param name="disposing">true if the managed resources should be disposed, otherwise false.</param>
240         /// <since_tizen> 6 </since_tizen>
241         protected virtual void Dispose(bool disposing)
242         {
243             if (disposing)
244             {
245                 _impl?.GetHandle()?.Dispose();
246                 _instance = null;
247             }
248         }
249     }
250
251     /// <summary>
252     /// The Bluetooth GATT client.
253     /// </summary>
254     /// <since_tizen> 3 </since_tizen>
255     public class BluetoothGattClient : IDisposable
256     {
257         private BluetoothGattClientImpl _impl;
258         private string _remoteAddress = string.Empty;
259         private TaskCompletionSource<bool> _taskForConnection;
260         private TaskCompletionSource<bool> _taskForDisconnection;
261         private static event EventHandler<GattConnectionStateChangedEventArgs> s_connectionStateChanged;
262         private static Interop.Bluetooth.GattConnectionStateChangedCallBack s_connectionStateChangeCallback;
263
264         internal BluetoothGattClient(string remoteAddress)
265         {
266             _impl = new BluetoothGattClientImpl(remoteAddress);
267             _remoteAddress = remoteAddress;
268             StaticConnectionStateChanged += OnConnectionStateChanged;
269         }
270
271         /// <summary>
272         /// Creates the Bluetooth GATT client.
273         /// </summary>
274         /// <param name="remoteAddress">The remote device address.</param>
275         /// <returns>The BluetoothGattClient instance.</returns>
276         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
277         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
278         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
279         /// <since_tizen> 6 </since_tizen>
280         public static BluetoothGattClient CreateClient(string remoteAddress)
281         {
282             BluetoothGattClient client = new BluetoothGattClient(remoteAddress);
283             return client.Isvalid() ? client : null;
284         }
285
286         /// <summary>
287         /// The ConnectionStateChanged event is raised when the gatt connection state is changed.
288         /// </summary>
289         /// <since_tizen> 6 </since_tizen>
290         public event EventHandler<GattConnectionStateChangedEventArgs> ConnectionStateChanged;
291
292         private void OnConnectionStateChanged(Object s, GattConnectionStateChangedEventArgs e)
293         {
294             if (e.RemoteAddress == _remoteAddress)
295             {
296                 if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
297                 {
298                     if (e.Result == (int)BluetoothError.None)
299                     {
300                         _taskForConnection.SetResult(true);
301                     }
302                     else
303                     {
304                         _taskForConnection.SetException(BluetoothErrorFactory.CreateBluetoothException((int)e.Result));
305                     }
306                     _taskForConnection = null;
307                 }
308
309                 if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
310                 {
311                     if (e.Result == (int)BluetoothError.None)
312                     {
313                         _taskForDisconnection.SetResult(true);
314                     }
315                     else
316                     {
317                         _taskForDisconnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result));
318                     }
319                     _taskForDisconnection = null;
320                 }
321
322                 if (e.Result == (int)BluetoothError.None)
323                 {
324                     ConnectionStateChanged?.Invoke(this, e);
325                 }
326             }
327         }
328
329         internal static event EventHandler<GattConnectionStateChangedEventArgs> StaticConnectionStateChanged
330         {
331             add
332             {
333                 if (s_connectionStateChanged == null)
334                 {
335                     RegisterConnectionStateChangedEvent();
336                 }
337                 s_connectionStateChanged += value;
338             }
339             remove
340             {
341                 s_connectionStateChanged -= value;
342                 if (s_connectionStateChanged == null)
343                 {
344                     UnregisterConnectionStateChangedEvent();
345                 }
346             }
347         }
348
349         private static void RegisterConnectionStateChangedEvent()
350         {
351             s_connectionStateChangeCallback = (int result, bool connected, string remoteDeviceAddress, IntPtr userData) =>
352             {
353                 Log.Info(Globals.LogTag, "Setting gatt connection state changed callback");
354                 GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs(result, connected, remoteDeviceAddress);
355                 s_connectionStateChanged?.Invoke(null, e);
356             };
357
358             int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(s_connectionStateChangeCallback, IntPtr.Zero);
359             if (ret != (int)BluetoothError.None)
360             {
361                 Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret);
362             }
363         }
364
365         private static void UnregisterConnectionStateChangedEvent()
366         {
367             int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback();
368             if (ret != (int)BluetoothError.None)
369             {
370                 Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret);
371             }
372         }
373
374         /// <summary>
375         /// Connects to the remote GATT server asynchronously.
376         /// </summary>
377         /// <param name="autoConnect">The flag for reconnecting when the connection is disconnceted.</param>
378         /// <returns> A task indicating whether the method is done or not.</returns>
379         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
380         /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
381         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
382         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
383         /// <since_tizen> 6 </since_tizen>
384         public Task ConnectAsync(bool autoConnect)
385         {
386             if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
387             {
388                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
389             }
390             _taskForConnection = new TaskCompletionSource<bool>();
391             _impl.Connect(_remoteAddress, autoConnect);
392             return _taskForConnection.Task;
393         }
394
395         /// <summary>
396         /// Disconnects to the remote GATT server asynchronously.
397         /// </summary>
398         /// <returns> A task indicating whether the method is done or not.</returns>
399         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
400         /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
401         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
402         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
403         /// <since_tizen> 6 </since_tizen>
404         public Task DisconnectAsync()
405         {
406             if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
407             {
408                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
409             }
410             _taskForDisconnection = new TaskCompletionSource<bool>();
411             _impl.Disconnect(_remoteAddress);
412             return _taskForDisconnection.Task;
413         }
414
415         /// <summary>
416         /// Destroy Bluetooth GATT client
417         /// </summary>
418         /// <since_tizen> 3 </since_tizen>
419         [Obsolete("Deprecated since API level 6. Please use Dispose() method on BluetoothGattClient.")]
420         public void DestroyClient()
421         {
422             _impl.GetHandle().Dispose();
423         }
424
425         /// <summary>
426         /// The address of the remote device.
427         /// </summary>
428         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
429         /// or when the remote device is disconnected.</exception>
430         /// <since_tizen> 3 </since_tizen>
431         public string RemoteAddress
432         {
433             get
434             {
435                 if (string.IsNullOrEmpty(_remoteAddress))
436                 {
437                     _remoteAddress = _impl.GetRemoteAddress();
438                 }
439                 return _remoteAddress;
440             }
441         }
442
443         /// <summary>
444         /// Gets the service with the given UUID that belongs to the remote device.
445         /// </summary>
446         /// <param name="uuid">The UUID for the service to get.</param>
447         /// <returns>The service with the given UUID if it exists, null otherwise.</returns>
448         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
449         /// or when the remote device is disconnected, or when the get service fails.</exception>
450         /// <since_tizen> 3 </since_tizen>
451         public BluetoothGattService GetService(string uuid)
452         {
453             return _impl.GetService(this, uuid);
454         }
455
456         /// <summary>
457         /// Gets list of services that belongs to the remote device.
458         /// </summary>
459         /// <returns>The list of services that belongs to the remote device.</returns>
460         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
461         /// or when the remote device is disconnected, or when the get service fails.</exception>
462         /// <since_tizen> 3 </since_tizen>
463         public IEnumerable<BluetoothGattService> GetServices()
464         {
465             return _impl.GetServices(this);
466         }
467
468         /// <summary>
469         /// Reads the value of a given characteristic from the remote device asynchronously.
470         /// </summary>
471         /// <param name="characteristic">The characteristic to be read.</param>
472         /// <returns>true on success, false otherwise.</returns>
473         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
474         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
475         /// <since_tizen> 3 </since_tizen>
476         public async Task<bool> ReadValueAsync(BluetoothGattCharacteristic characteristic)
477         {
478             return await _impl.ReadValueAsyncTask(characteristic.GetHandle());
479         }
480
481         /// <summary>
482         /// Reads the value of the given descriptor from the remote device asynchronously.
483         /// </summary>
484         /// <param name="descriptor">The descriptor to be read.</param>
485         /// <returns>true on success, false otherwise.</returns>
486         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
487         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
488         /// <since_tizen> 3 </since_tizen>
489         public async Task<bool> ReadValueAsync(BluetoothGattDescriptor descriptor)
490         {
491             return await _impl.ReadValueAsyncTask(descriptor.GetHandle());
492         }
493
494         /// <summary>
495         /// Writes the value of a given characteristic to the remote device asynchronously.
496         /// </summary>
497         /// <param name="characteristic">The characteristic to be written.</param>
498         /// <returns>true on success, false otherwise.</returns>
499         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
500         /// or when the remote device is disconnected or when the write attribute value fails.</exception>
501         /// <since_tizen> 3 </since_tizen>
502         public async Task<bool> WriteValueAsync(BluetoothGattCharacteristic characteristic)
503         {
504             return await _impl.WriteValueAsyncTask(characteristic.GetHandle());
505         }
506
507         /// <summary>
508         /// Writes the value of the given descriptor to the remote device asynchronously.
509         /// </summary>
510         /// <param name="descriptor">The descriptor to be written.</param>
511         /// <returns>true on success, false otherwise.</returns>
512         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
513         /// or when the remote device is disconnected, or when the write attribute value fails.</exception>
514         /// <since_tizen> 3 </since_tizen>
515         public async Task<bool> WriteValueAsync(BluetoothGattDescriptor descriptor)
516         {
517             return await _impl.WriteValueAsyncTask(descriptor.GetHandle());
518         }
519
520         internal bool Isvalid()
521         {
522             return _impl.GetHandle().IsInvalid == false;
523         }
524
525         /// <summary>
526         /// Destroys the current object.
527         /// </summary>
528         ~BluetoothGattClient()
529         {
530             Dispose(false);
531         }
532
533         /// <summary>
534         /// Destroys the current object.
535         /// </summary>
536         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
537         /// <since_tizen> 6 </since_tizen>
538         public void Dispose()
539         {
540             Dispose(true);
541             GC.SuppressFinalize(this);
542         }
543
544         /// <summary>
545         /// Releases all the resources currently used by this instance.
546         /// </summary>
547         /// <param name="disposing">true if the managed resources should be disposed, otherwise false.</param>
548         /// <since_tizen> 6 </since_tizen>
549         protected virtual void Dispose(bool disposing)
550         {
551             if (disposing)
552             {
553                 _impl?.GetHandle()?.Dispose();
554                 _impl = null;
555                 StaticConnectionStateChanged -= OnConnectionStateChanged;
556             }
557         }
558     }
559
560     /// <summary>
561     /// The Bluetooth GATT service.
562     /// </summary>
563     /// <since_tizen> 3 </since_tizen>
564     public class BluetoothGattService
565     {
566         private BluetoothGattServiceImpl _impl;
567         private BluetoothGattClient _parentClient = null;
568         private BluetoothGattServer _parentServer = null;
569         private BluetoothGattService _parentService = null;
570
571         /// <summary>
572         /// The constructor.
573         /// </summary>
574         /// <param name="uuid">The UUID of the service.</param>
575         /// <param name="type">The type of service.</param>
576         /// <exception cref="InvalidOperationException">Thrown when the create GATT service procedure fails.</exception>
577         /// <since_tizen> 3 </since_tizen>
578         public BluetoothGattService(string uuid, BluetoothGattServiceType type)
579         {
580             Uuid = uuid;
581             _impl = new BluetoothGattServiceImpl(uuid, type);
582         }
583
584         internal BluetoothGattService(BluetoothGattServiceImpl impl, string uuid)
585         {
586             Uuid = uuid;
587             _impl = impl;
588         }
589
590         /// <summary>
591         /// Specification name from the UUID.
592         /// </summary>
593         /// <since_tizen> 3 </since_tizen>
594         public string Uuid { get; }
595
596         /// <summary>
597         /// Adds a characteristic to this service.
598         /// </summary>
599         /// <param name="characteristic">The characteristic to be added.</param>
600         /// <returns>true on success, false otherwise.</returns>
601         /// <exception cref="InvalidOperationException">Thrown when the add GATT characteristic procedure fails.</exception>
602         /// <since_tizen> 3 </since_tizen>
603         public void AddCharacteristic(BluetoothGattCharacteristic characteristic)
604         {
605             if (GetGattClient() != null)
606             {
607                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
608             }
609
610             if (characteristic.GetService() != null)
611             {
612                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
613             }
614
615             _impl.AddCharacteristic(characteristic);
616             characteristic.SetParent(this);
617         }
618
619         /// <summary>
620         /// Gets the characteristic with the given UUID that belongs to this service.
621         /// </summary>
622         /// <param name="uuid">The UUID for the characteristic to get.</param>
623         /// <returns>The characteristic with a given UUID if it exists, null otherwise.</returns>
624         /// <since_tizen> 3 </since_tizen>
625         public BluetoothGattCharacteristic GetCharacteristic(string uuid)
626         {
627             return _impl.GetCharacteristic(this, uuid);
628         }
629
630         /// <summary>
631         /// Gets list of the characteristic that belongs to this service.
632         /// </summary>
633         /// <returns>The list of the characteristic that belongs to this service.</returns>
634         /// <since_tizen> 3 </since_tizen>
635         public IEnumerable<BluetoothGattCharacteristic> GetCharacteristics()
636         {
637             return _impl.GetCharacteristics(this);
638         }
639
640         /// <summary>
641         /// Includes a service to this service.
642         /// </summary>
643         /// <param name="service">The service to be included.</param>
644         /// <returns>true on success, false otherwise</returns>
645         /// <exception cref="InvalidOperationException">Thrown when the add GATT service procedure fails.</exception>///
646         /// <since_tizen> 3 </since_tizen>
647         public void AddService(BluetoothGattService service)
648         {
649             if (GetGattClient() != null)
650             {
651                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
652             }
653
654             if (service.IsRegistered())
655             {
656                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
657             }
658
659             _impl.AddIncludeService(service);
660             service.SetParent(this);
661         }
662
663         /// <summary>
664         /// Gets the included service.
665         /// </summary>
666         /// <param name="uuid">The UUID for the service to get.</param>
667         /// <returns>The service with a given UUID if it exists, null otherwise.</returns>
668         /// <since_tizen> 3 </since_tizen>
669         public BluetoothGattService GetIncludeService(string uuid)
670         {
671             return _impl.GetIncludeService(this, uuid);
672         }
673
674         /// <summary>
675         /// Gets the included service list of this service.
676         /// </summary>
677         /// <returns>The included service list of this service.</returns>
678         /// <since_tizen> 3 </since_tizen>
679         public IEnumerable<BluetoothGattService> GetIncludeServices()
680         {
681             return _impl.GetIncludeServices(this);
682         }
683
684         /// <summary>
685         /// Gets the server instance which the specified service belongs to.
686         /// </summary>
687         /// <returns>The server instance which the specified service belongs to.</returns>
688         /// <since_tizen> 3 </since_tizen>
689         public BluetoothGattServer GetGattServer()
690         {
691             return _parentServer;
692         }
693
694         /// <summary>
695         /// Gets the client instance which the specified service belongs to.
696         /// </summary>
697         /// <returns>The client instance which the specified service belongs to.</returns>
698         /// <since_tizen> 3 </since_tizen>
699         public BluetoothGattClient GetGattClient()
700         {
701             return _parentClient;
702         }
703
704         internal BluetoothGattAttributeHandle GetHandle()
705         {
706             return _impl.GetHandle();
707         }
708
709         internal void SetParent(BluetoothGattService parent)
710         {
711             if (!IsRegistered())
712             {
713                 _parentService = parent;
714                 _impl.ReleaseHandleOwnership();
715             }
716         }
717
718         internal void SetParent(BluetoothGattClient parent)
719         {
720             if (!IsRegistered())
721             {
722                 _parentClient = parent;
723                 _impl.ReleaseHandleOwnership();
724             }
725         }
726
727         internal void SetParent(BluetoothGattServer parent)
728         {
729             if (!IsRegistered())
730             {
731                 _parentServer = parent;
732                 _impl.ReleaseHandleOwnership();
733             }
734         }
735
736         internal void UnregisterService()
737         {
738             _parentServer = null;
739             _parentClient = null;
740             _parentService = null;
741         }
742
743         internal bool IsRegistered()
744         {
745             return _parentClient != null || _parentServer != null || _parentService != null;
746         }
747     }
748
749     /// <summary>
750     /// The Bluetooth GATT characteristic.
751     /// </summary>
752     /// <since_tizen> 3 </since_tizen>
753     public class BluetoothGattCharacteristic : BluetoothGattAttribute
754     {
755         private BluetoothGattCharacteristicImpl _impl;
756         private BluetoothGattService _parent = null;
757
758         private Interop.Bluetooth.BtClientCharacteristicValueChangedCallback _characteristicValueChangedCallback;
759         private Interop.Bluetooth.BtGattServerNotificationStateChangeCallback _notificationStateChangedCallback;
760
761         private EventHandler<ValueChangedEventArgs> _characteristicValueChanged;
762         internal EventHandler<NotificationStateChangedEventArg> _notificationStateChanged;
763
764         /// <summary>
765         /// The constructor.
766         /// </summary>
767         /// <param name="uuid">The UUID of the characterstic.</param>
768         /// <param name="permissions">Permissions for the characterstic.</param>
769         /// <param name="properties">Properties set for the characterstic.</param>
770         /// <param name="value">The value associated with the characterstic.</param>
771         /// <remarks>throws in case of internal error.</remarks>
772         /// <exception cref="InvalidOperationException">Thrown when the create GATT characteristics procedure fails.</exception>
773         /// <since_tizen> 3 </since_tizen>
774         public BluetoothGattCharacteristic(string uuid, BluetoothGattPermission permissions, BluetoothGattProperty properties, byte[] value) : base(uuid, permissions)
775         {
776             _impl = new BluetoothGattCharacteristicImpl(uuid, permissions, properties, value);
777         }
778
779         internal BluetoothGattCharacteristic(BluetoothGattCharacteristicImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
780         {
781             _impl = impl;
782         }
783
784         /// <summary>
785         /// The CharacteristicValueChanged event is raised when the server notifies for change in this characteristic value.
786         /// </summary>
787         /// <remarks>
788         /// Adding the event handle on characteristic on the server side will not have any effect.
789         /// </remarks>
790         /// <since_tizen> 3 </since_tizen>
791         public event EventHandler<ValueChangedEventArgs> ValueChanged
792         {
793             add
794             {
795                 if (Client != null)
796                 {
797                     if (_characteristicValueChanged == null)
798                     {
799                         _characteristicValueChangedCallback = (gattHandle, characteristicValue, len, userData) =>
800                         {
801                             _characteristicValueChanged?.Invoke(this, new ValueChangedEventArgs(characteristicValue, len));
802                         };
803
804                         _impl.SetCharacteristicValueChangedEvent(_characteristicValueChangedCallback);
805                     }
806                     _characteristicValueChanged = value;
807                 }
808             }
809             remove
810             {
811                 if (Client != null)
812                 {
813                     _characteristicValueChanged = null;
814                     if (_characteristicValueChanged == null)
815                     {
816                         _impl.UnsetCharacteristicValueChangedEvent();
817                     }
818
819                 }
820             }
821         }
822
823         /// <summary>
824         /// The NotificationStateChanged event is called when the client enables or disables the Notification/Indication for particular characteristics.
825         /// </summary>
826         /// <remarks>
827         /// BluetoothGattServer.RegisterGattService() should be called before adding/removing this EventHandler.
828         /// Adding event handle on the characteristic on the client side will not have any effect.
829         /// </remarks>
830         /// <since_tizen> 3 </since_tizen>
831         public event EventHandler<NotificationStateChangedEventArg> NotificationStateChanged
832         {
833             add
834             {
835                 if (Server != null)
836                 {
837                     if (_notificationStateChangedCallback == null)
838                     {
839                         _notificationStateChangedCallback = (notify, serverHandle, characteristicHandle, userData) =>
840                         {
841                             _notificationStateChanged?.Invoke(this, new NotificationStateChangedEventArg(Server, notify));
842                         };
843
844                         _impl.SetNotificationStateChangedEvent(_notificationStateChangedCallback);
845                     }
846
847                     _notificationStateChanged = value;
848                 }
849             }
850             remove
851             {
852                 if (Server != null)
853                 {
854                     _notificationStateChanged = null;
855                     // CAPI does not allow unsetting ReadValueRequestedEventCallback.
856                 }
857             }
858         }
859
860         /// <summary>
861         /// The property for this characteristic.
862         /// </summary>
863         /// <since_tizen> 3 </since_tizen>
864         public BluetoothGattProperty Properties
865         {
866             get
867             {
868                 return _impl.GetProperties();
869             }
870             set
871             {
872                 if (Server != null)
873                 {
874                     _impl.SetProperties(value);
875                 }
876             }
877         }
878
879         /// <summary>
880         /// The write type to be used for write operations.
881         /// </summary>
882         /// <since_tizen> 3 </since_tizen>
883         public BluetoothGattWriteType WriteType
884         {
885             get
886             {
887                 return _impl.GetWriteType();
888             }
889             set
890             {
891                 _impl.SetWriteType(value);
892             }
893         }
894
895         internal override BluetoothGattClient Client
896         {
897             get
898             {
899                 return _parent?.GetGattClient();
900             }
901         }
902
903         internal override BluetoothGattServer Server
904         {
905             get
906             {
907                 return _parent?.GetGattServer();
908             }
909         }
910
911         internal override BluetoothGattAttributeImpl Impl
912         {
913             get
914             {
915                 return _impl;
916             }
917         }
918
919         /// <summary>
920         /// Adds a descriptor to this characteristic.
921         /// </summary>
922         /// <param name="descriptor">The descriptor to be added.</param>
923         /// <returns>true on success, false otherwise.</returns>
924         /// <exception cref="InvalidOperationException">Thrown when the add GATT descriptor procedure fails.</exception>
925         /// <since_tizen> 3 </since_tizen>
926         public void AddDescriptor(BluetoothGattDescriptor descriptor)
927         {
928             if (Client != null)
929             {
930                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
931             }
932
933             if (descriptor.GetCharacteristic() != null)
934             {
935                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
936             }
937
938             _impl.AddDescriptor(descriptor);
939             descriptor.SetParent(this);
940         }
941
942         /// <summary>
943         /// Gets the descriptor with the given UUID that belongs to this characteristic.
944         /// </summary>
945         /// <param name="uuid">The UUID for the descriptor to get.</param>
946         /// <returns>The descriptor with a given UUID if it exists, null otherwise.</returns>
947         /// <since_tizen> 3 </since_tizen>
948         public BluetoothGattDescriptor GetDescriptor(string uuid)
949         {
950             return _impl.GetDescriptor(this, uuid);
951         }
952
953         /// <summary>
954         /// Gets the list of descriptors that belongs to this characteristic.
955         /// </summary>
956         /// <returns>The list of descriptors that belongs to this characteristic.</returns>
957         /// <since_tizen> 3 </since_tizen>
958         public IEnumerable<BluetoothGattDescriptor> GetDescriptors()
959         {
960             return _impl.GetDescriptors(this);
961         }
962
963         /// <summary>
964         /// Gets the service instance, which the specified characterstic belongs to.
965         /// </summary>
966         /// <returns>The characteristic instance, the specified characterstic belongs to.</returns>
967         /// <since_tizen> 3 </since_tizen>
968         public BluetoothGattService GetService()
969         {
970             return _parent;
971         }
972
973         internal void SetParent(BluetoothGattService parent)
974         {
975             if (_parent == null)
976             {
977                 _parent = parent;
978                 ReleaseHandleOwnership();
979             }
980          }
981     }
982
983     /// <summary>
984     /// The Bluetooth GATT descriptor.
985     /// </summary>
986     /// <since_tizen> 3 </since_tizen>
987     public class BluetoothGattDescriptor : BluetoothGattAttribute
988     {
989         private BluetoothGattCharacteristic _parent = null;
990         private BluetoothGattDescriptorImpl _impl;
991
992         /// <summary>
993         /// The constructor.
994         /// </summary>
995         /// <param name="uuid">The UUID of the descriptor.</param>
996         /// <param name="permisions">Permissions for the descriptor.</param>
997         /// <param name="value">The value associated with the descriptor.</param>
998         /// <remarks>throws in case of internal error.</remarks>
999         /// <exception cref="InvalidOperationException">Thrown when the create GATT descriptor procedure fails.</exception>
1000         /// <since_tizen> 3 </since_tizen>
1001         public BluetoothGattDescriptor(string uuid, BluetoothGattPermission permisions, byte[] value) : base (uuid, permisions)
1002         {
1003             _impl = new BluetoothGattDescriptorImpl(uuid, permisions, value);
1004         }
1005
1006         internal BluetoothGattDescriptor(BluetoothGattDescriptorImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
1007         {
1008             _impl = impl;
1009         }
1010
1011         internal override BluetoothGattClient Client
1012         {
1013             get
1014             {
1015                 return _parent?.Client;
1016             }
1017         }
1018
1019         internal override BluetoothGattServer Server
1020         {
1021             get
1022             {
1023                 return _parent?.Server;
1024             }
1025         }
1026
1027         internal override BluetoothGattAttributeImpl Impl
1028         {
1029             get
1030             {
1031                 return _impl;
1032             }
1033         }
1034
1035         /// <summary>
1036         /// Gets the characteristic instance, which the specified descriptor belongs to.
1037         /// </summary>
1038         /// <returns>The characteristic instance, the specified descriptor belongs to.</returns>
1039         /// <since_tizen> 3 </since_tizen>
1040         public BluetoothGattCharacteristic GetCharacteristic()
1041         {
1042             return _parent;
1043         }
1044
1045         internal void SetParent(BluetoothGattCharacteristic parent)
1046         {
1047             if (_parent == null)
1048             {
1049                 _parent = parent;
1050                 ReleaseHandleOwnership();
1051             }
1052         }
1053     }
1054
1055     /// <summary>
1056     /// The Bluetooth GATT attribute.
1057     /// </summary>
1058     /// <since_tizen> 3 </since_tizen>
1059     public abstract class BluetoothGattAttribute
1060     {
1061         private Interop.Bluetooth.BtGattServerReadValueRequestedCallback _readValueRequestedCallback;
1062         private Interop.Bluetooth.BtGattServerWriteValueRequestedCallback _writeValueRequestedCallback;
1063
1064         private EventHandler<ReadRequestedEventArgs> _readValueRequested;
1065         private EventHandler<WriteRequestedEventArgs> _writeValueRequested;
1066
1067         /// <summary>
1068         /// The constructor.
1069         /// </summary>
1070         /// <param name="uuid">The UUID of the GATT attribute.</param>
1071         /// <param name="permission">Permission for the GATT attribute.</param>
1072         /// <since_tizen> 3 </since_tizen>
1073         public BluetoothGattAttribute(string uuid, BluetoothGattPermission permission)
1074         {
1075             Uuid = uuid;
1076             Permissions = permission;
1077         }
1078
1079         // Events
1080
1081         /// <summary>
1082         /// This event is called when the client request to read the value of a characteristic or a descriptor.
1083         /// </summary>
1084         /// <remarks>
1085         /// BluetoothGattServer.RegisterGattService() should be called before adding/removing this EventHandler.
1086         /// </remarks>
1087         /// <exception cref="InvalidOperationException">Thrown when the set read value requested callback procedure fails.</exception>
1088         /// <since_tizen> 3 </since_tizen>
1089         public event EventHandler<ReadRequestedEventArgs> ReadRequested
1090         {
1091             add
1092             {
1093                 if (Server == null) return;
1094                 if (_readValueRequestedCallback == null)
1095                 {
1096                     _readValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, offset, userData) =>
1097                     {
1098                         _readValueRequested?.Invoke(this, new ReadRequestedEventArgs(Server, clientAddress, requestId, offset));
1099                     };
1100                     Impl.SetReadValueRequestedEventCallback(_readValueRequestedCallback);
1101                 }
1102                 _readValueRequested = value;
1103             }
1104             remove
1105             {
1106                 if (Server == null) return;
1107                 _readValueRequested = null;
1108                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
1109             }
1110         }
1111
1112         /// <summary>
1113         /// This event is called when a value of a characteristic or a descriptor has been changed by a client.
1114         /// </summary>
1115         /// <remarks>
1116         /// BluetoothGattServer.RegisterGattService() should be called before adding/removing this EventHandler.
1117         /// </remarks>
1118         /// <exception cref="InvalidOperationException">Thrown when the set write value requested callback procedure fails.</exception>
1119         /// <since_tizen> 3 </since_tizen>
1120         public event EventHandler<WriteRequestedEventArgs> WriteRequested
1121         {
1122             add
1123             {
1124                 if (Server == null) return;
1125                 if (_writeValueRequested == null)
1126                 {
1127                     _writeValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, response_needed, offset, valueToWrite, len, userData) =>
1128                     {
1129                         byte[] writeValue = new byte[len];
1130                         Marshal.Copy(valueToWrite, writeValue, 0, len);
1131                         _writeValueRequested?.Invoke(this, new WriteRequestedEventArgs(Server, clientAddress, requestId, writeValue, offset, response_needed));
1132                     };
1133                     Impl.SetWriteValueRequestedEventCallback(_writeValueRequestedCallback);
1134                 }
1135                 _writeValueRequested = value;
1136             }
1137             remove
1138             {
1139                 if (Server == null) return;
1140                 _writeValueRequested = null;
1141                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
1142             }
1143         }
1144
1145         /// <summary>
1146         /// The attribute's UUID.
1147         /// </summary>
1148         /// <since_tizen> 3 </since_tizen>
1149         public string Uuid { get; }
1150
1151         /// <summary>
1152         /// Permissions for this attribute.
1153         /// </summary>
1154         /// <since_tizen> 3 </since_tizen>
1155         public BluetoothGattPermission Permissions { get; }
1156
1157         /// <summary>
1158         /// The value of this descriptor.
1159         /// </summary>
1160         /// <since_tizen> 3 </since_tizen>
1161         public byte[] Value
1162         {
1163             get
1164             {
1165                 return Impl.GetValue();
1166             }
1167             set
1168             {
1169                 Impl.SetValue(value);
1170             }
1171         }
1172
1173         internal abstract BluetoothGattClient Client { get; }
1174         internal abstract BluetoothGattServer Server { get; }
1175         internal abstract BluetoothGattAttributeImpl Impl { get; }
1176
1177         /// <summary>
1178         /// Returns a string value at the specified offset.
1179         /// </summary>
1180         /// <param name="offset">An offset in the attribute value buffer.</param>
1181         /// <returns>The string value at specified offset.</returns>
1182         /// <since_tizen> 3 </since_tizen>
1183         public string GetValue(int offset)
1184         {
1185             return Impl.GetValue(offset);
1186         }
1187
1188         /// <summary>
1189         /// Sets the string value as a specified offset.
1190         /// </summary>
1191         /// <param name="value">value to set</param>
1192         /// <exception cref="InvalidOperationException">Throws exception if the value is null.</exception>
1193         /// <since_tizen> 3 </since_tizen>
1194         public void SetValue(string value)
1195         {
1196             if (string.IsNullOrEmpty(value))
1197                 GattUtil.ThrowForError((int)BluetoothError.InvalidParameter, "value should not be null");
1198
1199             byte[] val = Encoding.UTF8.GetBytes(value);
1200             Impl.SetValue(val);
1201         }
1202
1203         /// <summary>
1204         /// Returns a value at specified offset as the int value of the specified type.
1205         /// </summary>
1206         /// <param name="type">The type of the int value.</param>
1207         /// <param name="offset">An offset in the attribute value buffer.</param>
1208         /// <returns>The int value at given offset.</returns>
1209         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1210         /// <since_tizen> 3 </since_tizen>
1211         public int GetValue(IntDataType type, int offset)
1212         {
1213             return Impl.GetValue(type, offset);
1214         }
1215
1216         /// <summary>
1217         /// Updates a value at the specified offset by the int value of the specified type.
1218         /// </summary>
1219         /// <param name="type">The type of the int value.</param>
1220         /// <param name="value">The value to set.</param>
1221         /// <param name="offset">An offset in the attribute value buffer.</param>
1222         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1223         /// <since_tizen> 3 </since_tizen>
1224         public void SetValue(IntDataType type, int value, int offset)
1225         {
1226             Impl.SetValue(type, value, offset);
1227         }
1228
1229         /// <summary>
1230         /// Returns a value at the specified offset as the float value of the specified type.
1231         /// </summary>
1232         /// <param name="type">The type of the float value.</param>
1233         /// <param name="offset">An offset in the attribute value buffer.</param>
1234         /// <returns>The float value at given offset.</returns>
1235         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1236         /// <since_tizen> 3 </since_tizen>
1237         public float GetValue(FloatDataType type, int offset)
1238         {
1239             return Impl.GetValue(type, offset);
1240         }
1241
1242         /// <summary>
1243         /// Updates the value at the specified offset by the float value of the specified type.
1244         /// </summary>
1245         /// <param name="type">The type of the float value.</param>
1246         /// <param name="mantissa">The mantissa of the float value.</param>
1247         /// <param name="exponent">An exponent of the float value.</param>
1248         /// <param name="offset">An offset in the attribute value buffer.</param>
1249         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1250         /// <since_tizen> 3 </since_tizen>
1251         public void SetValue(FloatDataType type, int mantissa, int exponent, int offset)
1252         {
1253             Impl.SetValue(type, mantissa, exponent, offset);
1254         }
1255
1256         internal void ReleaseHandleOwnership()
1257         {
1258             Impl.ReleaseHandleOwnership();
1259         }
1260
1261         internal BluetoothGattAttributeHandle GetHandle()
1262         {
1263             return Impl.GetHandle();
1264         }
1265     }
1266 }