1+ #include < condition_variable>
2+ #include < deque>
3+ #include < functional>
4+ #include < future>
5+ #include < memory>
16#include < string.h>
27#include < string>
8+ #include < thread>
9+ #include < type_traits>
10+ #include < utility>
11+
12+ #ifdef _WIN32
13+ #include < objbase.h>
14+ #ifdef _MSC_VER
15+ #pragma comment(lib, "ole32.lib")
16+ #endif
17+ #endif
318
419#include " ble_lib_board.h"
520
621#include " bluetooth_types.h"
722#include " get_dll_dir.h"
823
24+ namespace
25+ {
26+ #ifdef _WIN32
27+ class BLEThreadDispatcher
28+ {
29+ public:
30+ BLEThreadDispatcher ()
31+ : stop (false ), started (false ), worker (&BLEThreadDispatcher::worker_loop, this )
32+ {
33+ std::unique_lock<std::mutex> lock (mutex);
34+ cv.wait (lock, [this ] { return started; });
35+ }
36+
37+ ~BLEThreadDispatcher ()
38+ {
39+ {
40+ std::lock_guard<std::mutex> lock (mutex);
41+ stop = true ;
42+ }
43+ cv.notify_one ();
44+ if (worker.joinable ())
45+ {
46+ worker.join ();
47+ }
48+ }
49+
50+ template <typename Func>
51+ typename std::enable_if<!std::is_void<typename std::result_of<Func ()>::type>::value,
52+ typename std::result_of<Func ()>::type>::type
53+ run (Func func)
54+ {
55+ typedef typename std::result_of<Func ()>::type result_type;
56+ if (is_worker_thread ())
57+ {
58+ return func ();
59+ }
60+
61+ std::shared_ptr<std::packaged_task<result_type ()>> task (
62+ new std::packaged_task<result_type ()> (std::move (func)));
63+ std::future<result_type> future = task->get_future ();
64+ {
65+ std::lock_guard<std::mutex> lock (mutex);
66+ queue.push_back ([task] () { (*task) (); });
67+ }
68+ cv.notify_one ();
69+ return future.get ();
70+ }
71+
72+ template <typename Func>
73+ typename std::enable_if<std::is_void<typename std::result_of<Func ()>::type>::value,
74+ void >::type
75+ run (Func func)
76+ {
77+ if (is_worker_thread ())
78+ {
79+ func ();
80+ return ;
81+ }
82+
83+ std::shared_ptr<std::packaged_task<void ()>> task (
84+ new std::packaged_task<void ()> (std::move (func)));
85+ std::future<void > future = task->get_future ();
86+ {
87+ std::lock_guard<std::mutex> lock (mutex);
88+ queue.push_back ([task] () { (*task) (); });
89+ }
90+ cv.notify_one ();
91+ future.get ();
92+ }
93+
94+ private:
95+ void worker_loop ()
96+ {
97+ HRESULT coinit_result = CoInitializeEx (NULL , COINIT_MULTITHREADED);
98+ bool co_initialized = SUCCEEDED (coinit_result);
99+
100+ {
101+ std::lock_guard<std::mutex> lock (mutex);
102+ worker_id = std::this_thread::get_id ();
103+ started = true ;
104+ }
105+ cv.notify_one ();
106+
107+ for (;;)
108+ {
109+ std::function<void ()> task;
110+ {
111+ std::unique_lock<std::mutex> lock (mutex);
112+ cv.wait (lock, [this ] { return stop || !queue.empty (); });
113+ if (stop && queue.empty ())
114+ {
115+ break ;
116+ }
117+ task = queue.front ();
118+ queue.pop_front ();
119+ }
120+ task ();
121+ }
122+
123+ if (co_initialized)
124+ {
125+ CoUninitialize ();
126+ }
127+ }
128+
129+ bool is_worker_thread ()
130+ {
131+ std::lock_guard<std::mutex> lock (mutex);
132+ return std::this_thread::get_id () == worker_id;
133+ }
134+
135+ std::mutex mutex;
136+ std::condition_variable cv;
137+ std::deque<std::function<void ()>> queue;
138+ bool stop;
139+ bool started;
140+ std::thread worker;
141+ std::thread::id worker_id;
142+ };
143+
144+ BLEThreadDispatcher &get_ble_thread_dispatcher ()
145+ {
146+ static BLEThreadDispatcher dispatcher;
147+ return dispatcher;
148+ }
149+
150+ template <typename Func>
151+ typename std::result_of<Func ()>::type run_on_simpleble_thread (Func func)
152+ {
153+ return get_ble_thread_dispatcher ().run (std::move (func));
154+ }
155+ #else
156+ template <typename Func>
157+ typename std::result_of<Func ()>::type run_on_simpleble_thread (Func func)
158+ {
159+ return func ();
160+ }
161+ #endif
162+ } // namespace
163+
9164#ifndef STATIC_SIMPLEBLE
10165DLLLoader *BLELibBoard::dll_loader = NULL ;
11166std::mutex BLELibBoard::mutex;
@@ -449,9 +604,10 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_connect (simpleble_peripheral_
449604 return SIMPLEBLE_FAILURE;
450605 }
451606
452- return func ( handle);
607+ return run_on_simpleble_thread ([ func, handle] () { return func ( handle); } );
453608#else
454- return ::simpleble_peripheral_connect (handle);
609+ return run_on_simpleble_thread (
610+ [handle] () { return ::simpleble_peripheral_connect (handle); });
455611#endif
456612}
457613
@@ -474,9 +630,10 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_disconnect (simpleble_peripher
474630 return SIMPLEBLE_FAILURE;
475631 }
476632
477- return func ( handle);
633+ return run_on_simpleble_thread ([ func, handle] () { return func ( handle); } );
478634#else
479- return ::simpleble_peripheral_disconnect (handle);
635+ return run_on_simpleble_thread (
636+ [handle] () { return ::simpleble_peripheral_disconnect (handle); });
480637#endif
481638}
482639
@@ -499,9 +656,10 @@ void BLELibBoard::simpleble_peripheral_release_handle (simpleble_peripheral_t ha
499656 return ;
500657 }
501658
502- func ( handle);
659+ run_on_simpleble_thread ([ func, handle] () { func ( handle); } );
503660#else
504- return ::simpleble_peripheral_release_handle (handle);
661+ return run_on_simpleble_thread (
662+ [handle] () { return ::simpleble_peripheral_release_handle (handle); });
505663#endif
506664}
507665
@@ -524,9 +682,10 @@ size_t BLELibBoard::simpleble_peripheral_services_count (simpleble_peripheral_t
524682 return 0 ;
525683 }
526684
527- return func ( handle);
685+ return run_on_simpleble_thread ([ func, handle] () { return func ( handle); } );
528686#else
529- return ::simpleble_peripheral_services_count (handle);
687+ return run_on_simpleble_thread (
688+ [handle] () { return ::simpleble_peripheral_services_count (handle); });
530689#endif
531690}
532691
@@ -550,9 +709,11 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_services_get (
550709 return SIMPLEBLE_FAILURE;
551710 }
552711
553- return func (handle, index, services);
712+ return run_on_simpleble_thread (
713+ [func, handle, index, services] () { return func (handle, index, services); });
554714#else
555- return ::simpleble_peripheral_services_get (handle, index, services);
715+ return run_on_simpleble_thread ([handle, index, services] ()
716+ { return ::simpleble_peripheral_services_get (handle, index, services); });
556717#endif
557718}
558719
@@ -578,10 +739,15 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_write_request (simpleble_perip
578739 return SIMPLEBLE_FAILURE;
579740 }
580741
581- return func (handle, service, characteristic, data, data_length);
742+ return run_on_simpleble_thread ([func, handle, service, characteristic, data, data_length] ()
743+ { return func (handle, service, characteristic, data, data_length); });
582744#else
583- return ::simpleble_peripheral_write_request (
584- handle, service, characteristic, data, data_length);
745+ return run_on_simpleble_thread (
746+ [handle, service, characteristic, data, data_length] ()
747+ {
748+ return ::simpleble_peripheral_write_request (
749+ handle, service, characteristic, data, data_length);
750+ });
585751#endif
586752}
587753
@@ -606,10 +772,15 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_write_command (simpleble_perip
606772 return SIMPLEBLE_FAILURE;
607773 }
608774
609- return func (handle, service, characteristic, data, data_length);
775+ return run_on_simpleble_thread ([func, handle, service, characteristic, data, data_length] ()
776+ { return func (handle, service, characteristic, data, data_length); });
610777#else
611- return ::simpleble_peripheral_write_command (
612- handle, service, characteristic, data, data_length);
778+ return run_on_simpleble_thread (
779+ [handle, service, characteristic, data, data_length] ()
780+ {
781+ return ::simpleble_peripheral_write_command (
782+ handle, service, characteristic, data, data_length);
783+ });
613784#endif
614785}
615786
@@ -640,9 +811,14 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_notify (simpleble_peripheral_t
640811 return SIMPLEBLE_FAILURE;
641812 }
642813
643- return func (handle, service, characteristic, callback, userdata);
814+ return run_on_simpleble_thread ([func, handle, service, characteristic, callback, userdata] ()
815+ { return func (handle, service, characteristic, callback, userdata); });
644816#else
645- return ::simpleble_peripheral_notify (handle, service, characteristic, callback, userdata);
817+ return run_on_simpleble_thread (
818+ [handle, service, characteristic, callback, userdata] () {
819+ return ::simpleble_peripheral_notify (
820+ handle, service, characteristic, callback, userdata);
821+ });
646822#endif
647823}
648824
@@ -666,9 +842,11 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_unsubscribe (
666842 return SIMPLEBLE_FAILURE;
667843 }
668844
669- return func (handle, service, characteristic);
845+ return run_on_simpleble_thread ([func, handle, service, characteristic] ()
846+ { return func (handle, service, characteristic); });
670847#else
671- return ::simpleble_peripheral_unsubscribe (handle, service, characteristic);
848+ return run_on_simpleble_thread ([handle, service, characteristic] ()
849+ { return ::simpleble_peripheral_unsubscribe (handle, service, characteristic); });
672850#endif
673851}
674852
@@ -744,9 +922,13 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_read (simpleble_peripheral_t h
744922 return SIMPLEBLE_FAILURE;
745923 }
746924
747- return func (handle, service, characteristic, data, data_length);
925+ return run_on_simpleble_thread ([func, handle, service, characteristic, data, data_length] ()
926+ { return func (handle, service, characteristic, data, data_length); });
748927#else
749- return ::simpleble_peripheral_read (handle, service, characteristic, data, data_length);
928+ return run_on_simpleble_thread (
929+ [handle, service, characteristic, data, data_length] () {
930+ return ::simpleble_peripheral_read (handle, service, characteristic, data, data_length);
931+ });
750932#endif
751933}
752934
@@ -770,8 +952,10 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_is_connected (
770952 return SIMPLEBLE_FAILURE;
771953 }
772954
773- return func (handle, connected);
955+ return run_on_simpleble_thread (
956+ [func, handle, connected] () { return func (handle, connected); });
774957#else
775- return ::simpleble_peripheral_is_connected (handle, connected);
958+ return run_on_simpleble_thread (
959+ [handle, connected] () { return ::simpleble_peripheral_is_connected (handle, connected); });
776960#endif
777961}
0 commit comments