ruble 0.0.3.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gdbinit +21 -0
- data/.gitignore +18 -0
- data/.rubocop.yml +96 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +6 -0
- data/CMakeLists.txt +4 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +98 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +41 -0
- data/ext/ruble/.gitignore +5 -0
- data/ext/ruble/CMakeLists.txt +157 -0
- data/ext/ruble/RuBLEHelpers.cmake +240 -0
- data/ext/ruble/bindings/Adapter.cpp +193 -0
- data/ext/ruble/bindings/Adapter.hpp +85 -0
- data/ext/ruble/bindings/Characteristic.cpp +171 -0
- data/ext/ruble/bindings/Characteristic.hpp +132 -0
- data/ext/ruble/bindings/Descriptor.cpp +34 -0
- data/ext/ruble/bindings/Descriptor.hpp +69 -0
- data/ext/ruble/bindings/Peripheral.cpp +212 -0
- data/ext/ruble/bindings/Peripheral.hpp +108 -0
- data/ext/ruble/bindings/RuBLE.cpp +115 -0
- data/ext/ruble/bindings/Service.cpp +112 -0
- data/ext/ruble/bindings/Service.hpp +61 -0
- data/ext/ruble/bindings/common.hpp +48 -0
- data/ext/ruble/bindings/globals.cpp +43 -0
- data/ext/ruble/cmake.mk +62 -0
- data/ext/ruble/concerns/CharacteristicValueTracker.cpp +18 -0
- data/ext/ruble/concerns/CharacteristicValueTracker.hpp +40 -0
- data/ext/ruble/concerns/Rubyable.cpp +4 -0
- data/ext/ruble/concerns/Rubyable.hpp +46 -0
- data/ext/ruble/config.h.in +25 -0
- data/ext/ruble/containers/ByteArray.cpp +64 -0
- data/ext/ruble/containers/ByteArray.hpp +161 -0
- data/ext/ruble/containers/Callback.hpp +52 -0
- data/ext/ruble/containers/NamedBitSet.hpp +140 -0
- data/ext/ruble/containers/NamedBitSet.ipp +71 -0
- data/ext/ruble/extconf.rb +30 -0
- data/ext/ruble/management/Registry.cpp +63 -0
- data/ext/ruble/management/Registry.hpp +170 -0
- data/ext/ruble/management/RegistryFactory.hpp +113 -0
- data/ext/ruble/management/RubyQueue.cpp +152 -0
- data/ext/ruble/management/RubyQueue.hpp +69 -0
- data/ext/ruble/modularize.diff +28 -0
- data/ext/ruble/types/SimpleBLE.hpp +21 -0
- data/ext/ruble/types/declarations.hpp +91 -0
- data/ext/ruble/types/helpers.hpp +12 -0
- data/ext/ruble/types/ruby.hpp +36 -0
- data/ext/ruble/types/stl.hpp +41 -0
- data/ext/ruble/utils/RubyCallbackTraits.cpp +28 -0
- data/ext/ruble/utils/RubyCallbackTraits.hpp +48 -0
- data/ext/ruble/utils/async.cpp +10 -0
- data/ext/ruble/utils/async.hpp +76 -0
- data/ext/ruble/utils/containers.hpp +41 -0
- data/ext/ruble/utils/exception_handling.cpp +50 -0
- data/ext/ruble/utils/exception_handling.hpp +53 -0
- data/ext/ruble/utils/garbage_collection.cpp +82 -0
- data/ext/ruble/utils/garbage_collection.hpp +22 -0
- data/ext/ruble/utils/hash.cpp +83 -0
- data/ext/ruble/utils/hash.hpp +52 -0
- data/ext/ruble/utils/hexadecimal.hpp +116 -0
- data/ext/ruble/utils/human_type_names.hpp +38 -0
- data/ext/ruble/utils/inspection.cpp +24 -0
- data/ext/ruble/utils/inspection.hpp +108 -0
- data/ext/ruble/utils/ruby.hpp +103 -0
- data/ext/ruble/utils/ruby_context.hpp +73 -0
- data/lib/ruble/build/.rubocop.yml +19 -0
- data/lib/ruble/build/boost.rb +34 -0
- data/lib/ruble/build/cmake.rb +134 -0
- data/lib/ruble/build/core_ext.rb +5 -0
- data/lib/ruble/build/data/bundler.rb +24 -0
- data/lib/ruble/build/data/extension.rb +101 -0
- data/lib/ruble/build/data/os.rb +21 -0
- data/lib/ruble/build/data/rice.rb +24 -0
- data/lib/ruble/build/data.rb +22 -0
- data/lib/ruble/build/extconf.rb +76 -0
- data/lib/ruble/build/github_repo.rb +129 -0
- data/lib/ruble/build/simpleble.rb +56 -0
- data/lib/ruble/build.rb +28 -0
- data/lib/ruble/version.rb +7 -0
- data/lib/ruble.rb +46 -0
- data/lib/tasks/dev/dev_tasks.rb +130 -0
- data/lib/tasks/dev/pager.rb +218 -0
- data/lib/tasks/dev/paths.rb +30 -0
- data/lib/tasks/dev/state_hash.rb +65 -0
- data/lib/tasks/dev.rake +41 -0
- data/lib/tasks/simpleble.rake +29 -0
- data/sig/rubble.rbs +4 -0
- metadata +263 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
# From https://stackoverflow.com/a/51987470
|
2
|
+
# Get all properties that cmake supports
|
3
|
+
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
|
4
|
+
|
5
|
+
# Convert command output into a CMake list
|
6
|
+
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
|
7
|
+
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
|
8
|
+
# Fix https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i
|
9
|
+
list(FILTER CMAKE_PROPERTY_LIST EXCLUDE REGEX "^LOCATION$|^LOCATION_|_LOCATION$")
|
10
|
+
# For some reason, "TYPE" shows up twice - others might too?
|
11
|
+
list(REMOVE_DUPLICATES CMAKE_PROPERTY_LIST)
|
12
|
+
|
13
|
+
# build whitelist by filtering down from CMAKE_PROPERTY_LIST in case cmake is
|
14
|
+
# a different version, and one of our hardcoded whitelisted properties
|
15
|
+
# doesn't exist!
|
16
|
+
unset(CMAKE_WHITELISTED_PROPERTY_LIST)
|
17
|
+
foreach(prop ${CMAKE_PROPERTY_LIST})
|
18
|
+
if(prop MATCHES "^(INTERFACE|[_a-z]|IMPORTED_LIBNAME_|MAP_IMPORTED_CONFIG_)|^(COMPATIBLE_INTERFACE_(BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|EXPORT_NAME|IMPORTED(_GLOBAL|_CONFIGURATIONS|_LIBNAME)?|NAME|TYPE|NO_SYSTEM_FROM_IMPORTED)$")
|
19
|
+
list(APPEND CMAKE_WHITELISTED_PROPERTY_LIST ${prop})
|
20
|
+
endif()
|
21
|
+
endforeach(prop)
|
22
|
+
|
23
|
+
function(print_properties)
|
24
|
+
message ("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}")
|
25
|
+
endfunction(print_properties)
|
26
|
+
|
27
|
+
function(print_whitelisted_properties)
|
28
|
+
message ("CMAKE_WHITELISTED_PROPERTY_LIST = ${CMAKE_WHITELISTED_PROPERTY_LIST}")
|
29
|
+
endfunction(print_whitelisted_properties)
|
30
|
+
|
31
|
+
function(print_target_properties tgt)
|
32
|
+
if(NOT TARGET ${tgt})
|
33
|
+
message("There is no target named '${tgt}'")
|
34
|
+
return()
|
35
|
+
endif()
|
36
|
+
|
37
|
+
get_target_property(target_type ${tgt} TYPE)
|
38
|
+
if(target_type STREQUAL "INTERFACE_LIBRARY")
|
39
|
+
set(PROP_LIST ${CMAKE_WHITELISTED_PROPERTY_LIST})
|
40
|
+
else()
|
41
|
+
set(PROP_LIST ${CMAKE_PROPERTY_LIST})
|
42
|
+
endif()
|
43
|
+
|
44
|
+
foreach (prop ${PROP_LIST})
|
45
|
+
string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
|
46
|
+
# message ("Checking ${prop}")
|
47
|
+
get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
|
48
|
+
if (propval)
|
49
|
+
get_target_property(propval ${tgt} ${prop})
|
50
|
+
message ("${tgt} ${prop} = ${propval}")
|
51
|
+
endif()
|
52
|
+
endforeach(prop)
|
53
|
+
endfunction(print_target_properties)
|
54
|
+
|
55
|
+
function(dump_variables)
|
56
|
+
get_cmake_property(_variableNames VARIABLES)
|
57
|
+
list (SORT _variableNames)
|
58
|
+
foreach (_variableName ${_variableNames})
|
59
|
+
message(STATUS "${_variableName}=${${_variableName}}")
|
60
|
+
endforeach()
|
61
|
+
endfunction()
|
62
|
+
|
63
|
+
macro(build_boost)
|
64
|
+
set(REPO "https://github.com/boostorg/boost")
|
65
|
+
set(TAG boost-1.83.0)
|
66
|
+
cmake_path(SET CACHE_LOCATION NORMALIZE "${CMAKE_SOURCE_DIR}/../../tmp/${TAG}")
|
67
|
+
|
68
|
+
set(ADDITIONAL_DEPENDENCIES core;stacktrace)
|
69
|
+
set(HEADER_ONLY_LIBS headers;describe)
|
70
|
+
set(LINKED_LIBS exception;endian;algorithm) # + detected stacktrace backend
|
71
|
+
set(STACKTRACE_BACKEND_PRIORITIES backtrace;addr2line;windgb_cached;windbg;basic;noop)
|
72
|
+
|
73
|
+
set(ALL_LIBS ${HEADER_ONLY_LIBS};${LINKED_LIBS})
|
74
|
+
set(BUILD_DEPS ${ALL_LIBS})
|
75
|
+
set(BOOST_INCLUDE_LIBRARIES ${ADDITIONAL_DEPENDENCIES};${BUILD_DEPS})
|
76
|
+
|
77
|
+
list(TRANSFORM HEADER_ONLY_LIBS PREPEND "Boost::"
|
78
|
+
OUTPUT_VARIABLE HEADER_ONLY_NAMESPACES)
|
79
|
+
list(TRANSFORM LINKED_LIBS PREPEND "Boost::"
|
80
|
+
OUTPUT_VARIABLE LINKED_NAMESPACES)
|
81
|
+
list(TRANSFORM BUILD_DEPS PREPEND "boost_"
|
82
|
+
OUTPUT_VARIABLE PREFIXED_BUILD_DEPS)
|
83
|
+
# dump_variables()
|
84
|
+
# message(FATAL_ERROR "quitting")
|
85
|
+
|
86
|
+
set(STACKTRACE_BACKEND_PRIORITIES backtrace;addr2line;windgb_cached;windbg;basic;noop)
|
87
|
+
list(TRANSFORM STACKTRACE_BACKEND_PRIORITIES
|
88
|
+
PREPEND "stacktrace_"
|
89
|
+
OUTPUT_VARIABLE STACKTRACE_BACKENDS)
|
90
|
+
|
91
|
+
# set(USES_TERMINAL_DOWNLOAD ON)
|
92
|
+
# set(USES_TERMINAL_UPDATE ON)
|
93
|
+
# set(LOG_DOWNLOAD ON)
|
94
|
+
# set(LOG_UPDATE ON)
|
95
|
+
|
96
|
+
set(BOOST_ENABLE_PYTHON OFF)
|
97
|
+
set(BUILD_SHARED_LIBS OFF)
|
98
|
+
set(Boost_DEBUG OFF)
|
99
|
+
set(Boost_VERBOSE OFF)
|
100
|
+
set(BUILD_TESTING OFF)
|
101
|
+
|
102
|
+
# TODO: add option to use local boost (in which case we can link dynamically)
|
103
|
+
|
104
|
+
include(FetchContent)
|
105
|
+
# cmake_policy(SET CMP0097 NEW)
|
106
|
+
FetchContent_Declare(
|
107
|
+
Boost
|
108
|
+
SOURCE_DIR "${CACHE_LOCATION}"
|
109
|
+
URL "${rb_boost_asset_browser_download_url}"
|
110
|
+
# GIT_REPOSITORY "${REPO}" # TODO: would an archive make more sense(?)
|
111
|
+
# GIT_TAG "${TAG}" # TODO: set this in build-config.cmake
|
112
|
+
# GIT_PROGRESS ON
|
113
|
+
# GIT_SHALLOW ON
|
114
|
+
# GIT_SUBMODULES ""
|
115
|
+
# GIT_SUBMODULES_RECURSE OFF
|
116
|
+
# GIT_REMOTE_UPDATE_STRATEGY REBASE
|
117
|
+
# UPDATE_COMMAND git submodule update --init --recursive --remote -f --depth 1 -j ${NPROC}
|
118
|
+
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
119
|
+
USES_TERMINAL_DOWNLOAD ON
|
120
|
+
USES_TERMINAL_UPDATE ON
|
121
|
+
OVERRIDE_FIND_PACKAGE
|
122
|
+
)
|
123
|
+
FetchContent_MakeAvailable(Boost)
|
124
|
+
# dump_variables()
|
125
|
+
|
126
|
+
find_package(
|
127
|
+
Boost
|
128
|
+
REQUIRED
|
129
|
+
${BOOST_INCLDUE_LIBRARIES}
|
130
|
+
OPTIONAL_COMPONENTS
|
131
|
+
${STACKTRACE_BACKENDS}
|
132
|
+
PATHS "${CACHE_LOCATION}" "${CACHE_LOCATION}/tools/cmake"
|
133
|
+
EXCLUDE_FROM_ALL ON
|
134
|
+
NO_DEFAULT_PATH
|
135
|
+
)
|
136
|
+
endmacro()
|
137
|
+
|
138
|
+
# TODO: Should we fall back with this?
|
139
|
+
function(setup_boost build_target)
|
140
|
+
build_boost()
|
141
|
+
|
142
|
+
target_link_libraries(${build_target} INTERFACE ${HEADER_ONLY_NAMESPACES}) #Boost::headers Boost::exception Boost::describe Boost::endian)
|
143
|
+
target_link_libraries(${build_target} PRIVATE ${LINKED_NAMESPACES})
|
144
|
+
add_dependencies(${build_target} ${PREFIXED_BUILD_DEPS})
|
145
|
+
|
146
|
+
foreach(possible_backend IN LISTS STACKTRACE_BACKEND_PRIORITIES)
|
147
|
+
string(TOUPPER "${possible_backend}" possible_backend_upper)
|
148
|
+
|
149
|
+
message(STATUS "Testing for stacktrace backend ${possible_backend}")
|
150
|
+
message(STATUS "BOOST_STACKTRACE_ENABLE_${possible_backend_upper}: ${BOOST_STACKTRACE_ENABLE_${possible_backend_upper}}")
|
151
|
+
message(STATUS "BOOST_STACKTRACE_HAS_${possible_backend_upper}: ${BOOST_STACKTRACE_HAS_${possible_backend_upper}}")
|
152
|
+
if(NOT BOOST_STACKTRACE_ENABLE_${possible_backend_upper} OR NOT BOOST_STACKTRACE_HAS_${possible_backend_upper})
|
153
|
+
continue()
|
154
|
+
endif()
|
155
|
+
|
156
|
+
string(REGEX MATCH "^windbg_" STACKTRACE_BACKEND_IS_WINDBG "${possible_backend}")
|
157
|
+
set(STACKTRACE_BACKEND "${possible_backend}")
|
158
|
+
set(STACKTRACE_BACKEND "${possible_backend}" PARENT_SCOPE)
|
159
|
+
set(BOOST_STACKTRACE_LINK ON)
|
160
|
+
set(BOOST_STACKTRACE_LINK ON PARENT_SCOPE)
|
161
|
+
set(BOOST_STACKTRACE_USE_${possible_backend_upper} ON PARENT_SCOPE)
|
162
|
+
|
163
|
+
target_link_libraries(${build_target} PRIVATE Boost::stacktrace_${STACKTRACE_BACKEND})
|
164
|
+
add_dependencies(${build_target} boost_stacktrace_${STACKTRACE_BACKEND})
|
165
|
+
|
166
|
+
target_link_libraries(${build_target} PRIVATE Boost::stacktrace_${possible_backend})
|
167
|
+
if(possible_backend STREQUAL "backtrace")
|
168
|
+
include(FindBacktrace)
|
169
|
+
if(Backtrace_LIBRARY)
|
170
|
+
target_link_libraries(${build_target} PRIVATE ${Backtrace_LIBRARY})
|
171
|
+
endif()
|
172
|
+
|
173
|
+
if(Backtrace_HEADER)
|
174
|
+
set(BACKTRACE_HEADER_PATH "${Backtrace_INCLUDE_DIR}/${Backtrace_HEADER}")
|
175
|
+
set(BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE "${BACKTRACE_HEADER_PATH}" PARENT_SCOPE)
|
176
|
+
endif ()
|
177
|
+
# elseif(possible_backend STREQUAL "addr2line")
|
178
|
+
# # This really only makes sense to use if this is being built on the computer it's used on
|
179
|
+
# set(BOOST_STACKTRACE_ADDR2LINE_LOCATION "${CMAKE_ADDR2LINE}")
|
180
|
+
elseif(WINDOWS AND STACKTRACE_BACKEND_IS_WINDBG) # TODO: untested
|
181
|
+
find_library(OLE32 ole32)
|
182
|
+
find_library(WINDBGENG dbgeng)
|
183
|
+
target_link_libraries(${build_target} PUBLIC ole32 dbgeng)
|
184
|
+
endif()
|
185
|
+
break()
|
186
|
+
endforeach()
|
187
|
+
|
188
|
+
if(NOT BOOST_STACKTRACE_LINK)
|
189
|
+
# dump_variables()
|
190
|
+
message(FATAL_ERROR "Could not find supported Boost::stacktrace backend")
|
191
|
+
endif()
|
192
|
+
message(STATUS "Boost::stacktrace backend: ${STACKTRACE_BACKEND}")
|
193
|
+
|
194
|
+
set(UNUSED_STACKTRACE_BACKENDS ${STACKTRACE_BACKEND_PRIORITIES})
|
195
|
+
list(REMOVE_ITEM UNUSED_STACKTRACE_BACKENDS "${STACKTRACE_BACKEND}")
|
196
|
+
message(VERBOSE "Disabling unused Boost::stacktrace backends: ${UNUSED_STACKTRACE_BACKENDS}")
|
197
|
+
foreach(unused_backend IN LISTS UNUSED_STACKTRACE_BACKENDS)
|
198
|
+
string(TOUPPER "${unused_backend}" unused_backend_upper)
|
199
|
+
if(NOT BOOST_STACKTRACE_ENABLE_${unused_backend_upper})
|
200
|
+
continue()
|
201
|
+
endif()
|
202
|
+
|
203
|
+
set_target_properties(boost_stacktrace_${unused_backend} PROPERTIES EXCLUDE_FROM_ALL ON)
|
204
|
+
set(BOOST_STACKTRACE_ENABLE_${unused_backend_upper} OFF)
|
205
|
+
endforeach()
|
206
|
+
endfunction()
|
207
|
+
|
208
|
+
# TODO: try changing these into functions
|
209
|
+
function(setup_simpleble build_target)
|
210
|
+
include(FetchContent)
|
211
|
+
# TODO: would it be easier/better to use git and the commit hash
|
212
|
+
# and build SimpleBLE from source? The main downside is more
|
213
|
+
# dependencies. The upside is vastly simplifying configuring
|
214
|
+
# simpleble_DIR, as well as choosing between shared/static linking.
|
215
|
+
FetchContent_Declare(
|
216
|
+
simpleble
|
217
|
+
URL "${rb_simpleble_asset_browser_download_url}"
|
218
|
+
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
219
|
+
# OVERRIDE_FIND_PACKAGE
|
220
|
+
)
|
221
|
+
FetchContent_MakeAvailable(simpleble)
|
222
|
+
set(simpleble_DIR ${simpleble_SOURCE_DIR}/${rb_simpleble_archive_path})
|
223
|
+
find_package(simpleble REQUIRED CONFIG PATHS "${simpleble_DIR}" NO_DEFAULT_PATH)
|
224
|
+
target_link_libraries("${build_target}" PUBLIC simpleble::simpleble)
|
225
|
+
include("${simpleble_CONFIG}")
|
226
|
+
message(STATUS "SimpleBLE found in ${simpleble_DIR}")
|
227
|
+
endfunction()
|
228
|
+
|
229
|
+
|
230
|
+
macro(setup_ruby build_target)
|
231
|
+
#set(_Ruby_DEBUG_OUTPUT ON)
|
232
|
+
set(RUBY_FIND_VERSION 3.2)
|
233
|
+
find_package(Ruby 3.2 REQUIRED Ruby_FIND_VIRTUALENV)
|
234
|
+
target_link_libraries("${build_target}" PUBLIC ${Ruby_LIBRARIES})
|
235
|
+
target_include_directories("${build_target}" PUBLIC ${Ruby_INCLUDE_DIRS})
|
236
|
+
target_include_directories("${build_target}" PRIVATE ${RICE_INCLUDE_PATH})
|
237
|
+
set_target_properties("${build_target}" PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
|
238
|
+
message(STATUS "libruby ${Ruby_VERSION} found at ${Ruby_LIBRARY}")
|
239
|
+
message(STATUS "Rice ${RICE_VERSION} found in ${RICE_INCLUDE_PATH}")
|
240
|
+
endmacro()
|
@@ -0,0 +1,193 @@
|
|
1
|
+
#include <ranges>
|
2
|
+
|
3
|
+
#include "types/declarations.hpp"
|
4
|
+
#include "bindings/Adapter.hpp"
|
5
|
+
#include "bindings/Peripheral.hpp"
|
6
|
+
#include "management/Registry.hpp"
|
7
|
+
#include "management/RegistryFactory.hpp"
|
8
|
+
#include "management/RubyQueue.hpp"
|
9
|
+
#include "utils/containers.hpp"
|
10
|
+
|
11
|
+
namespace RuBLE {
|
12
|
+
using Rice::String;
|
13
|
+
Adapter::Adapter(const SimpleBLE::Adapter &adapter) :
|
14
|
+
_adapter(std::make_shared<SimpleBLE::Adapter>(adapter)),
|
15
|
+
_addr(_adapter->address()),
|
16
|
+
_peripheral_registry(peripheralRegistryFactory->registry(this)),
|
17
|
+
_on_scan_start(std::make_shared<Callback>(1)),
|
18
|
+
_on_scan_stop(std::make_shared<Callback>(1)),
|
19
|
+
_on_scan_update(std::make_shared<Callback>(2)),
|
20
|
+
_on_scan_find(std::make_shared<Callback>(2)),
|
21
|
+
_self(Adapter_DO(*this)) {
|
22
|
+
get().set_callback_on_scan_start([this]() {
|
23
|
+
RubyQueue::FnType fn = [this]() -> void { _on_scan_start->fire(self()); };
|
24
|
+
if (_on_scan_start) rubyQueue->push(fn);
|
25
|
+
});
|
26
|
+
|
27
|
+
get().set_callback_on_scan_stop([this]() {
|
28
|
+
RubyQueue::FnType fn = [this]() -> void { _on_scan_stop->fire(self()); };
|
29
|
+
if (_on_scan_stop) rubyQueue->push(fn);
|
30
|
+
});
|
31
|
+
|
32
|
+
get().set_callback_on_scan_updated([this](const SimpleBLE::Peripheral &peripheral) {
|
33
|
+
RubyQueue::FnType fn = [this, peripheral]() -> void {
|
34
|
+
const std::shared_ptr<Peripheral> &wrapped = _peripheral_registry->fetch(peripheral);
|
35
|
+
_on_scan_update->fire(wrapped->self(), self());
|
36
|
+
};
|
37
|
+
if (_on_scan_update) rubyQueue->push(fn);
|
38
|
+
});
|
39
|
+
|
40
|
+
get().set_callback_on_scan_found([this](const SimpleBLE::Peripheral &peripheral) {
|
41
|
+
RubyQueue::FnType fn = [this, peripheral]() -> void {
|
42
|
+
const std::shared_ptr<Peripheral> &wrapped = _peripheral_registry->fetch(peripheral);
|
43
|
+
_on_scan_find->fire(wrapped->self(), self());
|
44
|
+
};
|
45
|
+
if (_on_scan_find) rubyQueue->push(fn);
|
46
|
+
});
|
47
|
+
}
|
48
|
+
|
49
|
+
bool Adapter::initialized() const { return get().initialized(); }
|
50
|
+
|
51
|
+
std::string Adapter::identifier() { return (_adapter) ? get().identifier() : ""; }
|
52
|
+
|
53
|
+
|
54
|
+
BluetoothAddress Adapter::address() const {
|
55
|
+
return _addr; /*get().address();*/
|
56
|
+
}
|
57
|
+
|
58
|
+
void Adapter::scan_start() { if (!scan_is_active()) get().scan_start(); }
|
59
|
+
|
60
|
+
void Adapter::scan_stop() { if (scan_is_active()) get().scan_stop(); }
|
61
|
+
|
62
|
+
void Adapter::scan_for(int timeout_ms) { get().scan_for(timeout_ms); }
|
63
|
+
|
64
|
+
bool Adapter::scan_is_active() const {
|
65
|
+
return const_cast<Adapter*>(this)->get().scan_is_active();
|
66
|
+
}
|
67
|
+
|
68
|
+
bool Adapter::operator==(const SimpleBLE::BluetoothAddress &addr) const { return !_addr.empty() && _addr == addr; }
|
69
|
+
|
70
|
+
bool Adapter::operator==(const Adapter &ap) const { return *this == ap._addr; }
|
71
|
+
|
72
|
+
std::vector<std::shared_ptr<Peripheral>> Adapter::scan_get_results() {
|
73
|
+
auto unwrappedPeripherals = get().scan_get_results();
|
74
|
+
return _peripheral_registry->map_to_objects(unwrappedPeripherals);
|
75
|
+
}
|
76
|
+
|
77
|
+
Rice::Array Adapter::scan_get_ruby_results() {
|
78
|
+
auto unwrappedPeripherals = get().scan_get_results();
|
79
|
+
return _peripheral_registry->map_to_ruby_objects(unwrappedPeripherals);
|
80
|
+
}
|
81
|
+
|
82
|
+
std::vector<std::shared_ptr<Peripheral>> Adapter::get_paired_peripherals() {
|
83
|
+
auto unwrappedPeripherals = get().get_paired_peripherals();
|
84
|
+
return _peripheral_registry->map_to_objects(unwrappedPeripherals);
|
85
|
+
}
|
86
|
+
|
87
|
+
|
88
|
+
Rice::Array Adapter::get_ruby_paired_peripherals() {
|
89
|
+
auto unwrappedPeripherals = get().get_paired_peripherals();
|
90
|
+
return _peripheral_registry->map_to_ruby_objects(unwrappedPeripherals);
|
91
|
+
}
|
92
|
+
|
93
|
+
SimpleBLE::Adapter &Adapter::get() {
|
94
|
+
if (!_adapter) throw std::runtime_error("Tried fetching address for unconfigured Adapter instance");
|
95
|
+
return *_adapter;
|
96
|
+
}
|
97
|
+
|
98
|
+
const SimpleBLE::Adapter &Adapter::get() const {
|
99
|
+
if (!_adapter) throw std::runtime_error("Tried fetching address for unconfigured Adapter instance");
|
100
|
+
return *_adapter;
|
101
|
+
}
|
102
|
+
|
103
|
+
Object Adapter::self() const { return _self; }
|
104
|
+
|
105
|
+
bool Adapter::bluetooth_enabled() { return SimpleBLE::Adapter::bluetooth_enabled(); }
|
106
|
+
|
107
|
+
std::vector<std::shared_ptr<Adapter>> Adapter::get_adapters() {
|
108
|
+
std::vector<SimpleBLE::Adapter> unwrappedAdapters = SimpleBLE::Adapter::get_adapters();
|
109
|
+
return adapterRegistry->map_to_objects(unwrappedAdapters);
|
110
|
+
}
|
111
|
+
|
112
|
+
Rice::Array Adapter::get_ruby_adapters() {
|
113
|
+
std::vector<SimpleBLE::Adapter> unwrappedAdapters = SimpleBLE::Adapter::get_adapters();
|
114
|
+
return adapterRegistry->map_to_ruby_objects(unwrappedAdapters);
|
115
|
+
}
|
116
|
+
|
117
|
+
void Adapter::on_scan_start(Object new_cb) { _on_scan_start->set(new_cb); }
|
118
|
+
|
119
|
+
void Adapter::on_scan_stop(Object new_cb) { _on_scan_stop->set(new_cb); }
|
120
|
+
|
121
|
+
void Adapter::on_scan_update(Object new_cb) { _on_scan_update->set(new_cb); }
|
122
|
+
|
123
|
+
void Adapter::on_scan_find(Object new_cb) { _on_scan_find->set(new_cb); }
|
124
|
+
|
125
|
+
std::unordered_set<std::string> Adapter::status_flags() const {
|
126
|
+
using PossibleFlagMap = std::unordered_map<std::string, std::function<bool(const Adapter&)>>;
|
127
|
+
static const PossibleFlagMap possible_flag_fns {
|
128
|
+
{ "initialized"s, &Adapter::initialized },
|
129
|
+
{ "scanning"s, &Adapter::scan_is_active },
|
130
|
+
};
|
131
|
+
static auto flag_check = [this](const PossibleFlagMap::value_type &pair) -> bool {
|
132
|
+
return pair.second(*this);
|
133
|
+
};
|
134
|
+
|
135
|
+
ranges::viewable_range auto flags = possible_flag_fns | views::filter(flag_check) | views::keys;
|
136
|
+
return { flags.begin(), flags.end() };
|
137
|
+
}
|
138
|
+
|
139
|
+
std::string Adapter::to_s() const {
|
140
|
+
std::ostringstream oss;
|
141
|
+
String superStr(rb_call_super(0, nullptr));
|
142
|
+
if (superStr.test() && superStr.length() > 0) {
|
143
|
+
std::string super(superStr.str());
|
144
|
+
super.pop_back();
|
145
|
+
oss << super;
|
146
|
+
} else {
|
147
|
+
oss << "#<" << Utils::human_type_name<decltype(*this)>();
|
148
|
+
oss << ":" << Utils::to_hex_addr(this);
|
149
|
+
}
|
150
|
+
oss << " ";
|
151
|
+
if (!initialized()) return oss.str() + "uninitialized>";
|
152
|
+
oss << "@address=\"" << address() << "\" ";
|
153
|
+
oss << Utils::join(status_flags(), "|");
|
154
|
+
oss << ">";
|
155
|
+
return oss.str();
|
156
|
+
}
|
157
|
+
|
158
|
+
void Adapter::ruby_mark() const {
|
159
|
+
// std::cout << "ruby_mark-ing adapter proxy: " << address() << std::endl;
|
160
|
+
// rb_gc_mark(self());
|
161
|
+
Rice::ruby_mark<RuBLE::PeripheralRegistry>(_peripheral_registry.get());
|
162
|
+
// rb_gc_mark(_peripheral_registry->self());
|
163
|
+
if (_on_scan_start) Rice::ruby_mark<RuBLE::Callback>(_on_scan_start.get());
|
164
|
+
if (_on_scan_stop) Rice::ruby_mark<RuBLE::Callback>(_on_scan_stop.get());
|
165
|
+
if (_on_scan_update) Rice::ruby_mark<RuBLE::Callback>(_on_scan_update.get());
|
166
|
+
if (_on_scan_find) Rice::ruby_mark<RuBLE::Callback>(_on_scan_find.get());
|
167
|
+
}
|
168
|
+
|
169
|
+
void Init_Adapter() {
|
170
|
+
define_class_under<SimpleBLE::Adapter>(rb_mRuBLEUnderlying, "SimpleBLEAdapter");
|
171
|
+
rb_cAdapter = define_class_under<Adapter>(rb_mRuBLE, "Adapter")
|
172
|
+
.define_singleton_function("bluetooth_enabled?", &Adapter::bluetooth_enabled) // returns bool
|
173
|
+
.define_singleton_function("get_adapters", &Adapter::get_ruby_adapters) // returns vector<Adapter>
|
174
|
+
.define_method("initialized?", &Adapter::initialized)
|
175
|
+
.define_method("identifier", &Adapter::identifier)
|
176
|
+
.define_method("address", &Adapter::address) // returns BluetoothAddress (alias of std::string)
|
177
|
+
.define_method("scan_start", &Adapter::scan_start)
|
178
|
+
.define_method("scan_stop", &Adapter::scan_stop)
|
179
|
+
.define_method("scan_for", &Adapter::scan_for) // takes (int timeout_ms)
|
180
|
+
.define_method("scanning?", &Adapter::scan_is_active)
|
181
|
+
.define_method("scan_get_results", &Adapter::scan_get_ruby_results) // returns vector<Peripheral>
|
182
|
+
.define_method("get_paired_peripherals",
|
183
|
+
&Adapter::get_ruby_paired_peripherals) // returns vector<Peripheral>
|
184
|
+
.define_method("on_scan_start", &Adapter::on_scan_start, Arg("cb").keepAlive() = Qnil)
|
185
|
+
.define_method("on_scan_stop", &Adapter::on_scan_stop, Arg("cb").keepAlive() = Qnil)
|
186
|
+
.define_method("on_scan_update", &Adapter::on_scan_update, Arg("cb").keepAlive() = Qnil)
|
187
|
+
.define_method("on_scan_find", &Adapter::on_scan_find, Arg("cb").keepAlive() = Qnil)
|
188
|
+
;
|
189
|
+
// define_class_under<std::shared_ptr<RuBLE::Adapter>>(rb_mRuBLE, "AdapterPtr");
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#pragma clang diagnostic push
|
2
|
+
#pragma ide diagnostic ignored "modernize-use-nodiscard"
|
3
|
+
#pragma once
|
4
|
+
|
5
|
+
#include "types/declarations.hpp"
|
6
|
+
#include "containers/Callback.hpp"
|
7
|
+
#include "management/Registry.hpp"
|
8
|
+
|
9
|
+
#include <unordered_set>
|
10
|
+
#include "utils/hash.hpp"
|
11
|
+
|
12
|
+
namespace RuBLE {
|
13
|
+
namespace Rice = ::Rice;
|
14
|
+
|
15
|
+
// template<Identifiers::OwnerTypedResource T>
|
16
|
+
// class ResourceUniqueIdentifier;
|
17
|
+
|
18
|
+
class Adapter {
|
19
|
+
public:
|
20
|
+
using Owner = nullptr_t;
|
21
|
+
using DataObject [[maybe_unused]] = Data_Object<Adapter>;
|
22
|
+
|
23
|
+
protected:
|
24
|
+
VALUE _self;
|
25
|
+
std::shared_ptr<SimpleBLE::Adapter> _adapter;
|
26
|
+
BluetoothAddress _addr;
|
27
|
+
std::shared_ptr<Callback> _on_scan_start;
|
28
|
+
std::shared_ptr<Callback> _on_scan_stop;
|
29
|
+
std::shared_ptr<Callback> _on_scan_update;
|
30
|
+
std::shared_ptr<Callback> _on_scan_find;
|
31
|
+
std::shared_ptr<PeripheralRegistry> _peripheral_registry;
|
32
|
+
|
33
|
+
public:
|
34
|
+
Adapter() = delete;
|
35
|
+
Adapter(const SimpleBLE::Adapter &adapter);
|
36
|
+
~Adapter() = default;
|
37
|
+
|
38
|
+
Object self() const;
|
39
|
+
|
40
|
+
SimpleBLE::Adapter &get();
|
41
|
+
const SimpleBLE::Adapter &get() const;
|
42
|
+
|
43
|
+
static bool bluetooth_enabled();
|
44
|
+
static std::vector<std::shared_ptr<Adapter>> get_adapters();
|
45
|
+
static Rice::Array get_ruby_adapters();
|
46
|
+
virtual bool initialized() const;
|
47
|
+
std::string identifier();
|
48
|
+
SimpleBLE::BluetoothAddress address() const;
|
49
|
+
|
50
|
+
void scan_start();
|
51
|
+
void scan_stop();
|
52
|
+
void scan_for(int timeout_ms);
|
53
|
+
bool scan_is_active() const;
|
54
|
+
|
55
|
+
void on_scan_start(Object on_scan_start);
|
56
|
+
void on_scan_stop(Object on_scan_stop);
|
57
|
+
void on_scan_update(Object on_scan_updated);
|
58
|
+
void on_scan_find(Object on_scan_found);
|
59
|
+
|
60
|
+
std::vector<std::shared_ptr<Peripheral>> scan_get_results();
|
61
|
+
std::vector<std::shared_ptr<Peripheral>> get_paired_peripherals();
|
62
|
+
Rice::Array scan_get_ruby_results();
|
63
|
+
Rice::Array get_ruby_paired_peripherals();
|
64
|
+
bool operator==(const SimpleBLE::BluetoothAddress &addr) const;
|
65
|
+
bool operator==(const Adapter &ap) const;
|
66
|
+
|
67
|
+
std::unordered_set<std::string> status_flags() const;
|
68
|
+
std::string to_s() const;
|
69
|
+
|
70
|
+
// constexpr ResourceUniqueIdentifier<Adapter> full_resource_identifier() const;
|
71
|
+
// constexpr BluetoothAddress this_resource_identifier() const;
|
72
|
+
|
73
|
+
void ruby_mark() const;
|
74
|
+
|
75
|
+
template<typename Key, class ProxyClass, class Value>
|
76
|
+
friend class Registry;
|
77
|
+
|
78
|
+
friend void Init_Adapter();
|
79
|
+
friend void Init_Registries();
|
80
|
+
friend void DeInit(VALUE);
|
81
|
+
};
|
82
|
+
|
83
|
+
}
|
84
|
+
|
85
|
+
#pragma clang diagnostic pop
|