43#include "HCIIoctl.hpp"
56 #include <sys/ioctl.h>
63HCIEnv::HCIEnv() noexcept
65 HCI_READER_THREAD_POLL_TIMEOUT(
jau::
environment::getFractionProperty("
direct_bt.hci.reader.timeout", 10_s, 1500_ms , 365_d ) ),
66 HCI_COMMAND_STATUS_REPLY_TIMEOUT(
jau::
environment::getFractionProperty("
direct_bt.hci.cmd.status.timeout", 3_s, 1500_ms , 365_d ) ),
67 HCI_COMMAND_COMPLETE_REPLY_TIMEOUT(
jau::
environment::getFractionProperty("
direct_bt.hci.cmd.complete.timeout", 10_s, 1500_ms , 365_d ) ),
68 HCI_COMMAND_POLL_PERIOD(
jau::
environment::getFractionProperty("
direct_bt.hci.cmd.poll.period", 125_ms, 50_ms, 365_d) ),
72 HCI_READ_PACKET_MAX_RETRY( HCI_EVT_RING_CAPACITY )
83 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
84 auto end = list.end();
85 for (
auto it = list.begin(); it != end; ++it) {
86 HCIConnectionRef conn = *it;
87 if ( conn->equals(visibleAddressAndType) ) {
88 conn->setResolvAddrAndType(addressAndType);
97 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
98 auto end = list.end();
99 for (
auto it = list.begin(); it != end; ++it) {
100 HCIConnectionRef conn = *it;
101 if ( conn->equals(addressAndType) ) {
103 WORDY_PRINT(
"HCIHandler<%u>::addTrackerConnection: address%s, handle %s: reuse entry %s - %s",
105 conn->toString().c_str(), toString().c_str());
108 if( 0 != conn->getHandle() && handle != conn->getHandle() ) {
109 WARN_PRINT(
"address%s, handle %s: reusing entry %s, overwriting non-zero handle - %s",
111 conn->toString().c_str(), toString().c_str());
113 conn->setHandle( handle );
119 HCIConnectionRef res( std::make_shared<HCIConnection>(addressAndType, handle) );
120 list.push_back( res );
122 }
catch (
const std::bad_alloc &e) {
123 ABORT(
"Error: bad_alloc: HCIConnectionRef allocation failed");
129 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
132 HCIConnectionRef & e = list[i];
133 if( e->equals(addressAndType) ) {
141 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
144 HCIConnectionRef & e = connectionList[i];
145 if ( handle == e->getHandle() ) {
153 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
154 auto end = connectionList.end();
155 for (
auto it = connectionList.begin(); it != end; ++it) {
156 HCIConnectionRef e = *it;
158 connectionList.erase(it);
165 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
167 for (
const auto& e : connectionList) {
168 if ( e->getHandle() == 0 ) {
175 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
176 return connectionList.size();
179 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
180 auto end = list.end();
181 for (
auto it = list.begin(); it != end; ++it) {
182 HCIConnectionRef e = *it;
183 if ( e->getHandle() == handle ) {
212std::unique_ptr<MgmtEvent> HCIHandler::translate(
HCIEvent& ev)
noexcept {
220 const hci_ev_le_conn_complete * ev_cc = getMetaReplyStruct<hci_ev_le_conn_complete>(ev, mevt, &status);
221 if(
nullptr == ev_cc ) {
222 ERR_PRINT(
"LE_CONN_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
228 const HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, handle);
230 advertisingEnabled =
false;
231 return std::make_unique<MgmtEvtDeviceConnected>(dev_id, addressAndType, handle);
233 removeTrackerConnection(conn);
234 return std::make_unique<MgmtEvtDeviceConnectFailed>(dev_id, addressAndType, status);
239 const HCIConnectionRef conn = findTrackerConnection(ev2.
getHandle());
240 if(
nullptr == conn ) {
241 WARN_PRINT(
"dev_id %u: LE_LTK_REQUEST: Not tracked conn_handle of %s", dev_id, ev2.
toString().c_str());
244 return std::make_unique<MgmtEvtHCILELTKReq>(dev_id, conn->getAddressAndType(), ev2.
getRand(), ev2.
getEDIV());
248 const hci_ev_le_enh_conn_complete * ev_cc = getMetaReplyStruct<hci_ev_le_enh_conn_complete>(ev, mevt, &status);
249 if(
nullptr == ev_cc ) {
250 ERR_PRINT(
"LE_EXT_CONN_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
256 const HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, handle);
258 advertisingEnabled =
false;
259 return std::make_unique<MgmtEvtDeviceConnected>(dev_id, addressAndType, handle);
261 removeTrackerConnection(conn);
262 return std::make_unique<MgmtEvtDeviceConnectFailed>(dev_id, addressAndType, status);
267 const hci_ev_le_remote_feat_complete * ev_cc = getMetaReplyStruct<hci_ev_le_remote_feat_complete>(ev, mevt, &status);
268 if(
nullptr == ev_cc ) {
269 ERR_PRINT(
"LE_REMOTE_FEAT_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
274 const HCIConnectionRef conn = findTrackerConnection(handle);
275 if(
nullptr == conn ) {
276 WARN_PRINT(
"dev_id %u:: LE_REMOTE_FEAT_COMPLETE: Not tracked conn_handle %s of %s",
280 return std::make_unique<MgmtEvtHCILERemoteFeatures>(dev_id, conn->getAddressAndType(), status, features);
284 struct le_phy_update_complete {
290 const le_phy_update_complete * ev_cc = getMetaReplyStruct<le_phy_update_complete>(ev, mevt, &status);
291 if(
nullptr == ev_cc ) {
292 ERR_PRINT(
"LE_PHY_UPDATE_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
298 const HCIConnectionRef conn = findTrackerConnection(handle);
299 if(
nullptr == conn ) {
300 WARN_PRINT(
"dev_id %u:: LE_PHY_UPDATE_COMPLETE: Not tracked conn_handle %s of %s",
304 return std::make_unique<MgmtEvtHCILEPhyUpdateComplete>(dev_id, conn->getAddressAndType(), status, Tx, Rx);
313 const hci_ev_conn_complete * ev_cc = getReplyStruct<hci_ev_conn_complete>(ev, evt, &status);
314 if(
nullptr == ev_cc ) {
315 ERR_PRINT(
"CONN_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
319 HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, ev_cc->handle);
321 advertisingEnabled =
false;
322 return std::make_unique<MgmtEvtDeviceConnected>(dev_id, conn->getAddressAndType(), conn->getHandle());
325 std::unique_ptr<MgmtEvent> res( std::make_unique<MgmtEvtDeviceConnectFailed>(dev_id, conn->getAddressAndType(),status) );
326 removeTrackerConnection(conn);
328 }
catch (
const std::bad_alloc &e) {
329 ABORT(
"Error: bad_alloc: MgmtEvtDeviceConnectFailedRef allocation failed");
336 const hci_ev_disconn_complete * ev_cc = getReplyStruct<hci_ev_disconn_complete>(ev, evt, &status);
337 if(
nullptr == ev_cc ) {
338 ERR_PRINT(
"DISCONN_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
341 removeDisconnectCmd(ev_cc->handle);
342 HCIConnectionRef conn = removeTrackerConnection(ev_cc->handle);
343 if(
nullptr == conn ) {
344 WORDY_PRINT(
"HCIHandler<%u>::translate(evt): DISCONN_COMPLETE: Not tracked handle %s: %s of %s",
345 dev_id,
jau::to_hexstring(ev_cc->handle).c_str(), ev.toString().c_str(), toString().c_str());
350 ERR_PRINT(
"DISCONN_COMPLETE: !SUCCESS[%s, %s], %s: %s - %s",
352 conn->toString().c_str(), ev.toString().c_str(), toString().c_str());
355 return std::make_unique<MgmtEvtDeviceDisconnected>(dev_id, conn->getAddressAndType(), hciRootReason, conn->getHandle());
360 const hci_ev_encrypt_change * ev_cc = getReplyStruct<hci_ev_encrypt_change>(ev, evt, &status);
361 if(
nullptr == ev_cc ) {
362 ERR_PRINT(
"ENCRYPT_CHANGE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
366 const HCIConnectionRef conn = findTrackerConnection(handle);
367 if(
nullptr == conn ) {
368 WARN_PRINT(
"dev_id %u:: ENCRYPT_CHANGE: Not tracked conn_handle %s of %s",
372 return std::make_unique<MgmtEvtHCIEncryptionChanged>(dev_id, conn->getAddressAndType(), status, ev_cc->encrypt);
376 const hci_ev_key_refresh_complete * ev_cc = getReplyStruct<hci_ev_key_refresh_complete>(ev, evt, &status);
377 if(
nullptr == ev_cc ) {
378 ERR_PRINT(
"ENCRYPT_KEY_REFRESH_COMPLETE: Null reply-struct: %s - %s", ev.toString().c_str(), toString().c_str());
382 const HCIConnectionRef conn = findTrackerConnection(handle);
383 if(
nullptr == conn ) {
384 WARN_PRINT(
"dev_id %u:: ENCRYPT_KEY_REFRESH_COMPLETE: Not tracked conn_handle %s of %s",
388 return std::make_unique<MgmtEvtHCIEncryptionKeyRefreshComplete>(dev_id, conn->getAddressAndType(), status);
398std::unique_ptr<MgmtEvent> HCIHandler::translate(
HCICommand& ev)
noexcept {
403 const HCIConnectionRef conn = findTrackerConnection(ev2.
getHandle());
404 if(
nullptr == conn ) {
405 WARN_PRINT(
"dev_id %u:: LE_ENABLE_ENC: Not tracked conn_handle %s", dev_id, ev2.
toString().c_str());
408 return std::make_unique<MgmtEvtHCILEEnableEncryptionCmd>(dev_id, conn->getAddressAndType(),
413 const HCIConnectionRef conn = findTrackerConnection(ev2.
getHandle());
414 if(
nullptr == conn ) {
415 WARN_PRINT(
"dev_id %u:: LE_LTK_REPLY_ACK: Not tracked conn_handle %s", dev_id, ev2.
toString().c_str());
418 return std::make_unique<MgmtEvtHCILELTKReplyAckCmd>(dev_id, conn->getAddressAndType(), ev2.
getLTK());
422 const HCIConnectionRef conn = findTrackerConnection(ev2.
getHandle());
423 if(
nullptr == conn ) {
424 WARN_PRINT(
"dev_id %u:: LE_LTK_REPLY_REJ: Not tracked conn_handle %s", dev_id, ev2.
toString().c_str());
427 return std::make_unique<MgmtEvtHCILELTKReplyRejCmd>(dev_id, conn->getAddressAndType());
434std::unique_ptr<const SMPPDUMsg> HCIHandler::getSMPPDUMsg(
const HCIACLData::l2cap_frame & l2cap,
const uint8_t * l2cap_data)
const noexcept {
435 if(
nullptr != l2cap_data && 0 < l2cap.len && l2cap.isSMP() ) {
445 ERR_PRINT(
"Not connected %s", toString().c_str());
450 len = comm.read(rbuffer.get_wptr(), rbuffer.size(), env.HCI_READER_THREAD_POLL_TIMEOUT);
458 if(
nullptr == acldata ) {
461 WARN_PRINT(
"dev_id %u: IO RECV Drop ACL (non-acl-data) %s - %s",
462 dev_id,
jau::bytesHexString(rbuffer.get_ptr(), 0, len2,
true ).c_str(), toString().c_str());
466 const uint8_t* l2cap_data =
nullptr;
468 std::unique_ptr<const SMPPDUMsg> smpPDU = getSMPPDUMsg(l2cap, l2cap_data);
469 if(
nullptr != smpPDU ) {
470 HCIConnectionRef conn = findTrackerConnection(l2cap.
handle);
472 if(
nullptr != conn ) {
473 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV ACL (SMP) %s for %s",
474 dev_id, smpPDU->toString().c_str(), conn->toString().c_str());
476 cb(conn->getAddressAndType(), *smpPDU, l2cap);
479 WARN_PRINT(
"dev_id %u: IO RECV ACL Drop (SMP): Not tracked conn_handle %s: %s, %s",
481 l2cap.
toString().c_str(), smpPDU->toString().c_str());
483 }
else if( !l2cap.
isGATT() ) {
484 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV ACL Drop (L2CAP): ???? %s",
485 dev_id, acldata->toString(l2cap, l2cap_data).c_str());
493 if(
nullptr == event ) {
495 ERR_PRINT(
"IO RECV CMD Drop (non-command) %s - %s",
499 std::unique_ptr<MgmtEvent> mevent = translate(*event);
500 if(
nullptr != mevent ) {
501 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV CMD (CB) %s\n -> %s", dev_id, event->toString().c_str(), mevent->toString().c_str());
502 sendMgmtEvent( *mevent );
504 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV CMD Drop (no translation) %s", dev_id, event->toString().c_str());
510 WARN_PRINT(
"dev_id %u: IO RECV EVT Drop (not event, nor command, nor acl-data) %s - %s",
511 dev_id,
jau::bytesHexString(rbuffer.get_ptr(), 0, len2,
true ).c_str(), toString().c_str());
517 if(
nullptr == event ) {
519 ERR_PRINT(
"IO RECV EVT Drop (non-event) %s - %s",
527 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV EVT Drop (meta filter) %s", dev_id, event->toString().c_str());
533 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV EVT (CMD REPLY) %s", dev_id, event->toString().c_str());
534 if( hciEventRing.isFull() ) {
535 const jau::nsize_t dropCount = hciEventRing.capacity()/4;
536 hciEventRing.drop(dropCount);
537 WARN_PRINT(
"dev_id %u: IO RECV Drop (%u oldest elements of %u capacity, ring full) - %s",
538 dev_id, dropCount, hciEventRing.capacity(), toString().c_str());
541 ERR_PRINT2(
"hciEventRing put: %s", hciEventRing.toString().c_str());
550 COND_PRINT(env.DEBUG_SCAN_AD_EIR,
"HCIHandler<%u>-IO RECV EVT (AD EIR) [%d] %s",
551 dev_id, eircount, e.getEIR()->toString().c_str());
559 COND_PRINT(env.DEBUG_SCAN_AD_EIR,
"HCIHandler<%u>-IO RECV EVT (EAD EIR (ext)) [%d] %s",
560 dev_id, eircount, e.getEIR()->toString().c_str());
565 std::unique_ptr<MgmtEvent> mevent = translate(*event);
566 if(
nullptr != mevent ) {
567 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV EVT (CB) %s\n -> %s", dev_id, event->toString().c_str(), mevent->toString().c_str());
568 sendMgmtEvent( *mevent );
570 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV EVT Drop (no translation) %s", dev_id, event->toString().c_str());
573 }
else if( 0 > len && ETIMEDOUT != errno && !comm.interrupted() ) {
574 ERR_PRINT(
"HCIComm read: Error res %d, %s", len, toString().c_str());
576 }
else if( ETIMEDOUT != errno && !comm.interrupted() ) {
577 WORDY_PRINT(
"HCIHandler<%u>::reader: HCIComm read: IRQed res %d, %s", dev_id, len, toString().c_str());
583 WORDY_PRINT(
"HCIHandler<%u>::reader: Ended. Ring has %u entries flushed - %s", dev_id, hciEventRing.size(), toString().c_str());
584 hciEventRing.clear();
589 MgmtEventCallbackList & mgmtEventCallbackList = mgmtEventCallbackLists[
static_cast<uint16_t
>(
event.getOpcode())];
595 }
catch (std::exception &e) {
596 ERR_PRINT(
"CBs %d/%zd: MgmtEventCallback %s : Caught exception %s - %s",
597 invokeCount+1, mgmtEventCallbackList.
size(),
598 cb.toString().c_str(), e.what(), toString().c_str());
603 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>::sendMgmtEvent: Event %s -> %d/%zd callbacks",
604 dev_id, event.toString().c_str(), invokeCount, mgmtEventCallbackList.
size());
608bool HCIHandler::sendCommand(
HCICommand &req,
const bool quiet)
noexcept {
609 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO SENT %s", dev_id, req.toString().c_str());
612 if ( comm.write( pdu.
get_ptr(), pdu.
size() ) < 0 ) {
614 ERR_PRINT(
"HCIComm write error, req %s - %s", req.toString().c_str(), toString().c_str());
621std::unique_ptr<HCIEvent> HCIHandler::getNextReply(
HCICommand &req, int32_t & retryCount,
const jau::fraction_i64& replyTimeout)
noexcept
624 while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
625 std::unique_ptr<HCIEvent> ev;
626 if( !hciEventRing.getBlocking(ev, replyTimeout) ||
nullptr == ev ) {
628 ERR_PRINT(
"nullptr result (timeout %" PRIi64
" ms -> abort): req %s - %s", replyTimeout.to_ms(), req.toString().c_str(), toString().c_str());
630 }
else if( !ev->validate(req) ) {
634 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV getNextReply: res mismatch (drop, retry %d): res %s; req %s",
635 dev_id, retryCount, ev->toString().c_str(), req.toString().c_str());
637 COND_PRINT(env.DEBUG_EVENT,
"HCIHandler<%u>-IO RECV getNextReply: res %s; req %s", dev_id, ev->toString().c_str(), req.toString().c_str());
645 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
649 int32_t retryCount = 0;
650 std::unique_ptr<HCIEvent> ev =
nullptr;
652 while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
653 ev = getNextReply(req, retryCount, env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT);
654 if(
nullptr == ev ) {
665 DBG_WARN_PRINT(
"dev_id %u: CMD_STATUS 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
666 dev_id,
number(status),
to_string(status).c_str(), errno, strerror(errno),
667 ev_cs->
toString().c_str(), req.toString().c_str(), toString().c_str());
670 DBG_PRINT(
"HCIHandler<%u>::getNextCmdCompleteReply: CMD_STATUS 0x%2.2X (%s, retryCount %d), errno %d %s: res %s, req %s - %s",
671 dev_id,
number(status),
to_string(status).c_str(), retryCount, errno, strerror(errno),
672 ev_cs->
toString().c_str(), req.toString().c_str(), toString().c_str());
678 DBG_PRINT(
"HCIHandler<%u>::getNextCmdCompleteReply: !(CMD_COMPLETE, CMD_STATUS) (drop, retry %d): res %s; req %s - %s",
679 dev_id, retryCount, ev->toString().c_str(), req.toString().c_str(), toString().c_str());
690 comm(dev_id_, HCI_CHANNEL_RAW),
695 hciEventRing(env.HCI_EVT_RING_CAPACITY),
697 sup_commands_set(
false ),
698 allowClose( comm.is_open() ),
701 advertisingEnabled(
false)
705 WORDY_PRINT(
"HCIHandler<%u>.ctor: Start %s", dev_id, toString().c_str());
707 ERR_PRINT(
"Could not open hci control channel %s", toString().c_str());
712 hci_reader_service.start();
719 if (setsockopt(comm.socket(), SOL_SOCKET, SO_TIMESTAMP, &opt,
sizeof(opt)) < 0) {
720 ERR_PRINT(
"setsockopt SO_TIMESTAMP %s", toString().c_str());
724 if (setsockopt(comm.socket(), SOL_SOCKET, SO_PASSCRED, &opt,
sizeof(opt)) < 0) {
725 ERR_PRINT(
"setsockopt SO_PASSCRED %s", toString().c_str());
731#define FILTER_ALL_EVENTS 0
741 if (getsockopt(comm.socket(), SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
742 ERR_PRINT(
"getsockopt %s", toString().c_str());
775 if (setsockopt(comm.socket(), SOL_HCI, HCI_FILTER, &filter_mask,
sizeof(filter_mask)) < 0) {
776 ERR_PRINT(
"setsockopt HCI_FILTER %s", toString().c_str());
784 filter_all_metaevs(mask);
796 filter_put_metaevs(mask);
802 filter_all_opcbit(mask);
833 filter_put_opcbit(mask);
838 WORDY_PRINT(
"HCIHandler.ctor: End OK - %s", toString().c_str());
844 WORDY_PRINT(
"HCIHandler.ctor: End failure - %s", toString().c_str());
848void HCIHandler::zeroSupCommands() noexcept {
849 bzero(sup_commands,
sizeof(sup_commands));
850 sup_commands_set =
false;
853bool HCIHandler::initSupCommands() noexcept {
864 const hci_rp_le_read_local_features * ev_lf;
865 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lf, &status,
true );
867 DBG_PRINT(
"HCIHandler<%u>::initSupCommands: LE_READ_LOCAL_FEATURES: 0x%x (%s) - %s",
876 const hci_rp_read_local_commands * ev_cmds;
877 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_cmds, &status,
true );
879 DBG_PRINT(
"HCIHandler<%u>::initSupCommands: READ_LOCAL_COMMANDS: 0x%x (%s) - %s",
884 memcpy(sup_commands, ev_cmds->commands,
sizeof(sup_commands));
885 sup_commands_set =
true;
890HCIStatusCode HCIHandler::check_open_connection(
const std::string& caller,
892 const bool addUntrackedConn) {
897 if( 0 == conn_handle ) {
898 ERR_PRINT(
"%s: Null conn_handle given address%s (drop) - %s",
902 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
904 if(
nullptr == conn ) {
906 if( addUntrackedConn ) {
908 conn = addOrUpdateTrackerConnection(peerAddressAndType, conn_handle);
909 WORDY_PRINT(
"HCIHandler::%s: Not tracked address%s, added %s - %s",
910 caller.c_str(), peerAddressAndType.
toString().c_str(),
911 conn->toString().c_str(),
toString().c_str());
913 ERR_PRINT(
"%s: Not tracked handle %s (address%s) (drop) - %s",
918 }
else if( !conn->equals(peerAddressAndType) ) {
919 ERR_PRINT(
"%s: Mismatch given address%s and tracked %s (drop) - %s",
920 caller.c_str(), peerAddressAndType.
toString().c_str(),
921 conn->toString().c_str(),
toString().c_str());
924 DBG_PRINT(
"HCIHandler<%u>::%s: address%s, handle %s, %s - %s",
925 dev_id, caller.c_str(), peerAddressAndType.
toString().c_str(),
927 conn->toString().c_str(),
toString().c_str());
933 HCIStatusCode status = check_open_connection(
"le_read_remote_features", conn_handle, peerAddressAndType);
938 hci_cp_le_read_remote_features * cp = req0.
getWStruct();
940 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
943 ERR_PRINT(
"le_read_remote_features: LE_READ_PHY: 0x%x (%s) - %s",
954 const bool hci_service_stopped = hci_reader_service.
join();
956 DBG_PRINT(
"HCIHandler<%u>::close: Not open: stopped %d, %s", dev_id, hci_service_stopped,
toString().c_str());
963 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
969 hci_reader_service.
stop();
990 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
993 #if defined(__linux__)
995 if( ( res_ioctl = ioctl(comm.
socket(), HCIDEVUP, dev_id) ) < 0 ) {
996 if (errno != EALREADY) {
1004 #elif defined(__FreeBSD__)
1006 ABORT(
"add implementation for FreeBSD");
1008 #warning add implementation
1009 ABORT(
"add implementation");
1025 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1028 #if defined(__linux__)
1030 if( ( res_ioctl = ioctl(comm.
socket(), HCIDEVDOWN, dev_id) ) < 0) {
1035 #elif defined(__FreeBSD__)
1037 ABORT(
"add implementation for FreeBSD");
1039 #warning add implementation
1040 ABORT(
"add implementation");
1055 bool user_called =
false;
1056 bool user_abort =
false;
1058 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1061 #if defined(__linux__)
1062 res = stopAdapter();
1064 if(
nullptr != user_post_shutdown ) {
1066 res = user_post_shutdown();
1070 res = startAdapter();
1073 #elif defined(__FreeBSD__)
1075 (void)user_post_shutdown;
1076 ABORT(
"add implementation for FreeBSD");
1078 #warning add implementation
1079 (void)user_post_shutdown;
1080 ABORT(
"add implementation");
1082 DBG_PRINT(
"HCIHandler<%u>::resetAdapter.X: %s user[called %d, abort %d] - %s", dev_id,
to_string(res).c_str(), user_called, user_abort,
toString().c_str());
1087 const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList);
1088 connectionList.clear();
1089 disconnectCmdList.clear();
1091 advertisingEnabled =
false;
1094 return initSupCommands();
1103 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1109 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &res);
1110 if(
nullptr == ev ) {
1119 ERR_PRINT(
"Not connected %s", toString().c_str());
1123 const hci_rp_read_local_version * ev_lv;
1125 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lv, &status);
1129 bzero(&version,
sizeof(version));
1131 version.hci_ver = ev_lv->hci_ver;
1134 version.lmp_ver = ev_lv->lmp_ver;
1145 ERR_PRINT(
"Not connected %s", toString().c_str());
1149 WARN_PRINT(
"Not allowed: LE Scan Enabled: %s - tried scan [interval %.3f ms, window %.3f ms]",
1153 DBG_PRINT(
"HCIHandler<%u>::le_set_scan_param: scan [active %d, interval %.3f ms, window %.3f ms, filter %d] - %s",
1159 if( use_ext_scan() ) {
1160 struct le_set_ext_scan_params {
1161 __u8 own_address_type;
1164 hci_cp_le_scan_phy_params p1;
1168 le_set_ext_scan_params * cp = req0.getWStruct();
1169 cp->own_address_type =
static_cast<uint8_t
>(own_mac_type);
1179 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1182 hci_cp_le_set_scan_param * cp = req0.getWStruct();
1186 cp->own_address_type =
static_cast<uint8_t
>(own_mac_type);
1190 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1197 ERR_PRINT(
"Not connected %s", toString().c_str());
1200 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1202 if( enable && advertisingEnabled ) {
1203 WARN_PRINT(
"dev_id %u: Not allowed: Advertising is enabled %s", dev_id, toString().c_str());
1207 DBG_PRINT(
"HCIHandler<%u>::le_enable_scan: enable %s -> %s, filter_dup %d - %s",
1211 if( currentScanType != nextScanType ) {
1212 if( use_ext_scan() ) {
1214 hci_cp_le_set_ext_scan_enable * cp = req0.
getWStruct();
1215 cp->enable = enable ? LE_SCAN_ENABLE : LE_SCAN_DISABLE;
1216 cp->filter_dup =
filter_dup ? LE_SCAN_FILTER_DUP_ENABLE : LE_SCAN_FILTER_DUP_DISABLE;
1220 std::unique_ptr<HCIEvent> evComplete = processCommandComplete(req0, &ev_status, &status);
1223 hci_cp_le_set_scan_enable * cp = req0.
getWStruct();
1224 cp->enable = enable ? LE_SCAN_ENABLE : LE_SCAN_DISABLE;
1225 cp->filter_dup =
filter_dup ? LE_SCAN_FILTER_DUP_ENABLE : LE_SCAN_FILTER_DUP_DISABLE;
1227 std::unique_ptr<HCIEvent> evComplete = processCommandComplete(req0, &ev_status, &status);
1231 WARN_PRINT(
"dev_id %u: current %s == next %s, OK, skip command - %s",
1232 dev_id,
to_string(currentScanType).c_str(),
to_string(nextScanType).c_str(), toString().c_str());
1236 currentScanType = nextScanType;
1249 ERR_PRINT(
"Not connected %s", toString().c_str());
1252 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1254 if( advertisingEnabled ) {
1255 WARN_PRINT(
"dev_id %u: Not allowed: Advertising is enabled %s", dev_id, toString().c_str());
1259 WARN_PRINT(
"dev_id %u: Not allowed: LE Scan Enabled: %s", dev_id, toString().c_str());
1264 WARN_PRINT(
"dev_id %u: le_set_scan_param failed: %s - %s",
1265 dev_id,
to_string(status).c_str(), toString().c_str());
1270 WARN_PRINT(
"dev_id %u: le_enable_scan failed: %s - %s",
1271 dev_id,
to_string(status).c_str(), toString().c_str());
1280 const uint16_t conn_interval_min,
const uint16_t conn_interval_max,
1281 const uint16_t conn_latency,
const uint16_t supervision_timeout)
noexcept {
1287 const std::lock_guard<std::mutex> lock(mtx_connect_cmd);
1290 ERR_PRINT(
"Not connected %s", toString().c_str());
1293 if( advertisingEnabled ) {
1294 WARN_PRINT(
"Not allowed: Advertising is enabled %s", toString().c_str());
1298 const uint16_t min_ce_length = 0x0000;
1299 const uint16_t max_ce_length = 0x0000;
1300 const uint8_t initiator_filter = 0x00;
1302 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: scan [interval %.3f ms, window %.3f ms]", 0.625f *
1304 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: conn [interval [%.3f ms - %.3f ms], latency %d, sup_timeout %d ms] - %s",
1305 dev_id, 1.25f * (
float)conn_interval_min, 1.25f * (
float)conn_interval_max,
1306 conn_latency, supervision_timeout*10, toString().c_str());
1308 size_type pendingConnections = countPendingTrackerConnections();
1309 if( 0 < pendingConnections ) {
1310 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: %zu connections pending - %s", dev_id, (
size_t)pendingConnections, toString().c_str());
1312 while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && 0 < pendingConnections ) {
1314 td += env.HCI_COMMAND_POLL_PERIOD;
1315 pendingConnections = countPendingTrackerConnections();
1317 if( 0 < pendingConnections ) {
1318 WARN_PRINT(
"%zu connections pending after %" PRIi64
" ms - %s", (
size_t)pendingConnections, td.
to_ms(), toString().c_str());
1320 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: pending connections resolved after %" PRIi64
" ms - %s", dev_id, td.
to_ms(), toString().c_str());
1325 if(
nullptr != disconn ) {
1326 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: disconnect pending %s - %s",
1327 dev_id, disconn->toString().c_str(), toString().c_str());
1329 while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td &&
nullptr != disconn ) {
1331 td += env.HCI_COMMAND_POLL_PERIOD;
1332 disconn = findDisconnectCmd(addressAndType);
1334 if(
nullptr != disconn ) {
1335 WARN_PRINT(
"disconnect persisting after %" PRIi64
" ms: %s - %s",
1336 td.
to_ms(), disconn->toString().c_str(), toString().c_str());
1338 DBG_PRINT(
"HCIHandler<%u>::le_create_conn: disconnect resolved after %" PRIi64
" ms - %s", dev_id, td.
to_ms(), toString().c_str());
1344 if( use_ext_conn() ) {
1345 struct le_ext_create_conn {
1347 __u8 own_address_type;
1348 __u8 peer_addr_type;
1351 hci_cp_le_ext_conn_param p1;
1357 cp->filter_policy = initiator_filter;
1358 cp->own_address_type =
static_cast<uint8_t
>(own_mac_type);
1359 cp->peer_addr_type =
static_cast<uint8_t
>(peer_mac_type);
1368 cp->p1.supervision_timeout =
jau::cpu_to_le(supervision_timeout);
1373 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1379 hci_cp_le_create_conn * cp = req0.
getWStruct();
1382 cp->filter_policy = initiator_filter;
1383 cp->peer_addr_type =
static_cast<uint8_t
>(peer_mac_type);
1385 cp->own_address_type =
static_cast<uint8_t
>(own_mac_type);
1393 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1398 removeTrackerConnection(conn);
1401 const std::string s0 =
nullptr != disconn ? disconn->toString() :
"null";
1402 WARN_PRINT(
"%s: disconnect pending: %s - %s",
1403 to_string(status).c_str(), s0.c_str(), toString().c_str());
1410 const uint16_t pkt_type,
1411 const uint16_t clock_offset,
const uint8_t role_switch)
noexcept {
1417 const std::lock_guard<std::mutex> lock(mtx_connect_cmd);
1420 ERR_PRINT(
"Not connected %s", toString().c_str());
1423 if( advertisingEnabled ) {
1424 WARN_PRINT(
"Not allowed: Advertising is enabled %s", toString().c_str());
1431 cp->pkt_type =
jau::cpu_to_le((uint16_t)(pkt_type & (uint16_t)ACL_PTYPE_MASK));
1432 cp->pscan_rep_mode = 0x02;
1433 cp->pscan_mode = 0x00;
1435 cp->role_switch = role_switch;
1437 size_type pendingConnections = countPendingTrackerConnections();
1438 if( 0 < pendingConnections ) {
1439 DBG_PRINT(
"HCIHandler<%u>::create_conn: %zu connections pending - %s", dev_id, (
size_t)pendingConnections, toString().c_str());
1441 while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && 0 < pendingConnections ) {
1443 td += env.HCI_COMMAND_POLL_PERIOD;
1444 pendingConnections = countPendingTrackerConnections();
1446 if( 0 < pendingConnections ) {
1447 WARN_PRINT(
"%zu connections pending after %" PRIi64
" ms - %s", (
size_t)pendingConnections, td.
to_ms(), toString().c_str());
1449 DBG_PRINT(
"HCIHandler<%u>::create_conn: pending connections resolved after %" PRIi64
" ms - %s", dev_id, td.
to_ms(), toString().c_str());
1454 if(
nullptr != disconn ) {
1455 DBG_PRINT(
"HCIHandler<%u>::create_conn: disconnect pending %s - %s",
1456 dev_id, disconn->toString().c_str(), toString().c_str());
1458 while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td &&
nullptr != disconn ) {
1460 td += env.HCI_COMMAND_POLL_PERIOD;
1461 disconn = findDisconnectCmd(addressAndType);
1463 if(
nullptr != disconn ) {
1464 WARN_PRINT(
"disconnect persisting after %" PRIi64
" ms: %s - %s",
1465 td.
to_ms(), disconn->toString().c_str(), toString().c_str());
1467 DBG_PRINT(
"HCIHandler<%u>::create_conn: disconnect resolved after %" PRIi64
" ms - %s", dev_id, td.
to_ms(), toString().c_str());
1472 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1474 removeTrackerConnection(conn);
1477 const std::string s0 =
nullptr != disconn ? disconn->toString() :
"null";
1478 WARN_PRINT(
"%s: disconnect pending: %s - %s",
1479 to_string(status).c_str(), s0.c_str(), toString().c_str());
1488 HCIStatusCode status = check_open_connection(
"disconnect", conn_handle, peerAddressAndType,
true );
1500 cp->reason =
number(reason);
1502 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1505 addOrUpdateDisconnectCmd(peerAddressAndType, conn_handle);
1515 hci_cp_le_add_to_resolv_list * cp = req0.
getWStruct();
1516 cp->bdaddr_type =
static_cast<uint8_t
>(peerIdentityAddressAndType.type);
1521 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1532 hci_cp_le_del_from_resolv_list * cp = req0.
getWStruct();
1533 cp->bdaddr_type =
static_cast<uint8_t
>(peerIdentityAddressAndType.type);
1536 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1548 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1560 const hci_rp_le_read_resolv_list_size * ev_res;
1561 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1565 size_res = ev_res->size;
1571 jau::EUI48& peerResolvableAddress)
noexcept {
1573 peerResolvableAddress.clear();
1576 hci_cp_le_read_peer_resolv_addr * cp = req0.
getWStruct();
1577 cp->peer_id_addr_type =
static_cast<uint8_t
>(peerIdentityAddressAndType.type);
1578 cp->peer_id_addr =
jau::cpu_to_le(peerIdentityAddressAndType.address);
1579 const hci_rp_le_read_peer_resolv_addr * ev_res;
1580 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1584 peerResolvableAddress =
jau::le_to_cpu(ev_res->peer_resolv_addr);
1590 jau::EUI48& localResolvableAddress)
noexcept {
1592 localResolvableAddress.clear();
1595 hci_cp_le_read_local_resolv_addr * cp = req0.
getWStruct();
1596 cp->peer_id_addr_type =
static_cast<uint8_t
>(peerIdentityAddressAndType.type);
1597 cp->peer_id_addr =
jau::cpu_to_le(peerIdentityAddressAndType.address);
1598 const hci_rp_le_read_local_resolv_addr * ev_res;
1599 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1603 localResolvableAddress =
jau::le_to_cpu(ev_res->local_resolv_addr);
1612 hci_cp_le_set_addr_resolv_enable * cp = req0.
getWStruct();
1613 cp->enable = enable ? 0x01 : 0x00;
1615 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_res, &status,
true );
1632 HCIStatusCode status = check_open_connection(
"le_read_phy", conn_handle, peerAddressAndType);
1637 struct hci_cp_le_read_phy {
1640 struct hci_rp_le_read_phy {
1650 const hci_rp_le_read_phy * ev_phy;
1651 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_phy, &status);
1657 const uint16_t conn_handle_rcvd =
jau::le_to_cpu(ev_phy->handle);
1658 if( conn_handle != conn_handle_rcvd ) {
1659 ERR_PRINT(
"Mismatch given address%s conn_handle (req) %s != %s (res) (drop) - %s",
1660 peerAddressAndType.
toString().c_str(),
1664 switch( ev_phy->tx_phys ) {
1669 switch( ev_phy->rx_phys ) {
1681 WARN_PRINT(
"dev_id %u: LE_2M_PHY no supported, requested Tx %s", dev_id,
to_string(Tx).c_str());
1685 WARN_PRINT(
"dev_id %u: LE_2M_PHY no supported, requested Rx %s", dev_id,
to_string(Rx).c_str());
1691 ERR_PRINT(
"Not connected %s", toString().c_str());
1697 hci_cp_le_set_default_phy * cp = req0.
getWStruct();
1700 cp->tx_phys =
number( Tx );
1701 cp->rx_phys =
number( Rx );
1704 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1716 WARN_PRINT(
"dev_id %u: LE_2M_PHY no supported, requested Tx %s", dev_id,
to_string(Tx).c_str());
1720 WARN_PRINT(
"dev_id %u: LE_2M_PHY no supported, requested Rx %s", dev_id,
to_string(Rx).c_str());
1725 HCIStatusCode status = check_open_connection(
"le_set_phy", conn_handle, peerAddressAndType);
1730 struct hci_cp_le_set_phy {
1735 uint16_t phy_options;
1743 cp->tx_phys =
number( Tx );
1744 cp->rx_phys =
number( Rx );
1745 cp->phy_options = 0;
1747 std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1762 DBG_PRINT(
"HCIHandler<%u>::le_set_adv_param: adv-interval[%.3f ms .. %.3f ms], filter %d - %s",
1767 if( use_ext_adv() ) {
1769 hci_cp_le_set_ext_adv_params * cp = req0.getWStruct();
1797 cp->evt_properties =
number(adv_type2);
1804 cp->own_addr_type =
static_cast<uint8_t
>(own_mac_type);
1805 cp->peer_addr_type =
static_cast<uint8_t
>(peer_mac_type);
1808 cp->tx_power = 0x7f;
1814 cp->notif_enable = 0x01;
1815 const hci_rp_le_set_ext_adv_params * ev_reply;
1816 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_reply, &status);
1820 hci_cp_le_set_adv_param * cp = req0.getWStruct();
1824 cp->own_address_type =
static_cast<uint8_t
>(own_mac_type);
1825 cp->direct_addr_type =
static_cast<uint8_t
>(peer_mac_type);
1830 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1837 DBG_PRINT(
"HCIHandler<%u>::le_set_adv_data: %d", dev_id, eir.toString(
true).c_str());
1840 if( use_ext_adv() ) {
1843 hci_cp_le_set_ext_adv_data * cp = req0.getWStruct();
1846 cp->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1847 cp->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1848 cp->length = eir.write_data(mask, cp->data, max_data_len);
1849 req0.trimParamSize( req0.getParamSize() + cp->length -
sizeof(cp->data) );
1852 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1857 hci_cp_le_set_adv_data * cp = req0.getWStruct();
1858 cp->length = eir.write_data(mask, cp->data,
sizeof(cp->data));
1862 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1869 DBG_PRINT(
"HCIHandler<%u>::le_set_scanrsp_data: %d", dev_id, eir.toString(
true).c_str());
1872 if( use_ext_adv() ) {
1875 hci_cp_le_set_ext_scan_rsp_data * cp = req0.getWStruct();
1878 cp->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1879 cp->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1880 cp->length = eir.write_data(mask, cp->data, max_data_len);
1881 req0.trimParamSize( req0.getParamSize() + cp->length -
sizeof(cp->data) );
1884 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1889 hci_cp_le_set_scan_rsp_data * cp = req0.getWStruct();
1890 cp->length = eir.write_data(mask, cp->data,
sizeof(cp->data));
1894 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1902 ERR_PRINT(
"Not connected %s", toString().c_str());
1905 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1909 WARN_PRINT(
"Not allowed (scan enabled): %s", toString().c_str());
1912 const size_type connCount = getTrackerConnectionCount();
1913 if( 0 < connCount ) {
1914 WARN_PRINT(
"Not allowed (%zu connections open/pending): %s", (
size_t)connCount, toString().c_str());
1918 DBG_PRINT(
"HCIHandler<%u>::le_enable_adv: enable %d - %s", dev_id, enable, toString().c_str());
1922 if( use_ext_adv() ) {
1925 struct hci_cp_le_set_ext_adv_enable_1 {
1928 hci_cp_ext_adv_set sets[1];
1932 hci_cp_le_set_ext_adv_enable_1 * cp = req0.
getWStruct();
1934 cp->num_of_sets = 1;
1935 cp->sets[0].handle = 0x00;
1936 cp->sets[0].duration = 0;
1937 cp->sets[0].max_events = 0;
1938 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1941 hci_cp_le_set_ext_adv_enable * cp = req0.
getWStruct();
1943 cp->num_of_sets = 0;
1944 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1947 struct hci_cp_le_set_adv_enable {
1951 hci_cp_le_set_adv_enable * cp = req0.
getWStruct();
1952 cp->enable = enable ? 0x01 : 0x00;
1954 std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
1957 advertisingEnabled = enable;
1958 }
else if( advertisingEnabled == enable ) {
1963 WARN_PRINT(
"enable-arg %d == enabled-state %d: Unchanged request, overriding failure: %s -> %s - %s",
1972 const EUI48 &peer_bdaddr,
1981 ERR_PRINT(
"Not connected %s", toString().c_str());
1984 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
1987 WARN_PRINT(
"Not allowed (scan enabled): %s", toString().c_str());
1990 const size_type connCount = getTrackerConnectionCount();
1991 if( 0 < connCount ) {
1992 WARN_PRINT(
"Not allowed (%zu connections open/pending): %s", (
size_t)connCount, toString().c_str());
1999 to_string(status).c_str(), toString().c_str());
2003 status = le_set_scanrsp_data(eir, scanrsp_mask);
2006 to_string(status).c_str(), toString().c_str());
2009 status = le_set_adv_param(peer_bdaddr, own_mac_type, peer_mac_type,
2014 to_string(status).c_str(), toString().c_str());
2018 status = le_enable_adv(
true);
2021 to_string(status).c_str(), toString().c_str());
2027std::unique_ptr<HCIEvent> HCIHandler::processCommandStatus(
HCICommand &req,
HCIStatusCode *status,
const bool quiet)
noexcept
2029 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
2033 int32_t retryCount = 0;
2034 std::unique_ptr<HCIEvent> ev =
nullptr;
2036 if( !sendCommand(req) ) {
2040 while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
2041 ev = getNextReply(req, retryCount, env.HCI_COMMAND_STATUS_REPLY_TIMEOUT);
2042 if(
nullptr == ev ) {
2048 DBG_PRINT(
"HCIHandler<%u>::processCommandStatus %s -> Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
2049 dev_id,
to_string(req.getOpcode()).c_str(),
2051 ev_cs->
toString().c_str(), req.toString().c_str(), toString().c_str());
2055 DBG_PRINT(
"HCIHandler<%u>::processCommandStatus: !CMD_STATUS (drop, retry %d): res %s; req %s - %s",
2056 dev_id, retryCount, ev->toString().c_str(), req.toString().c_str(), toString().c_str());
2060 if(
nullptr == ev ) {
2063 WARN_PRINT(
"%s -> Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
2066 req.toString().c_str(), toString().c_str());
2074template<
typename hci_cmd_event_struct>
2075std::unique_ptr<HCIEvent> HCIHandler::processCommandComplete(
HCICommand &req,
2077 const bool quiet)
noexcept
2079 const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply);
2084 if( !sendCommand(req, quiet) ) {
2086 WARN_PRINT(
"Send failed: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
2088 req.toString().c_str(), toString().c_str());
2093 return receiveCommandComplete(req, res, status, quiet);
2096template<
typename hci_cmd_event_struct>
2097std::unique_ptr<HCIEvent> HCIHandler::receiveCommandComplete(
HCICommand &req,
2099 const bool quiet)
noexcept
2106 std::unique_ptr<HCIEvent> ev = getNextCmdCompleteReply(req, &ev_cc);
2107 if(
nullptr == ev ) {
2110 WARN_PRINT(
"%s -> %s: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
2113 req.toString().c_str(), toString().c_str());
2116 }
else if(
nullptr == ev_cc ) {
2122 WARN_PRINT(
"%s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
2125 ev->toString().c_str(), req.toString().c_str(), toString().c_str());
2130 if( returnParamSize <
sizeof(hci_cmd_event_struct) ) {
2132 WARN_PRINT(
"%s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
2135 ev_cc->
toString().c_str(), req.toString().c_str(), toString().c_str());
2141 DBG_PRINT(
"HCIHandler<%u>::receiveCommandComplete %s -> %s: Status 0x%2.2X (%s): res %s, req %s - %s",
2144 ev_cc->
toString().c_str(), req.toString().c_str(), toString().c_str());
2148template<
typename hci_cmd_event_struct>
2151 const hci_cmd_event_struct* res =
nullptr;
2155 HCITypeCmdCompleteEvtWrap ev_cc( event );
2156 if( ev_cc.isTypeAndSizeValid(evc) ) {
2157 *status = ev_cc.getStatus();
2158 res = ev_cc.getStruct();
2160 WARN_PRINT(
"%s: Type or size mismatch: Status 0x%2.2X (%s), errno %d %s: res %s - %s",
2163 ev_cc.
toString().c_str(), toString().c_str());
2168template<
typename hci_cmd_event_struct>
2171 const hci_cmd_event_struct* res =
nullptr;
2175 const HCITypeCmdCompleteMetaEvtWrap ev_cc( *
static_cast<HCIMetaEvent*
>( &event ) );
2176 if( ev_cc.isTypeAndSizeValid(mec) ) {
2177 *status = ev_cc.getStatus();
2178 res = ev_cc.getStruct();
2180 WARN_PRINT(
"%s: Type or size mismatch: Status 0x%2.2X (%s), errno %d %s: res %s - %s",
2183 ev_cc.
toString().c_str(), toString().c_str());
2198 if( !isValidMgmtEventCallbackListsIndex(opc) ) {
2207 if( !isValidMgmtEventCallbackListsIndex(opc) ) {
2215 if( !isValidMgmtEventCallbackListsIndex(opc) ) {
2219 mgmtEventCallbackLists[
static_cast<uint16_t
>(opc)].
clear();
2222 for(
auto & mgmtEventCallbackList : mgmtEventCallbackLists) {
2223 mgmtEventCallbackList.clear();
2225 hciSMPMsgCallbackList.
clear();
static HCISMPMsgCallbackList::equal_comparator _changedHCISMPMsgCallbackEqComp
SMPMsgCallback handling.
static MgmtEventCallbackList::equal_comparator _mgmtEventCallbackEqComparator
Unique Bluetooth EUI48 address and BDAddressType tuple.
std::string toString() const noexcept
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
static jau::darray< std::unique_ptr< EInfoReport > > read_ext_ad_reports(uint8_t const *data, jau::nsize_t const data_length) noexcept
Reads a complete Advertising Data (AD) Report and returns the number of AD reports in form of a shara...
static std::unique_ptr< HCIACLData > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
void close() noexcept
Closing the HCI channel, locking mutex_write().
static void filter_set_opcode(uint16_t opcode, hci_ufilter *f) noexcept
int socket() const noexcept
Return this HCI socket descriptor.
static void filter_all_events(hci_ufilter *f) noexcept
static void filter_set_event(int e, hci_ufilter *f) noexcept
static void filter_clear(hci_ufilter *f) noexcept
static void filter_set_ptype(int t, hci_ufilter *f) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.14 Command Complete event.
jau::nsize_t getReturnParamSize() const noexcept
const uint8_t * getReturnParam() const
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.15 Command Status event.
HCIStatusCode getStatus() const noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 5.4.1 HCI Command packet.
static std::unique_ptr< HCICommand > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
HCIOpcode getOpcode() const noexcept
static HCIEnv & get() noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 5.4.4 HCI Event packet.
static std::unique_ptr< HCIEvent > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
bool use_ext_adv() const noexcept
Use extended advertising if LE_Features::LE_Ext_Adv is set (Bluetooth 5.0).
bool use_ext_conn() const noexcept
Use extended connection if HCI_LE_Extended_Create_Connection is supported (Bluetooth 5....
bool use_resolv_clear() const noexcept
bool isOpen() const noexcept
Returns true if this mgmt instance is open, connected and hence valid, otherwise false.
std::shared_ptr< HCIConnection > HCIConnectionRef
HCIStatusCode le_clear_resolv_list() noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.40 LE Clear Resolving List command.
HCIStatusCode le_read_remote_features(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType) noexcept
Request supported LE_Features from remote device.
HCIStatusCode le_enable_adv(const bool enable) noexcept
Enables or disabled advertising.
HCIStatusCode le_enable_scan(const bool enable, const bool filter_dup=true) noexcept
Starts or stops LE scanning.
HCIStatusCode resetAdapter(const PostShutdownFunc &user_post_shutdown)
Complete adapter reset.
void clearAllCallbacks() noexcept
Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists and all SMPSecurityReqCallbacks.
bool addMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
MgmtEventCallback handling
HCIStatusCode le_read_resolv_list_size(uint32_t &size_res) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.41 LE Read Resolving List Size command.
void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept
Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list.
HCIStatusCode create_conn(const EUI48 &bdaddr, const uint16_t pkt_type=HCI_DM1|HCI_DM3|HCI_DM5|HCI_DH1|HCI_DH3|HCI_DH5, const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept
Establish a connection to the given BREDR (non LE).
HCIStatusCode le_set_phy(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, const LE_PHYs Tx, const LE_PHYs Rx) noexcept
Sets preference of used LE_PHYs for the given connection.
HCIStatusCode le_start_adv(const EInfoReport &eir, const EIRDataType adv_mask=EIRDataType::FLAGS|EIRDataType::SERVICE_UUID, const EIRDataType scanrsp_mask=EIRDataType::NAME|EIRDataType::CONN_IVAL, const EUI48 &peer_bdaddr=EUI48::ANY_DEVICE, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const HCILEOwnAddressType peer_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t adv_interval_min=160, const uint16_t adv_interval_max=480, const AD_PDU_Type adv_type=AD_PDU_Type::ADV_IND, const uint8_t adv_chan_map=0x07, const uint8_t filter_policy=0x00) noexcept
Starts advertising.
HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, LE_PHYs &resTx, LE_PHYs &resRx) noexcept
Request and return LE_PHYs bit for the given connection.
HCIStatusCode le_set_default_phy(const LE_PHYs Tx, const LE_PHYs Rx) noexcept
Sets default preference of used LE_PHYs for all subsequent LE connections.
HCIStatusCode le_start_scan(const bool filter_dup=true, const bool le_scan_active=true, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint8_t filter_policy=0x00) noexcept
Start LE scanning, i.e.
bool resetAllStates(const bool powered_on) noexcept
Reset all internal states, i.e.
size_type removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list.
void sendMgmtEvent(const MgmtEvent &event) noexcept
Manually send a MgmtEvent to all of its listeners.
HCIStatusCode le_add_to_resolv_list(const BDAddressAndType &peerIdentityAddressAndType, jau::uint128dp_t &peer_irk, jau::uint128dp_t &local_irk) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.38 LE Add Device To Resolving List command.
HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept
HCIStatusCode le_set_addr_resolv_enable(const bool enable) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.44 LE Set Address Resolution Enable command.
HCIStatusCode le_read_peer_resolv_addr(const BDAddressAndType &peerIdentityAddressAndType, jau::EUI48 &peerResolvableAddress) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.42 LE Read Peer Resolvable Address command.
void addSMPMsgCallback(const HCISMPMsgCallback &l)
std::string toString() const noexcept
HCIStatusCode le_del_from_resolv_list(const BDAddressAndType &peerIdentityAddressAndType) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.39 LE Remove Device From Resolving List command.
HCIStatusCode le_create_conn(const EUI48 &peer_bdaddr, const HCILEPeerAddressType peer_mac_type=HCILEPeerAddressType::PUBLIC, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint16_t conn_interval_min=8, const uint16_t conn_interval_max=12, const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept
Establish a connection to the given LE peer.
HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect an established connection.
HCIStatusCode le_read_local_resolv_addr(const BDAddressAndType &peerIdentityAddressAndType, jau::EUI48 &localResolvableAddress) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.43 LE Read Local Resolvable Address command.
HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept
size_type removeSMPMsgCallback(const HCISMPMsgCallback &l)
bool use_ext_scan() const noexcept
Use extended scanning if HCI_LE_Set_Extended_Scan_Parameters and HCI_LE_Set_Extended_Scan_Enable is s...
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.24 LE Enable Encryption command.
constexpr jau::uint128dp_t getLTK() const noexcept
Returns the 128-bit Long Term Key (16 octets)
constexpr uint16_t getEDIV() const noexcept
Returns the 16-bit EDIV value (2 octets) being distributed.
constexpr uint64_t getRand() const noexcept
Returns the 64-bit Rand value (8 octets) being distributed.
constexpr uint16_t getHandle() const noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.25 LE Long Term Key Request Reply command.
constexpr uint16_t getHandle() const noexcept
constexpr jau::uint128dp_t getLTK() const noexcept
Returns the 128-bit Long Term Key (16 octets)
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.26 LE Long Term Key Request Negative Reply command.
constexpr uint16_t getHandle() const noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.65.5 LE Long Term Key Request event.
constexpr uint64_t getRand() const noexcept
Returns the 64-bit Rand value (8 octets) being distributed.
constexpr uint16_t getHandle() const noexcept
constexpr uint16_t getEDIV() const noexcept
Returns the 16-bit EDIV value (2 octets) being distributed.
std::string toString() const noexcept
Generic HCIEvent wrapper for any HCI IOCTL 'command complete' alike event struct having a HCIStatusCo...
Generic HCICommand wrapper for any HCI IOCTL structure.
hcistruct * getWStruct() noexcept
uint16_t opcode, uint16_t dev-id, uint16_t param_size
static std::string getOpcodeString(const Opcode opc) noexcept
mgmt_addr_info { EUI48, uint8_t type }, int8_t rssi, uint32_t flags, uint16_t eir_len; uint8_t *eir
static std::unique_ptr< const SMPPDUMsg > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
Transient read only and endian aware octet data, i.e.
constexpr nsize_t size() const noexcept
Returns the used memory size for read and write operations, may be zero.
constexpr uint8_t const * get_ptr() const noexcept
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
constexpr_atomic void push_back(const value_type &x)
Like std::vector::push_back(), copy.
constexpr_atomic void clear() noexcept
Like std::vector::clear(), but ending with zero capacity.
bool(* equal_comparator)(const value_type &a, const value_type &b)
Generic value_type equal comparator to be user defined for e.g.
constexpr_atomic size_type size() const noexcept
Like std::vector::size().
constexpr_atomic bool push_back_unique(const value_type &x, equal_comparator comparator)
Like std::vector::push_back(), but only if the newly added element does not yet exist.
constexpr_atomic size_type erase_matching(const value_type &x, const bool all_matching, equal_comparator comparator)
Erase either the first matching element or all matching elements.
Implementation of a dynamic linear array storage, aka vector.
constexpr size_type size() const noexcept
Like std::vector::size().
Main jau environment class, supporting environment variable access and fetching elapsed time using it...
const bool verbose
Verbose info logging enabled or disabled.
static environment & get(const std::string &root_prefix_domain="jau") noexcept
Static singleton initialization of this project's environment with the given global root prefix_domai...
constexpr int_type to_ms() const noexcept
Convenient shortcut to to_num_of(1_ms)
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Service runner, a reusable dedicated thread performing custom user services.
bool stop() noexcept
Stops this service, if running.
bool shall_stop2(int dummy) noexcept
Helper function to easy FunctionDef usage w/o creating a lambda alike capture with same semantics as ...
bool join() noexcept
Blocks the current thread until service is stopped or returns immediately if not running or called fr...
static const uint8_t filter_policy
static const uint16_t le_scan_interval
static const uint16_t le_scan_window
static const bool filter_dup
static bool le_scan_active
static const uint16_t adv_interval_max
static const uint8_t adv_chan_map
static const uint16_t adv_interval_min
static const AD_PDU_Type adv_type
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define COND_PRINT(C,...)
Use for conditional plain messages, prefix '[elapsed_time] '.
#define WORDY_PRINT(...)
Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time...
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line fu...
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
#define ERR_PRINT2(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define DBG_WARN_PRINT(...)
Use for environment-variable environment::DEBUG conditional warning messages, prefix '[elapsed_time] ...
#define WARN_PRINT(...)
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: '.
constexpr UnaryFunction for_each_fidelity(InputIt first, InputIt last, UnaryFunction f)
Like jau::for_each(), see above.
constexpr uint16_t le_to_cpu(uint16_t const l) noexcept
constexpr void put_uint16(uint8_t *buffer, const uint16_t v) noexcept
Put the given uint16_t value into the given byte address using packed_t to resolve a potential memory...
constexpr void put_uint128(uint8_t *buffer, const uint128dp_t &v) noexcept
See put_uint16() for reference.
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
constexpr uint64_t get_uint64(uint8_t const *buffer) noexcept
See get_uint16() for reference.
@ little
Identifier for little endian, equivalent to endian::little.
std::string to_string(const alphabet &v) noexcept
#define __packed
packed: lead out macro, requires packed lead in as well.
HCIOpcode
BT Core Spec v5.2: Vol 4, Part E HCI: 7.1 Link Controller commands.
constexpr const bool CONSIDER_HCI_CMD_FOR_SMP_STATE
constexpr const jau::fraction_i64 THREAD_SHUTDOWN_TIMEOUT_MS
Maximum time in fractions of seconds to wait for a thread shutdown.
HCIEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7 Events.
HCIMetaEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.65 LE Meta event.
@ LE_SET_EXT_SCAN_RSP_DATA
@ LE_CREATE_CONN
LE_CREATE_CONN.
@ LE_READ_PEER_RESOLV_ADDR
FIXME: May not be supported by Linux/BlueZ.
@ LE_READ_LOCAL_RESOLV_ADDR
FIXME: May not be supported by Linux/BlueZ.
@ LE_SET_ADDR_RESOLV_ENABLE
@ LE_DEL_FROM_RESOLV_LIST
@ LE_READ_REMOTE_FEATURES
@ LE_READ_RESOLV_LIST_SIZE
@ ENCRYPT_KEY_REFRESH_COMPLETE
@ LE_EXT_CONN_COMPLETE
LE_ENHANCED_CONN_COMPLETE.
@ LE_CONN_COMPLETE
LE_CONN_COMPLETE.
@ LE_LTK_REQUEST
LE_LTK_REQUEST.
@ LE_ADVERTISING_REPORT
LE_ADVERTISING_REPORT.
@ LE_EXT_ADV_REPORT
LE_EXT_ADV_REPORT.
@ LE_REMOTE_FEAT_COMPLETE
LE_REMOTE_FEAT_COMPLETE.
@ LE_PHY_UPDATE_COMPLETE
LE_PHY_UPDATE_COMPLETE.
@ LE_SET_EXT_SCAN_RSP_DATA
@ LE_READ_REMOTE_FEATURES
BTMode
Bluetooth adapter operating mode.
void clear() noexcept
Clears internal list.
LE_Features
HCI Supported Commands.
constexpr ScanType changeScanType(const ScanType current, const ScanType changeType, const bool changeEnable) noexcept
std::string to_string(const DiscoveryPolicy v) noexcept
LE_PHYs
LE Transport PHY bit values.
HCILEPeerAddressType
HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01.
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
AD_PDU_Type
LE Advertising (AD) Protocol Data Unit (PDU) Types.
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
constexpr BDAddressType to_BDAddressType(const uint8_t v) noexcept
constexpr bool is_set(const LE_Features mask, const LE_Features bit) noexcept
constexpr uint8_t number(const DiscoveryPolicy rhs) noexcept
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
@ BDADDR_BREDR
Bluetooth BREDR address.
@ NONCONN_IND2
EAD_Event_Type with EAD_Event_Type::LEGACY_PDU: ADV_NONCONN_IND variant.
@ ADV_NONCONN_IND
Non connectable devices, advertising information to any listening device.
@ SCAN_IND2
EAD_Event_Type with EAD_Event_Type::LEGACY_PDU: ADV_SCAN_IND variant.
@ ADV_SCAN_IND
Similar to ADV_IND, w/o connection requests and with the option additional information via scan respo...
@ ADV_IND2
EAD_Event_Type with EAD_Event_Type::LEGACY_PDU: ADV_IND variant.
@ ADV_IND
Advertising Indications (ADV_IND), where a peripheral device requests connection to any central devic...
@ INVALID_HCI_COMMAND_PARAMETERS
@ CONNECTION_ALREADY_EXISTS
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
std::string bytesHexString(const void *data, const nsize_t offset, const nsize_t length, const bool lsbFirst, const bool lowerCase=true) noexcept
Produce a hexadecimal string representation of the given byte values.
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
constexpr const jau::fraction_i64 zero(0l, 1lu)
zero is 0/1
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
Representing ACL Datas' L2CAP Frame.
static std::string toString(const PBFlag v) noexcept
constexpr bool isGATT() const noexcept
const uint16_t handle
The connection handle.
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
CXX_ALWAYS_INLINE bool compare_exchange_strong(_Tp &__e, _Tp __i) noexcept
A 128-bit packed uint8_t data array.