Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
HCIComm.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef HCI_COMM_HPP_
27#define HCI_COMM_HPP_
28
29#include <cstring>
30#include <string>
31#include <cstdint>
32#include <memory>
33#include <mutex>
34
35#include <jau/basic_types.hpp>
36#include <jau/functional.hpp>
37
38#include "HCIIoctl.hpp"
39
40extern "C" {
41 #include <pthread.h>
42}
43
44/**
45 * - - - - - - - - - - - - - - -
46 *
47 * Module HCIComm:
48 *
49 * - BT Core Spec v5.2: Vol 4, Part E Host Controller Interface (HCI)
50 */
51namespace direct_bt {
52
53 /** \addtogroup DBTSystemAPI
54 *
55 * @{
56 */
57
58 /**
59 * Read/Write HCI communication channel.
60 */
61 class HCIComm {
62 public:
63 /** Utilized to query for external interruption, whether device is still connected etc. */
64 typedef jau::function<bool(int /* dummy*/)> get_boolean_callback_t;
65
66 const uint16_t dev_id;
67 const uint16_t channel;
68
69 private:
70 static int hci_open_dev(const uint16_t dev_id, const uint16_t channel) noexcept;
71 static int hci_close_dev(int dd) noexcept;
72
73 std::recursive_mutex mtx_write;
74 jau::relaxed_atomic_int socket_descriptor; // the hci socket
75 jau::sc_atomic_bool interrupted_intern; // for forced disconnect and read interruption via close()
76 get_boolean_callback_t is_interrupted_extern; // for forced disconnect and read interruption via external event
77 std::atomic<::pthread_t> tid_read;
78
79 public:
80 /** Constructing a newly opened HCI communication channel instance */
81 HCIComm(const uint16_t dev_id, const uint16_t channel) noexcept;
82
83 HCIComm(const HCIComm&) = delete;
84 void operator=(const HCIComm&) = delete;
85
86 /**
87 * Releases this instance after issuing {@link #close()}.
88 */
89 ~HCIComm() noexcept { close(); }
90
91 bool is_open() const noexcept { return 0 <= socket_descriptor; }
92
93 /** The external `is interrupted` callback is used until close(), thereafter it is removed. */
94 void set_interrupted_query(get_boolean_callback_t is_interrupted_cb) { is_interrupted_extern = std::move(is_interrupted_cb); }
95
96 /** Returns true if interrupted by internal or external cause, hence shall stop connecting and reading. */
97 bool interrupted() const noexcept { return interrupted_intern || ( !is_interrupted_extern.is_null() && is_interrupted_extern(0/*dummy*/) ); }
98
99 /** Closing the HCI channel, locking {@link #mutex_write()}. */
100 void close() noexcept;
101
102 /** Return this HCI socket descriptor. */
103 inline int socket() const noexcept { return socket_descriptor; }
104
105 /** Return the recursive write mutex for multithreading access. */
106 inline std::recursive_mutex & mutex_write() noexcept { return mtx_write; }
107
108 /** Generic read w/ own timeout, w/o locking suitable for a unique ringbuffer sink. */
109 jau::snsize_t read(uint8_t* buffer, const jau::nsize_t capacity, const jau::fraction_i64& timeout) noexcept;
110
111 /** Generic write, locking {@link #mutex_write()}. */
112 jau::snsize_t write(const uint8_t* buffer, const jau::nsize_t size) noexcept;
113
114 private:
115 static inline void setu32_bit(int nr, void *addr) noexcept
116 {
117 *((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31));
118 }
119
120 static inline void clearu32_bit(int nr, void *addr) noexcept
121 {
122 *((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
123 }
124
125 static inline uint32_t testu32_bit(int nr, void *addr) noexcept
126 {
127 return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31));
128 }
129
130 public:
131 static inline void filter_clear(hci_ufilter *f) noexcept
132 {
133 bzero(f, sizeof(*f));
134 }
135 static inline void filter_set_ptype(int t, hci_ufilter *f) noexcept
136 {
137 setu32_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
138 }
139 static inline void filter_clear_ptype(int t, hci_ufilter *f) noexcept
140 {
141 clearu32_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
142 }
143 static inline uint32_t filter_test_ptype(int t, hci_ufilter *f) noexcept
144 {
145 return testu32_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
146 }
147 static inline void filter_all_ptypes(hci_ufilter *f) noexcept
148 {
149 memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask));
150 }
151 static inline void filter_set_event(int e, hci_ufilter *f) noexcept
152 {
153 setu32_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
154 }
155 static inline void filter_clear_event(int e, hci_ufilter *f) noexcept
156 {
157 clearu32_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
158 }
159 static inline uint32_t filter_test_event(int e, hci_ufilter *f) noexcept
160 {
161 return testu32_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
162 }
163 static inline void filter_all_events(hci_ufilter *f) noexcept
164 {
165 memset((void *) f->event_mask, 0xff, sizeof(f->event_mask));
166 }
167 static inline void filter_set_opcode(uint16_t opcode, hci_ufilter *f) noexcept
168 {
169 f->opcode = opcode;
170 }
171 static inline void filter_clear_opcode(hci_ufilter *f) noexcept
172 {
173 f->opcode = 0;
174 }
175 static inline int filter_test_opcode(uint16_t opcode, hci_ufilter *f) noexcept
176 {
177 return (f->opcode == opcode);
178 }
179 };
180
181 /**@}*/
182
183} // namespace direct_bt
184
185#endif /* HCI_COMM_HPP_ */
Read/Write HCI communication channel.
Definition: HCIComm.hpp:61
static uint32_t filter_test_ptype(int t, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:143
HCIComm(const uint16_t dev_id, const uint16_t channel) noexcept
Constructing a newly opened HCI communication channel instance.
Definition: HCIComm.cpp:111
bool is_open() const noexcept
Definition: HCIComm.hpp:91
void close() noexcept
Closing the HCI channel, locking mutex_write().
Definition: HCIComm.cpp:118
const uint16_t channel
Definition: HCIComm.hpp:67
bool interrupted() const noexcept
Returns true if interrupted by internal or external cause, hence shall stop connecting and reading.
Definition: HCIComm.hpp:97
static void filter_all_ptypes(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:147
const uint16_t dev_id
Definition: HCIComm.hpp:66
std::recursive_mutex & mutex_write() noexcept
Return the recursive write mutex for multithreading access.
Definition: HCIComm.hpp:106
static void filter_set_opcode(uint16_t opcode, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:167
static void filter_clear_ptype(int t, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:139
static int filter_test_opcode(uint16_t opcode, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:175
static void filter_clear_opcode(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:171
static uint32_t filter_test_event(int e, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:159
jau::snsize_t read(uint8_t *buffer, const jau::nsize_t capacity, const jau::fraction_i64 &timeout) noexcept
Generic read w/ own timeout, w/o locking suitable for a unique ringbuffer sink.
Definition: HCIComm.cpp:148
void set_interrupted_query(get_boolean_callback_t is_interrupted_cb)
The external is interrupted callback is used until close(), thereafter it is removed.
Definition: HCIComm.hpp:94
void operator=(const HCIComm &)=delete
~HCIComm() noexcept
Releases this instance after issuing close().
Definition: HCIComm.hpp:89
int socket() const noexcept
Return this HCI socket descriptor.
Definition: HCIComm.hpp:103
HCIComm(const HCIComm &)=delete
static void filter_all_events(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:163
jau::function< bool(int)> get_boolean_callback_t
Utilized to query for external interruption, whether device is still connected etc.
Definition: HCIComm.hpp:64
static void filter_set_event(int e, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:151
static void filter_clear(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:131
static void filter_clear_event(int e, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:155
static void filter_set_ptype(int t, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:135
jau::snsize_t write(const uint8_t *buffer, const jau::nsize_t size) noexcept
Generic write, locking mutex_write().
Definition: HCIComm.cpp:191
Class template jau::function is a general-purpose static-polymorphic function wrapper.
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition: int_types.hpp:65