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