5a40d27e112a769fc539c6c837b8525b4f4d579e
[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
261     {
262         private BluetoothGattClientImpl _impl;
263         private string _remoteAddress = string.Empty;
264
265         internal BluetoothGattClient(string remoteAddress)
266         {
267             _impl = new BluetoothGattClientImpl(remoteAddress);
268             _remoteAddress = remoteAddress;
269         }
270
271         internal static BluetoothGattClient CreateClient(string remoteAddress)
272         {
273             BluetoothGattClient client = new BluetoothGattClient(remoteAddress);
274             return client.Isvalid() ? client : null;
275         }
276
277         /// <summary>
278         /// Destroy Bluetooth GATT client
279         /// </summary>
280         /// <since_tizen> 3 </since_tizen>
281         public void DestroyClient()
282         {
283             _impl.GetHandle().Dispose();
284         }
285
286         /// <summary>
287         /// The address of the remote device.
288         /// </summary>
289         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
290         /// or when the remote device is disconnected.</exception>
291         /// <since_tizen> 3 </since_tizen>
292         public string RemoteAddress
293         {
294             get
295             {
296                 if (string.IsNullOrEmpty(_remoteAddress))
297                 {
298                     _remoteAddress = _impl.GetRemoteAddress();
299                 }
300                 return _remoteAddress;
301             }
302         }
303
304         /// <summary>
305         /// Gets the service with the given UUID that belongs to the remote device.
306         /// </summary>
307         /// <param name="uuid">The UUID for the service to get.</param>
308         /// <returns>The service with the given UUID if it exists, null otherwise.</returns>
309         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
310         /// or when the remote device is disconnected, or when the get service fails.</exception>
311         /// <since_tizen> 3 </since_tizen>
312         public BluetoothGattService GetService(string uuid)
313         {
314             return _impl.GetService(this, uuid);
315         }
316
317         /// <summary>
318         /// Gets list of services that belongs to the remote device.
319         /// </summary>
320         /// <returns>The list of services that belongs to the remote device.</returns>
321         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
322         /// or when the remote device is disconnected, or when the get service fails.</exception>
323         /// <since_tizen> 3 </since_tizen>
324         public IEnumerable<BluetoothGattService> GetServices()
325         {
326             return _impl.GetServices(this);
327         }
328
329         /// <summary>
330         /// Reads the value of a given characteristic from the remote device asynchronously.
331         /// </summary>
332         /// <param name="characteristic">The characteristic to be read.</param>
333         /// <returns>true on success, false otherwise.</returns>
334         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
335         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
336         /// <since_tizen> 3 </since_tizen>
337         public async Task<bool> ReadValueAsync(BluetoothGattCharacteristic characteristic)
338         {
339             return await _impl.ReadValueAsyncTask(characteristic.GetHandle());
340         }
341
342         /// <summary>
343         /// Reads the value of the given descriptor from the remote device asynchronously.
344         /// </summary>
345         /// <param name="descriptor">The descriptor to be read.</param>
346         /// <returns>true on success, false otherwise.</returns>
347         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
348         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
349         /// <since_tizen> 3 </since_tizen>
350         public async Task<bool> ReadValueAsync(BluetoothGattDescriptor descriptor)
351         {
352             return await _impl.ReadValueAsyncTask(descriptor.GetHandle());
353         }
354
355         /// <summary>
356         /// Writes the value of a given characteristic to the remote device asynchronously.
357         /// </summary>
358         /// <param name="characteristic">The characteristic to be written.</param>
359         /// <returns>true on success, false otherwise.</returns>
360         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
361         /// or when the remote device is disconnected or when the write attribute value fails.</exception>
362         /// <since_tizen> 3 </since_tizen>
363         public async Task<bool> WriteValueAsync(BluetoothGattCharacteristic characteristic)
364         {
365             return await _impl.WriteValueAsyncTask(characteristic.GetHandle());
366         }
367
368         /// <summary>
369         /// Writes the value of the given descriptor to the remote device asynchronously.
370         /// </summary>
371         /// <param name="descriptor">The descriptor to be written.</param>
372         /// <returns>true on success, false otherwise.</returns>
373         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
374         /// or when the remote device is disconnected, or when the write attribute value fails.</exception>
375         /// <since_tizen> 3 </since_tizen>
376         public async Task<bool> WriteValueAsync(BluetoothGattDescriptor descriptor)
377         {
378             return await _impl.WriteValueAsyncTask(descriptor.GetHandle());
379         }
380
381         internal bool Isvalid()
382         {
383             return _impl.GetHandle().IsInvalid == false;
384         }
385     }
386
387     /// <summary>
388     /// The Bluetooth GATT service.
389     /// </summary>
390     /// <since_tizen> 3 </since_tizen>
391     public class BluetoothGattService
392     {
393         private BluetoothGattServiceImpl _impl;
394         private BluetoothGattClient _parentClient = null;
395         private BluetoothGattServer _parentServer = null;
396         private BluetoothGattService _parentService = null;
397
398         /// <summary>
399         /// The constructor.
400         /// </summary>
401         /// <param name="uuid">The UUID of the service.</param>
402         /// <param name="type">The type of service.</param>
403         /// <exception cref="InvalidOperationException">Thrown when the create GATT service procedure fails.</exception>
404         /// <since_tizen> 3 </since_tizen>
405         public BluetoothGattService(string uuid, BluetoothGattServiceType type)
406         {
407             Uuid = uuid;
408             _impl = new BluetoothGattServiceImpl(uuid, type);
409         }
410
411         internal BluetoothGattService(BluetoothGattServiceImpl impl, string uuid)
412         {
413             Uuid = uuid;
414             _impl = impl;
415         }
416
417         /// <summary>
418         /// Specification name from the UUID.
419         /// </summary>
420         /// <since_tizen> 3 </since_tizen>
421         public string Uuid { get; }
422
423         /// <summary>
424         /// Adds a characteristic to this service.
425         /// </summary>
426         /// <param name="characteristic">The characteristic to be added.</param>
427         /// <returns>true on success, false otherwise.</returns>
428         /// <exception cref="InvalidOperationException">Thrown when the add GATT characteristic procedure fails.</exception>
429         /// <since_tizen> 3 </since_tizen>
430         public void AddCharacteristic(BluetoothGattCharacteristic characteristic)
431         {
432             if (GetGattClient() != null)
433             {
434                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
435             }
436
437             if (characteristic.GetService() != null)
438             {
439                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
440             }
441
442             _impl.AddCharacteristic(characteristic);
443             characteristic.SetParent(this);
444         }
445
446         /// <summary>
447         /// Gets the characteristic with the given UUID that belongs to this service.
448         /// </summary>
449         /// <param name="uuid">The UUID for the characteristic to get.</param>
450         /// <returns>The characteristic with a given UUID if it exists, null otherwise.</returns>
451         /// <since_tizen> 3 </since_tizen>
452         public BluetoothGattCharacteristic GetCharacteristic(string uuid)
453         {
454             return _impl.GetCharacteristic(this, uuid);
455         }
456
457         /// <summary>
458         /// Gets list of the characteristic that belongs to this service.
459         /// </summary>
460         /// <returns>The list of the characteristic that belongs to this service.</returns>
461         /// <since_tizen> 3 </since_tizen>
462         public IEnumerable<BluetoothGattCharacteristic> GetCharacteristics()
463         {
464             return _impl.GetCharacteristics(this);
465         }
466
467         /// <summary>
468         /// Includes a service to this service.
469         /// </summary>
470         /// <param name="service">The service to be included.</param>
471         /// <returns>true on success, false otherwise</returns>
472         /// <exception cref="InvalidOperationException">Thrown when the add GATT service procedure fails.</exception>///
473         /// <since_tizen> 3 </since_tizen>
474         public void AddService(BluetoothGattService service)
475         {
476             if (GetGattClient() != null)
477             {
478                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
479             }
480
481             if (service.IsRegistered())
482             {
483                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
484             }
485
486             _impl.AddIncludeService(service);
487             service.SetParent(this);
488         }
489
490         /// <summary>
491         /// Gets the included service.
492         /// </summary>
493         /// <param name="uuid">The UUID for the service to get.</param>
494         /// <returns>The service with a given UUID if it exists, null otherwise.</returns>
495         /// <since_tizen> 3 </since_tizen>
496         public BluetoothGattService GetIncludeService(string uuid)
497         {
498             return _impl.GetIncludeService(this, uuid);
499         }
500
501         /// <summary>
502         /// Gets the included service list of this service.
503         /// </summary>
504         /// <returns>The included service list of this service.</returns>
505         /// <since_tizen> 3 </since_tizen>
506         public IEnumerable<BluetoothGattService> GetIncludeServices()
507         {
508             return _impl.GetIncludeServices(this);
509         }
510
511         /// <summary>
512         /// Gets the server instance which the specified service belongs to.
513         /// </summary>
514         /// <returns>The server instance which the specified service belongs to.</returns>
515         /// <since_tizen> 3 </since_tizen>
516         public BluetoothGattServer GetGattServer()
517         {
518             return _parentServer;
519         }
520
521         /// <summary>
522         /// Gets the client instance which the specified service belongs to.
523         /// </summary>
524         /// <returns>The client instance which the specified service belongs to.</returns>
525         /// <since_tizen> 3 </since_tizen>
526         public BluetoothGattClient GetGattClient()
527         {
528             return _parentClient;
529         }
530
531         internal BluetoothGattAttributeHandle GetHandle()
532         {
533             return _impl.GetHandle();
534         }
535
536         internal void SetParent(BluetoothGattService parent)
537         {
538             if (!IsRegistered())
539             {
540                 _parentService = parent;
541                 _impl.ReleaseHandleOwnership();
542             }
543         }
544
545         internal void SetParent(BluetoothGattClient parent)
546         {
547             if (!IsRegistered())
548             {
549                 _parentClient = parent;
550                 _impl.ReleaseHandleOwnership();
551             }
552         }
553
554         internal void SetParent(BluetoothGattServer parent)
555         {
556             if (!IsRegistered())
557             {
558                 _parentServer = parent;
559                 _impl.ReleaseHandleOwnership();
560             }
561         }
562
563         internal void UnregisterService()
564         {
565             _parentServer = null;
566             _parentClient = null;
567             _parentService = null;
568         }
569
570         internal bool IsRegistered()
571         {
572             return _parentClient != null || _parentServer != null || _parentService != null;
573         }
574     }
575
576     /// <summary>
577     /// The Bluetooth GATT characteristic.
578     /// </summary>
579     /// <since_tizen> 3 </since_tizen>
580     public class BluetoothGattCharacteristic : BluetoothGattAttribute
581     {
582         private BluetoothGattCharacteristicImpl _impl;
583         private BluetoothGattService _parent = null;
584
585         private Interop.Bluetooth.BtClientCharacteristicValueChangedCallback _characteristicValueChangedCallback;
586         private Interop.Bluetooth.BtGattServerNotificationStateChangeCallback _notificationStateChangedCallback;
587
588         private EventHandler<ValueChangedEventArgs> _characteristicValueChanged;
589         internal EventHandler<NotificationStateChangedEventArg> _notificationStateChanged;
590
591         /// <summary>
592         /// The constructor.
593         /// </summary>
594         /// <param name="uuid">The UUID of the characterstic.</param>
595         /// <param name="permissions">Permissions for the characterstic.</param>
596         /// <param name="properties">Properties set for the characterstic.</param>
597         /// <param name="value">The value associated with the characterstic.</param>
598         /// <remarks>throws in case of internal error.</remarks>
599         /// <exception cref="InvalidOperationException">Thrown when the create GATT characteristics procedure fails.</exception>
600         /// <since_tizen> 3 </since_tizen>
601         public BluetoothGattCharacteristic(string uuid, BluetoothGattPermission permissions, BluetoothGattProperty properties, byte[] value) : base(uuid, permissions)
602         {
603             _impl = new BluetoothGattCharacteristicImpl(uuid, permissions, properties, value);
604         }
605
606         internal BluetoothGattCharacteristic(BluetoothGattCharacteristicImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
607         {
608             _impl = impl;
609         }
610
611         /// <summary>
612         /// The CharacteristicValueChanged event is raised when the server notifies for change in this characteristic value.
613         /// </summary>
614         /// <remarks>
615         /// Adding the event handle on characteristic on the server side will not have any effect.
616         /// </remarks>
617         /// <since_tizen> 3 </since_tizen>
618         public event EventHandler<ValueChangedEventArgs> ValueChanged
619         {
620             add
621             {
622                 if (Client != null)
623                 {
624                     if (_characteristicValueChanged == null)
625                     {
626                         _characteristicValueChangedCallback = (gattHandle, characteristicValue, len, userData) =>
627                         {
628                             _characteristicValueChanged?.Invoke(this, new ValueChangedEventArgs(characteristicValue, len));
629                         };
630
631                         _impl.SetCharacteristicValueChangedEvent(_characteristicValueChangedCallback);
632                     }
633                     _characteristicValueChanged = value;
634                 }
635             }
636             remove
637             {
638                 if (Client != null)
639                 {
640                     _characteristicValueChanged = null;
641                     if (_characteristicValueChanged == null)
642                     {
643                         _impl.UnsetCharacteristicValueChangedEvent();
644                     }
645
646                 }
647             }
648         }
649
650         /// <summary>
651         /// The NotificationStateChanged event is called when the client enables or disables the Notification/Indication for particular characteristics.
652         /// </summary>
653         /// <remarks>
654         /// Adding event handle on the characteristic on the client side will not have any effect.
655         /// </remarks>
656         /// <since_tizen> 3 </since_tizen>
657         public event EventHandler<NotificationStateChangedEventArg> NotificationStateChanged
658         {
659             add
660             {
661                 if (Server != null)
662                 {
663                     if (_notificationStateChangedCallback == null)
664                     {
665                         _notificationStateChangedCallback = (notify, serverHandle, characteristicHandle, userData) =>
666                         {
667                             _notificationStateChanged?.Invoke(this, new NotificationStateChangedEventArg(Server, notify));
668                         };
669
670                         _impl.SetNotificationStateChangedEvent(_notificationStateChangedCallback);
671                     }
672
673                     _notificationStateChanged = value;
674                 }
675             }
676             remove
677             {
678                 if (Server != null)
679                 {
680                     _notificationStateChanged = null;
681                     // CAPI does not allow unsetting ReadValueRequestedEventCallback.
682                 }
683             }
684         }
685
686         /// <summary>
687         /// The property for this characteristic.
688         /// </summary>
689         /// <since_tizen> 3 </since_tizen>
690         public BluetoothGattProperty Properties
691         {
692             get
693             {
694                 return _impl.GetProperties();
695             }
696             set
697             {
698                 if (Server != null)
699                 {
700                     _impl.SetProperties(value);
701                 }
702             }
703         }
704
705         /// <summary>
706         /// The write type to be used for write operations.
707         /// </summary>
708         /// <since_tizen> 3 </since_tizen>
709         public BluetoothGattWriteType WriteType
710         {
711             get
712             {
713                 return _impl.GetWriteType();
714             }
715             set
716             {
717                 _impl.SetWriteType(value);
718             }
719         }
720
721         internal override BluetoothGattClient Client
722         {
723             get
724             {
725                 return _parent?.GetGattClient();
726             }
727         }
728
729         internal override BluetoothGattServer Server
730         {
731             get
732             {
733                 return _parent?.GetGattServer();
734             }
735         }
736
737         internal override BluetoothGattAttributeImpl Impl
738         {
739             get
740             {
741                 return _impl;
742             }
743         }
744
745         /// <summary>
746         /// Adds a descriptor to this characteristic.
747         /// </summary>
748         /// <param name="descriptor">The descriptor to be added.</param>
749         /// <returns>true on success, false otherwise.</returns>
750         /// <exception cref="InvalidOperationException">Thrown when the add GATT descriptor procedure fails.</exception>
751         /// <since_tizen> 3 </since_tizen>
752         public void AddDescriptor(BluetoothGattDescriptor descriptor)
753         {
754             if (Client != null)
755             {
756                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
757             }
758
759             if (descriptor.GetCharacteristic() != null)
760             {
761                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
762             }
763
764             _impl.AddDescriptor(descriptor);
765             descriptor.SetParent(this);
766         }
767
768         /// <summary>
769         /// Gets the descriptor with the given UUID that belongs to this characteristic.
770         /// </summary>
771         /// <param name="uuid">The UUID for the descriptor to get.</param>
772         /// <returns>The descriptor with a given UUID if it exists, null otherwise.</returns>
773         /// <since_tizen> 3 </since_tizen>
774         public BluetoothGattDescriptor GetDescriptor(string uuid)
775         {
776             return _impl.GetDescriptor(this, uuid);
777         }
778
779         /// <summary>
780         /// Gets the list of descriptors that belongs to this characteristic.
781         /// </summary>
782         /// <returns>The list of descriptors that belongs to this characteristic.</returns>
783         /// <since_tizen> 3 </since_tizen>
784         public IEnumerable<BluetoothGattDescriptor> GetDescriptors()
785         {
786             return _impl.GetDescriptors(this);
787         }
788
789         /// <summary>
790         /// Gets the service instance, which the specified characterstic belongs to.
791         /// </summary>
792         /// <returns>The characteristic instance, the specified characterstic belongs to.</returns>
793         /// <since_tizen> 3 </since_tizen>
794         public BluetoothGattService GetService()
795         {
796             return _parent;
797         }
798
799         internal void SetParent(BluetoothGattService parent)
800         {
801             if (_parent == null)
802             {
803                 _parent = parent;
804                 ReleaseHandleOwnership();
805             }
806          }
807     }
808
809     /// <summary>
810     /// The Bluetooth GATT descriptor.
811     /// </summary>
812     /// <since_tizen> 3 </since_tizen>
813     public class BluetoothGattDescriptor : BluetoothGattAttribute
814     {
815         private BluetoothGattCharacteristic _parent = null;
816         private BluetoothGattDescriptorImpl _impl;
817
818         /// <summary>
819         /// The constructor.
820         /// </summary>
821         /// <param name="uuid">The UUID of the descriptor.</param>
822         /// <param name="permisions">Permissions for the descriptor.</param>
823         /// <param name="value">The value associated with the descriptor.</param>
824         /// <remarks>throws in case of internal error.</remarks>
825         /// <exception cref="InvalidOperationException">Thrown when the create GATT descriptor procedure fails.</exception>
826         /// <since_tizen> 3 </since_tizen>
827         public BluetoothGattDescriptor(string uuid, BluetoothGattPermission permisions, byte[] value) : base (uuid, permisions)
828         {
829             _impl = new BluetoothGattDescriptorImpl(uuid, permisions, value);
830         }
831
832         internal BluetoothGattDescriptor(BluetoothGattDescriptorImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
833         {
834             _impl = impl;
835         }
836
837         internal override BluetoothGattClient Client
838         {
839             get
840             {
841                 return _parent?.Client;
842             }
843         }
844
845         internal override BluetoothGattServer Server
846         {
847             get
848             {
849                 return _parent?.Server;
850             }
851         }
852
853         internal override BluetoothGattAttributeImpl Impl
854         {
855             get
856             {
857                 return _impl;
858             }
859         }
860
861         /// <summary>
862         /// Gets the characteristic instance, which the specified descriptor belongs to.
863         /// </summary>
864         /// <returns>The characteristic instance, the specified descriptor belongs to.</returns>
865         /// <since_tizen> 3 </since_tizen>
866         public BluetoothGattCharacteristic GetCharacteristic()
867         {
868             return _parent;
869         }
870
871         internal void SetParent(BluetoothGattCharacteristic parent)
872         {
873             if (_parent == null)
874             {
875                 _parent = parent;
876                 ReleaseHandleOwnership();
877             }
878         }
879     }
880
881     /// <summary>
882     /// The Bluetooth GATT attribute.
883     /// </summary>
884     /// <since_tizen> 3 </since_tizen>
885     public abstract class BluetoothGattAttribute
886     {
887         private Interop.Bluetooth.BtGattServerReadValueRequestedCallback _readValueRequestedCallback;
888         private Interop.Bluetooth.BtGattServerWriteValueRequestedCallback _writeValueRequestedCallback;
889
890         private EventHandler<ReadRequestedEventArgs> _readValueRequested;
891         private EventHandler<WriteRequestedEventArgs> _writeValueRequested;
892
893         /// <summary>
894         /// The constructor.
895         /// </summary>
896         /// <param name="uuid">The UUID of the GATT attribute.</param>
897         /// <param name="permission">Permission for the GATT attribute.</param>
898         /// <since_tizen> 3 </since_tizen>
899         public BluetoothGattAttribute(string uuid, BluetoothGattPermission permission)
900         {
901             Uuid = uuid;
902             Permissions = permission;
903         }
904
905         // Events
906
907         /// <summary>
908         /// This event is called when the client request to read the value of a characteristic or a descriptor.
909         /// </summary>
910         /// <exception cref="InvalidOperationException">Thrown when the set read value requested callback procedure fails.</exception>
911         /// <since_tizen> 3 </since_tizen>
912         public event EventHandler<ReadRequestedEventArgs> ReadRequested
913         {
914             add
915             {
916                 if (Server == null) return;
917                 if (_readValueRequestedCallback == null)
918                 {
919                     _readValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, offset, userData) =>
920                     {
921                         _readValueRequested?.Invoke(this, new ReadRequestedEventArgs(Server, clientAddress, requestId, offset));
922                     };
923                     Impl.SetReadValueRequestedEventCallback(_readValueRequestedCallback);
924                 }
925                 _readValueRequested = value;
926             }
927             remove
928             {
929                 if (Server == null) return;
930                 _readValueRequested = null;
931                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
932             }
933         }
934
935         /// <summary>
936         /// This event is called when a value of a characteristic or a descriptor has been changed by a client.
937         /// </summary>
938         /// <exception cref="InvalidOperationException">Thrown when the set write value requested callback procedure fails.</exception>
939         /// <since_tizen> 3 </since_tizen>
940         public event EventHandler<WriteRequestedEventArgs> WriteRequested
941         {
942             add
943             {
944                 if (Server == null) return;
945                 if (_writeValueRequested == null)
946                 {
947                     _writeValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, response_needed, offset, valueToWrite, len, userData) =>
948                     {
949                         _writeValueRequested?.Invoke(this, new WriteRequestedEventArgs(Server, clientAddress, requestId, valueToWrite, offset, response_needed));
950                     };
951                     Impl.SetWriteValueRequestedEventCallback(_writeValueRequestedCallback);
952                 }
953                 _writeValueRequested = value;
954             }
955             remove
956             {
957                 if (Server == null) return;
958                 _writeValueRequested = null;
959                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
960             }
961         }
962
963         /// <summary>
964         /// The attribute's UUID.
965         /// </summary>
966         /// <since_tizen> 3 </since_tizen>
967         public string Uuid { get; }
968
969         /// <summary>
970         /// Permissions for this attribute.
971         /// </summary>
972         /// <since_tizen> 3 </since_tizen>
973         public BluetoothGattPermission Permissions { get; }
974
975         /// <summary>
976         /// The value of this descriptor.
977         /// </summary>
978         /// <since_tizen> 3 </since_tizen>
979         public byte[] Value
980         {
981             get
982             {
983                 return Impl.GetValue();
984             }
985             set
986             {
987                 Impl.SetValue(value);
988             }
989         }
990
991         internal abstract BluetoothGattClient Client { get; }
992         internal abstract BluetoothGattServer Server { get; }
993         internal abstract BluetoothGattAttributeImpl Impl { get; }
994
995         /// <summary>
996         /// Returns a string value at the specified offset.
997         /// </summary>
998         /// <param name="offset">An offset in the attribute value buffer.</param>
999         /// <returns>The string value at specified offset.</returns>
1000         /// <since_tizen> 3 </since_tizen>
1001         public string GetValue(int offset)
1002         {
1003             return Impl.GetValue(offset);
1004         }
1005
1006         /// <summary>
1007         /// Sets the string value as a specified offset.
1008         /// </summary>
1009         /// <param name="value">value to set</param>
1010         /// <exception cref="InvalidOperationException">Throws exception if the value is null.</exception>
1011         /// <since_tizen> 3 </since_tizen>
1012         public void SetValue(string value)
1013         {
1014             if (string.IsNullOrEmpty(value))
1015                 GattUtil.ThrowForError((int)BluetoothError.InvalidParameter, "value should not be null");
1016
1017             byte[] val = Encoding.UTF8.GetBytes(value);
1018             Impl.SetValue(val);
1019         }
1020
1021         /// <summary>
1022         /// Returns a value at specified offset as the int value of the specified type.
1023         /// </summary>
1024         /// <param name="type">The type of the int value.</param>
1025         /// <param name="offset">An offset in the attribute value buffer.</param>
1026         /// <returns>The int value at given offset.</returns>
1027         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1028         /// <since_tizen> 3 </since_tizen>
1029         public int GetValue(IntDataType type, int offset)
1030         {
1031             return Impl.GetValue(type, offset);
1032         }
1033
1034         /// <summary>
1035         /// Updates a value at the specified offset by the int value of the specified type.
1036         /// </summary>
1037         /// <param name="type">The type of the int value.</param>
1038         /// <param name="value">The value to set.</param>
1039         /// <param name="offset">An offset in the attribute value buffer.</param>
1040         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1041         /// <since_tizen> 3 </since_tizen>
1042         public void SetValue(IntDataType type, int value, int offset)
1043         {
1044             Impl.SetValue(type, value, offset);
1045         }
1046
1047         /// <summary>
1048         /// Returns a value at the specified offset as the float value of the specified type.
1049         /// </summary>
1050         /// <param name="type">The type of the float value.</param>
1051         /// <param name="offset">An offset in the attribute value buffer.</param>
1052         /// <returns>The float value at given offset.</returns>
1053         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1054         /// <since_tizen> 3 </since_tizen>
1055         public float GetValue(FloatDataType type, int offset)
1056         {
1057             return Impl.GetValue(type, offset);
1058         }
1059
1060         /// <summary>
1061         /// Updates the value at the specified offset by the float value of the specified type.
1062         /// </summary>
1063         /// <param name="type">The type of the float value.</param>
1064         /// <param name="mantissa">The mantissa of the float value.</param>
1065         /// <param name="exponent">An exponent of the float value.</param>
1066         /// <param name="offset">An offset in the attribute value buffer.</param>
1067         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1068         /// <since_tizen> 3 </since_tizen>
1069         public void SetValue(FloatDataType type, int mantissa, int exponent, int offset)
1070         {
1071             Impl.SetValue(type, mantissa, exponent, offset);
1072         }
1073
1074         internal void ReleaseHandleOwnership()
1075         {
1076             Impl.ReleaseHandleOwnership();
1077         }
1078
1079         internal BluetoothGattAttributeHandle GetHandle()
1080         {
1081             return Impl.GetHandle();
1082         }
1083     }
1084 }