Merge "[FMRadio] update logs" into tizen_3.0
[platform/core/api/webapi-plugins.git] / src / bluetooth / bluetooth_le_adapter.cc
1 /*
2  * Copyright (c) 2015 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 #include "bluetooth/bluetooth_le_adapter.h"
18
19 #include "common/tools.h"
20 #include "common/logger.h"
21
22 #include "bluetooth/bluetooth_instance.h"
23 #include "bluetooth/bluetooth_le_device.h"
24 #include "bluetooth/bluetooth_util.h"
25
26 namespace extension {
27 namespace bluetooth {
28
29 namespace {
30
31 class ParsedDataHolder {
32  public:
33   ParsedDataHolder() : valid_(false) {}
34   virtual ~ParsedDataHolder() {}
35
36   bool valid() const {
37     return valid_;
38   }
39
40  protected:
41   void set_valid() {
42     valid_ = true;
43   }
44
45  private:
46   bool valid_;
47 };
48
49 class BluetoothLEServiceData : public ParsedDataHolder {
50  public:
51   BluetoothLEServiceData()
52       : ParsedDataHolder() {
53   }
54
55   const std::string& uuid() const {
56     return uuid_;
57   }
58
59   const std::string& data() const {
60     return data_;
61   }
62
63   static bool Construct(const picojson::value& obj,
64                         BluetoothLEServiceData* out) {
65     if (!obj.is<picojson::object>() ||
66         !ParseUUID(obj, out) ||
67         !ParseData(obj, out)) {
68       return false;
69     }
70
71     out->set_valid();
72
73     return true;
74   }
75
76  private:
77   static bool ParseUUID(const picojson::value& obj,
78                         BluetoothLEServiceData* out) {
79     LoggerD("Entered");
80     const auto& uuid = obj.get("serviceuuid");
81     if (uuid.is<std::string>()) {
82       out->uuid_ = uuid.get<std::string>();
83     } else {
84       return false;
85     }
86
87     return true;
88   }
89
90   static bool ParseData(const picojson::value& obj,
91                         BluetoothLEServiceData* out) {
92     LoggerD("Entered");
93     const auto& data = obj.get("data");
94     if (data.is<std::string>()) {
95       out->data_ = data.get<std::string>();
96     } else {
97       return false;
98     }
99
100     return true;
101   }
102
103   std::string uuid_;
104   std::string data_;
105 };
106
107 class BluetoothLEManufacturerData : public ParsedDataHolder {
108  public:
109   BluetoothLEManufacturerData()
110       : ParsedDataHolder(),
111         data_(nullptr),
112         data_length_(0) {
113   }
114
115   const std::string& id() const {
116     return id_;
117   }
118
119   const unsigned char* const data() const {
120     return data_;
121   }
122
123   const int data_length() const {
124     return data_length_;
125   }
126
127   static bool Construct(const picojson::value& obj,
128                         BluetoothLEManufacturerData* out) {
129     LoggerD("Entered");
130     if (!obj.is<picojson::object>() ||
131         !ParseId(obj, out) ||
132         !ParseData(obj, out)) {
133       return false;
134     }
135
136     out->set_valid();
137
138     return true;
139   }
140
141   ~BluetoothLEManufacturerData() {
142     if (data_) {
143       delete [] data_;
144       data_ = nullptr;
145       data_length_ = 0;
146     }
147   }
148
149  private:
150   static bool ParseId(const picojson::value& obj,
151                       BluetoothLEManufacturerData* out) {
152     LoggerD("Entered");
153     const auto& id = obj.get("id");
154     if (id.is<std::string>()) {
155       out->id_ = id.get<std::string>();
156     } else {
157       return false;
158     }
159
160     return true;
161   }
162
163   static bool ParseData(const picojson::value& obj,
164                         BluetoothLEManufacturerData* out) {
165     LoggerD("Entered");
166
167     const auto& val_data = obj.get("data");
168
169     if (val_data.is<std::string>()) {
170       const std::string& str_data = val_data.get<std::string>();
171       const char* p_data = str_data.c_str();
172       int size = str_data.length();
173       if (size > 2 && (str_data.find("0x", 0) == 0 || str_data.find("0X", 0) == 0)) {
174         p_data += 2;
175         size -= 2;
176       }
177       out->data_length_ = size / 2;
178       out->data_ = new unsigned char[out->data_length_];
179       common::tools::HexToBin(p_data, size, out->data_, out->data_length_);
180       return true;
181     } else {
182       return false;
183     }
184   }
185
186   std::string id_;
187   unsigned char* data_;
188   int data_length_;
189 };
190
191 class BluetoothLEAdvertiseData : public ParsedDataHolder {
192  public:
193   BluetoothLEAdvertiseData()
194       : ParsedDataHolder(),
195         include_name_(false),
196         appearance_(0),  // 0 means unknown
197         include_tx_power_level_(false) {
198   }
199
200   bool include_name() const {
201     return include_name_;
202   }
203
204   const std::vector<std::string>& service_uuids() const {
205     return service_uuids_;
206   }
207
208   const std::vector<std::string>& solicitation_uuids() const {
209     return solicitation_uuids_;
210   }
211
212   int appearance() const {
213     return appearance_;
214   }
215
216   bool include_tx_power_level() const {
217     return include_tx_power_level_;
218   }
219
220   const BluetoothLEServiceData& service_data() const {
221     return service_data_;
222   }
223
224   const BluetoothLEManufacturerData& manufacturer_data() const {
225     return manufacturer_data_;
226   }
227
228   static bool Construct(const picojson::value& obj,
229                         BluetoothLEAdvertiseData* out) {
230     LoggerD("Entered");
231     if (!obj.is<picojson::object>() ||
232         !ParseIncludeName(obj, out) ||
233         !ParseServiceUUIDs(obj, out) ||
234         !ParseSolicitationUUIDs(obj, out) ||
235         !ParseAppearance(obj, out) ||
236         !ParseIncludeTxPowerLevel(obj, out) ||
237         !ParseServiceData(obj, out) ||
238         !ParseManufacturerData(obj, out)) {
239       return false;
240     }
241
242     out->set_valid();
243
244     return true;
245   }
246
247  private:
248   static bool ParseIncludeName(const picojson::value& obj,
249                                BluetoothLEAdvertiseData* out) {
250     LoggerD("Entered");
251     const auto& include_name = obj.get("includeName");
252     if (include_name.is<bool>()) {
253       out->include_name_ = include_name.get<bool>();
254     } else if (!include_name.is<picojson::null>()) {
255       return false;
256     }
257
258     return true;
259   }
260
261   static bool ParseServiceUUIDs(const picojson::value& obj,
262                                 BluetoothLEAdvertiseData* out) {
263     LoggerD("Entered");
264     const auto& service_uuids = obj.get("serviceuuids");
265     if (service_uuids.is<picojson::array>()) {
266       for (const auto& i : service_uuids.get<picojson::array>()) {
267         if (i.is<std::string>()) {
268           out->service_uuids_.push_back(i.get<std::string>());
269         } else {
270           return false;
271         }
272       }
273     } else if (!service_uuids.is<picojson::null>()) {
274       return false;
275     }
276
277     return true;
278   }
279
280   static bool ParseSolicitationUUIDs(const picojson::value& obj,
281                                      BluetoothLEAdvertiseData* out) {
282     LoggerD("Entered");
283     const auto& solicitation_uuids = obj.get("solicitationuuids");
284     if (solicitation_uuids.is<picojson::array>()) {
285       for (const auto& i : solicitation_uuids.get<picojson::array>()) {
286         if (i.is<std::string>()) {
287           out->solicitation_uuids_.push_back(i.get<std::string>());
288         } else {
289           return false;
290         }
291       }
292     } else if (!solicitation_uuids.is<picojson::null>()) {
293       return false;
294     }
295
296     return true;
297   }
298
299   static bool ParseAppearance(const picojson::value& obj,
300                               BluetoothLEAdvertiseData* out) {
301     LoggerD("Entered");
302     const auto& appearance = obj.get("appearance");
303     if (appearance.is<double>()) {
304       out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
305     } else if (!appearance.is<picojson::null>()) {
306       return false;
307     }
308
309     return true;
310   }
311
312   static bool ParseIncludeTxPowerLevel(const picojson::value& obj,
313                                        BluetoothLEAdvertiseData* out) {
314     LoggerD("Entered");
315     const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
316     if (include_tx_power_level.is<bool>()) {
317       out->include_tx_power_level_ = include_tx_power_level.get<bool>();
318     } else if (!include_tx_power_level.is<picojson::null>()) {
319       return false;
320     }
321
322     return true;
323   }
324
325   static bool ParseServiceData(const picojson::value& obj,
326                                BluetoothLEAdvertiseData* out) {
327     LoggerD("Entered");
328     const auto& service_data = obj.get("serviceData");
329     BluetoothLEServiceData data;
330     if (BluetoothLEServiceData::Construct(service_data, &data)) {
331       out->service_data_ = std::move(data);
332     } else if (!service_data.is<picojson::null>()) {
333       return false;
334     }
335
336     return true;
337   }
338
339   static bool ParseManufacturerData(const picojson::value& obj,
340                                     BluetoothLEAdvertiseData* out) {
341     LoggerD("Entered");
342     const auto& manufacturer_data = obj.get("manufacturerData");
343     BluetoothLEManufacturerData data;
344     if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
345       out->manufacturer_data_ = std::move(data);
346     } else if (!manufacturer_data.is<picojson::null>()) {
347       return false;
348     }
349
350     return true;
351   }
352
353   bool include_name_;
354   std::vector<std::string> service_uuids_;
355   std::vector<std::string> solicitation_uuids_;
356   int appearance_;
357   bool include_tx_power_level_;
358   BluetoothLEServiceData service_data_;
359   BluetoothLEManufacturerData manufacturer_data_;
360 };
361
362 // utility functions
363
364 bool ToBool(bt_adapter_le_state_e state) {
365   return (BT_ADAPTER_LE_ENABLED == state) ? true : false;
366 }
367
368 // constants
369
370 const std::string kAction = "action";
371 const std::string kData = "data";
372 // scan-related
373 const std::string kOnScanSuccess = "onsuccess";
374 const std::string kOnScanError = "onerror";
375 const std::string kScanEvent = "BluetoothLEScanCallback";
376 // advertise-related
377 const std::string kOnAdvertiseState = "onstate";
378 const std::string kOnAdvertiseError = "onerror";
379 const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
380
381 } // namespace
382
383 using common::ErrorCode;
384 using common::PlatformResult;
385 using common::tools::ReportError;
386 using common::tools::ReportSuccess;
387
388 BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
389     : instance_(instance),
390       enabled_(false),
391       scanning_(false),
392       bt_advertiser_(nullptr) {
393   LoggerD("Entered");
394
395   bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
396
397   int ret = bt_adapter_le_get_state(&le_state);
398
399   if (BT_ERROR_NONE == ret) {
400     enabled_ = ToBool(le_state);
401
402     ret = bt_adapter_le_set_state_changed_cb(OnStateChanged, this);
403     if (BT_ERROR_NONE != ret) {
404       LoggerE("Failed to register BTLE state changed listener.");
405     }
406   } else {
407     LoggerE("Failed to obtain current state of BTLE.");
408   }
409 }
410
411 BluetoothLEAdapter::~BluetoothLEAdapter() {
412   LoggerD("Entered");
413   bt_adapter_le_unset_state_changed_cb();
414   if (scanning_) {
415     bt_adapter_le_stop_scan();
416   }
417   if (bt_advertiser_) {
418     bt_adapter_le_stop_advertising(bt_advertiser_);
419     bt_adapter_le_destroy_advertiser(bt_advertiser_);
420   }
421 }
422
423 void BluetoothLEAdapter::StartScan(const picojson::value& data, picojson::object& out) {
424   LoggerD("Entered");
425
426   int ret = bt_adapter_le_start_scan(OnScanResult, this);
427
428   if (BT_ERROR_NONE != ret) {
429     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
430       LogAndReportError(
431           PlatformResult(ErrorCode::INVALID_STATE_ERR, "Scan already in progress"), &out,
432           ("Scan in progress %d (%s)", ret, get_error_message(ret)));
433     } else {
434
435       // other errors are reported asynchronously
436       picojson::value value = picojson::value(picojson::object());
437       picojson::object* data_obj = &value.get<picojson::object>();
438       data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
439       LogAndReportError(
440           PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to start scan"), data_obj,
441           ("Failed to start scan: %d (%s)", ret, get_error_message(ret)));
442       instance_.FireEvent(kScanEvent, value);
443     }
444   } else {
445     scanning_ = true;
446     ReportSuccess(out);
447   }
448 }
449
450 void BluetoothLEAdapter::StopScan(const picojson::value& data, picojson::object& out) {
451   LoggerD("Entered");
452
453   int ret = bt_adapter_le_stop_scan();
454
455   if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
456     LogAndReportError(
457         PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop scan"), &out,
458         ("Failed to stop scan: %d (%s)", ret, get_error_message(ret)));
459   } else {
460     scanning_ = false;
461     ReportSuccess(out);
462   }
463 }
464
465 void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
466   LoggerD("Entered");
467
468   const auto& json_advertise_data = data.get("advertiseData");
469   const auto& json_packet_type = data.get("packetType");
470   const auto& json_mode = data.get("mode");
471   const auto& json_connectable = data.get("connectable");
472
473   if (!json_advertise_data.is<picojson::object>() ||
474       !json_packet_type.is<std::string>() ||
475       !json_mode.is<std::string>() ||
476       !json_connectable.is<bool>()) {
477     LogAndReportError(
478         PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"), &out);
479     return;
480   }
481
482   BluetoothLEAdvertiseData advertise_data;
483   if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
484     LogAndReportError(
485         PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
486     return;
487   }
488
489   bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
490   {
491     const auto& str_packet_type = json_packet_type.get<std::string>();
492     if ("ADVERTISE" == str_packet_type) {
493       packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
494     } else if ("SCAN_RESPONSE" == str_packet_type) {
495       packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
496     } else {
497       LogAndReportError(
498           PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out,
499           ("Wrong packet_type: %s", str_packet_type.c_str()));
500       return;
501     }
502   }
503
504   bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
505   {
506     const auto& str_mode = json_mode.get<std::string>();
507     if ("BALANCED" == str_mode) {
508       mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
509     } else if ("LOW_LATENCY" == str_mode) {
510       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
511     } else if ("LOW_ENERGY" == str_mode) {
512       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
513     } else {
514       LogAndReportError(
515           PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"), &out,
516           ("Wrong mode: %s", str_mode.c_str()));
517       return;
518     }
519   }
520
521   if (nullptr != bt_advertiser_) {
522     LogAndReportError(
523         PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out);
524     return;
525   }
526
527   bt_advertiser_h advertiser = nullptr;
528
529   int ret = bt_adapter_le_create_advertiser(&advertiser);
530   if (BT_ERROR_NONE != ret) {
531     LogAndReportError(
532         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
533         ("bt_adapter_le_create_advertiser() failed with: %d, (%s)", ret, get_error_message(ret)));
534     return;
535   }
536
537   std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type,
538       int (*)(bt_advertiser_h)> advertiser_ptr(advertiser, &bt_adapter_le_destroy_advertiser);  // automatically release the memory
539
540   // configure advertiser
541   if (advertise_data.include_name()) {
542     ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
543                                                 advertise_data.include_name());
544     if (BT_ERROR_NONE != ret) {
545       LogAndReportError(
546           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
547           ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret, get_error_message(ret)));
548       return;
549     }
550   }
551
552   for (const auto& i : advertise_data.service_uuids()) {
553     ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
554                                                      i.c_str());
555     if (BT_ERROR_NONE != ret) {
556       LogAndReportError(
557           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
558           ("bt_adapter_le_add_advertising_service_uuid() failed with: %d (%s)", ret, get_error_message(ret)));
559       return;
560     }
561   }
562
563   for (const auto& i : advertise_data.solicitation_uuids()) {
564     ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser,
565                                                                   packet_type,
566                                                                   i.c_str());
567     if (BT_ERROR_NONE != ret) {
568       LogAndReportError(
569           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
570           ("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d (%s)",
571             ret, get_error_message(ret)));
572       return;
573     }
574   }
575
576   ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
577                                                  advertise_data.appearance());
578   if (BT_ERROR_NONE != ret) {
579     LogAndReportError(
580         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
581         ("bt_adapter_le_set_advertising_appearance() failed with: %d (%s)",
582           ret, get_error_message(ret)));
583     return;
584   }
585
586   if (advertise_data.include_tx_power_level()) {
587     ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
588                                                        advertise_data.include_tx_power_level());
589     if (BT_ERROR_NONE != ret) {
590       LogAndReportError(
591           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
592           ("bt_adapter_le_set_advertising_tx_power_level() failed with: %d (%s)",
593             ret, get_error_message(ret)));
594       return;
595     }
596   }
597
598   const auto& service_data = advertise_data.service_data();
599   if (service_data.uuid().empty() && service_data.data().empty()) {
600     LoggerD("service data is empty");
601   } else {
602     ret = bt_adapter_le_add_advertising_service_data(advertiser, packet_type,
603                                                      service_data.uuid().c_str(),
604                                                      service_data.data().c_str(),
605                                                      service_data.data().length());
606     if (BT_ERROR_NONE != ret) {
607       LogAndReportError(
608           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
609           ("bt_adapter_le_add_advertising_service_data() failed with: %d (%s)",
610             ret, get_error_message(ret)));
611       return;
612     }
613   }
614
615   const auto& manufacturer_data = advertise_data.manufacturer_data();
616   if (manufacturer_data.id().empty() && manufacturer_data.data() == nullptr) {
617     LoggerD("manufacturerData is empty");
618   } else {
619     if (manufacturer_data.valid()) {
620       ret = bt_adapter_le_add_advertising_manufacturer_data(advertiser,
621                                                             packet_type,
622                                                             atoi(manufacturer_data.id().c_str()),
623                                                             (const char*)manufacturer_data.data(),
624                                                             manufacturer_data.data_length());
625       if (BT_ERROR_NONE != ret) {
626         LogAndReportError(
627             util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
628             ("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d (%s)",
629               ret, get_error_message(ret)));
630         return;
631       }
632     }
633   }
634
635   ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
636   if (BT_ERROR_NONE != ret) {
637     LogAndReportError(
638         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
639         ("bt_adapter_le_set_advertising_mode() failed with: %d (%s)",
640           ret, get_error_message(ret)));
641     return;
642   }
643
644   ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
645   if (BT_ERROR_NONE != ret) {
646     LogAndReportError(
647         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
648         ("bt_adapter_le_set_advertising_connectable() failed with: %d (%s)",
649           ret, get_error_message(ret)));
650     return;
651   }
652
653   // advertiser is ready, let's start advertising
654   ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
655   if (BT_ERROR_NONE != ret) {
656     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
657       LogAndReportError(
658           PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out,
659           ("bt_adapter_le_start_advertising_new error: %d (%s)", ret, get_error_message(ret)));
660       return;
661     }
662
663     LogAndReportError(
664         util::GetBluetoothError(ret, "Failed to start advertising"), &out,
665         ("bt_adapter_le_start_advertising_new() failed with: %d (%s)",
666           ret, get_error_message(ret)));
667     return;
668   }
669
670   // everything went well, we want to store the pointer, so unique_ptr should no longer manage the memory
671   bt_advertiser_ = advertiser_ptr.release();
672   ReportSuccess(out);
673 }
674
675 void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
676   LoggerD("Entered");
677
678   if (nullptr != bt_advertiser_) {
679     int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
680     if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
681       LogAndReportError(
682           PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out,
683           ("bt_adapter_le_stop_advertising() failed with: %d (%s)",
684             ret, get_error_message(ret)));
685       return;
686     }
687
688     ret = bt_adapter_le_destroy_advertiser(bt_advertiser_);
689     if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
690       LogAndReportError(
691           PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"), &out,
692           ("bt_adapter_le_destroy_advertiser() failed with: %d (%s)",
693             ret, get_error_message(ret)));
694       return;
695     }
696
697     bt_advertiser_ = nullptr;
698   } else {
699     LoggerD("Advertising is not in progress");
700   }
701
702   ReportSuccess(out);
703 }
704
705 void BluetoothLEAdapter::OnStateChanged(int result,
706                                         bt_adapter_le_state_e adapter_le_state,
707                                         void* user_data) {
708   LoggerD("Entered");
709
710   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
711
712   if (!adapter) {
713     LoggerE("user_data is NULL");
714     return;
715   }
716
717   adapter->enabled_ = ToBool(adapter_le_state);
718 }
719
720 void BluetoothLEAdapter::OnScanResult(
721     int result, bt_adapter_le_device_scan_result_info_s* info,
722     void* user_data) {
723   LoggerD("Entered, result: %d, info: %p, data: %p", result, info, user_data);
724
725   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
726
727   if (!adapter) {
728     LoggerE("user_data is NULL");
729     return;
730   }
731
732   picojson::value value = picojson::value(picojson::object());
733   picojson::object* data_obj = &value.get<picojson::object>();
734
735   if (BT_ERROR_NONE != result) {
736     LogAndReportError(
737         util::GetBluetoothError(result, "Error during scanning"), data_obj,
738         ("Error during scanning: %d (%s)", result, get_error_message(result)));
739     data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
740   } else {
741     // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
742     if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
743       // device found
744       LoggerD("Device found");
745       picojson::value data{picojson::object{}};
746       const auto& r = BluetoothLEDevice::ToJson(info, &data.get<picojson::object>());
747       if (r) {
748         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanSuccess)));
749         data_obj->insert(std::make_pair(kData, data));
750       } else {
751         LogAndReportError(r, data_obj, ("Failed to parse Bluetooth LE device"));
752         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
753       }
754     }
755   }
756
757   adapter->instance_.FireEvent(kScanEvent, value);
758 }
759
760 void BluetoothLEAdapter::OnAdvertiseResult(
761     int result, bt_advertiser_h advertiser,
762     bt_adapter_le_advertising_state_e adv_state, void* user_data) {
763   LoggerD("Entered, result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser, adv_state, user_data);
764
765   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
766
767   if (!adapter) {
768     LoggerE("user_data is NULL");
769     return;
770   }
771
772   picojson::value value = picojson::value(picojson::object());
773   picojson::object* data_obj = &value.get<picojson::object>();
774
775   if (BT_ERROR_NONE != result) {
776     LogAndReportError(
777         util::GetBluetoothError(result, "Error during advertising"), data_obj,
778         ("Error during advertising: %d (%s)", result, get_error_message(result)));
779     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
780   } else {
781     const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
782     LoggerD("Advertise state is: %s", state);
783     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
784     ReportSuccess(picojson::value(state), *data_obj);
785   }
786
787   adapter->instance_.FireEvent(kAdvertiseEvent, value);
788 }
789
790 } // namespace bluetooth
791 } // namespace extension