32void BTGattCmd::ResponseCharListener::store(
const jau::TROOctets& char_value) {
34 if( rsp_data.remaining() < char_value.
size() ) {
35 rsp_data.recapacity( rsp_pos + char_value.
size() );
37 rsp_data.put_bytes_nc(rsp_pos, char_value.
get_ptr(), char_value.
size());
38 rsp_data.resize(rsp_pos + char_value.
size());
41void BTGattCmd::ResponseCharListener::notificationReceived(
BTGattCharRef charDecl,
43 std::unique_lock<std::mutex> lock(source.mtxRspReceived);
44 DBG_PRINT(
"BTGattCmd::notificationReceived: Resp %s, value[%s]",
45 charDecl->toString().c_str(), char_value.
toString().c_str());
47 if(
nullptr != source.dataCallback ) {
48 source.dataCallback(charDecl, char_value, timestamp);
51 source.cvRspReceived.notify_all();
55void BTGattCmd::ResponseCharListener::indicationReceived(
BTGattCharRef charDecl,
57 const bool confirmationSent)
59 std::unique_lock<std::mutex> lock(source.mtxRspReceived);
60 DBG_PRINT(
"BTGattCmd::indicationReceived: Resp %s, value[%s]",
61 charDecl->toString().c_str(), char_value.
toString().c_str());
63 if(
nullptr != source.dataCallback ) {
64 source.dataCallback(charDecl, char_value, timestamp);
67 source.cvRspReceived.notify_all();
70 (void)confirmationSent;
73bool BTGattCmd::isConnected() const noexcept {
return dev.
getConnected(); }
80 cmdCharRef =
nullptr != service_uuid ? dev.
findGattChar(*service_uuid, *cmd_uuid)
82 if(
nullptr == cmdCharRef ) {
85 srvUUIDStr().c_str(), cmd_uuid->
toString().c_str());
92 jau::INFO_PRINT(
"Command has no write property: %s", cmdCharRef->toString().c_str());
98 if(
nullptr != rsp_uuid ) {
99 rspCharRef =
nullptr != service_uuid ? dev.
findGattChar(*service_uuid, *rsp_uuid)
101 if(
nullptr == rspCharRef ) {
104 srvUUIDStr().c_str(), rsp_uuid->
toString().c_str());
106 cmdCharRef =
nullptr;
110 bool cccdEnableResult[2];
111 bool cccdRet = rspCharRef->addCharListener( rspCharListener, cccdEnableResult );
116 jau::INFO_PRINT(
"CCCD Notify/Indicate not supported on response %s", rspCharRef->toString().c_str());
118 cmdCharRef =
nullptr;
119 rspCharRef =
nullptr;
122 }
catch ( std::exception & e ) {
124 cmdCharRef =
nullptr;
125 rspCharRef =
nullptr;
134 std::unique_lock<std::mutex> lockCmd(mtxCommand);
135 const bool wasResolved = isResolvedEq();
137 cmdCharRef =
nullptr;
138 rspCharRef =
nullptr;
146 if( !isConnected() ) {
149 if(
nullptr != rspCharRefCopy ) {
151 const bool res1 = rspCharRefCopy->removeCharListener(rspCharListener);
152 const bool res2 = rspCharRefCopy->disableIndicationNotification();
158 }
catch ( std::exception & e ) {
168 std::unique_lock<std::mutex> lockCmd(mtxCommand);
172 return isResolvedEq();
177 return sendImpl(prefNoAck, cmd_data, timeout,
true);
180 return sendImpl(prefNoAck, cmd_data, 0_s,
false);
183 std::unique_lock<std::mutex> lockCmd(mtxCommand);
186 if( !isConnected() ) {
189 std::unique_lock<std::mutex> lockRsp(mtxRspReceived);
197 DBG_PRINT(
"BTGattCmd::sendBlocking: Start: Cmd %s, args[%s], Resp %s, result[%s]",
198 cmdCharRef->toString().c_str(), cmd_data.toString().c_str(),
199 rspCharStr().c_str(), rsp_data.toString().c_str());
204 const bool prefWriteNoAck = hasWriteNoAck && ( prefNoAck || !hasWriteWithAck );
206 if( prefWriteNoAck ) {
208 if( !cmdCharRef->writeValueNoResp(cmd_data) ) {
209 ERR_PRINT(
"Write (noAck) to command failed: Cmd %s, args[%s]",
210 cmdCharRef->toString().c_str(), cmd_data.toString().c_str());
213 }
catch ( std::exception & e ) {
214 ERR_PRINT(
"Exception caught @ Write (noAck) to command failed: Cmd %s, args[%s]: %s",
215 cmdCharRef->toString().c_str(), cmd_data.toString().c_str(), e.what());
218 }
else if( hasWriteWithAck ) {
220 if( !cmdCharRef->writeValue(cmd_data) ) {
221 ERR_PRINT(
"Write (withAck) to command failed: Cmd %s, args[%s]",
222 cmdCharRef->toString().c_str(), cmd_data.toString().c_str());
225 }
catch ( std::exception & e ) {
226 ERR_PRINT(
"Exception caught @ Write (withAck) to command failed: Cmd %s, args[%s]: %s",
227 cmdCharRef->toString().c_str(), cmd_data.toString().c_str(), e.what());
231 ERR_PRINT(
"Command has no write property: %s: %s", cmdCharRef->toString().c_str(), toString().c_str());
235 if(
nullptr != rspCharRef && allowResponse ) {
238 ( rspMinSize > rsp_data.size() || ( 0 == rspMinSize && 0 == rsp_data.size() ) )
242 cvRspReceived.wait(lockRsp);
244 std::cv_status s =
wait_until(cvRspReceived, lockRsp, timeout_time);
245 if( std::cv_status::timeout == s && 0 == rsp_data.size() ) {
246 ERR_PRINT(
"BTGattCmd::sendBlocking: Timeout: Cmd %s, args[%s]",
247 cmdCharRef->toString().c_str(), cmd_data.toString().c_str());
255 DBG_PRINT(
"BTGattCmd::sendBlocking: OK: Cmd %s, args[%s], Resp %s, result[%s]",
256 cmdCharRef->toString().c_str(), cmd_data.toString().c_str(),
257 rspCharStr().c_str(), rsp_data.toString().c_str());
263 return "BTGattCmd["+dev.
getName()+
":"+name+
", service "+srvUUIDStr()+
264 ", char[cmd "+cmd_uuid->
toString()+
", rsp "+rspUUIDStr()+
std::string const getName() const noexcept
Returns the remote device name.
BTGattCharRef findGattChar(const jau::uuid_t &service_uuid, const jau::uuid_t &char_uuid) noexcept
Find a BTGattChar by its service_uuid and char_uuid.
bool getConnected() noexcept
Return true if the device has been successfully connected, otherwise false.
HCIStatusCode close() noexcept
Close this command instance, usually called at destruction.
HCIStatusCode send(const bool prefNoAck, const jau::TROOctets &cmd_data, const jau::fraction_i64 &timeout) noexcept
Send the command to the remote BTDevice.
HCIStatusCode sendOnly(const bool prefNoAck, const jau::TROOctets &cmd_data) noexcept
Send the command to the remote BTDevice, only.
bool isResolved() noexcept
Query whether all UUIDs of this commands have been resolved.
std::string toString() const noexcept
Transient read only and endian aware octet data, i.e.
std::string toString() const noexcept
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
virtual std::string toString() const noexcept=0
Returns the string representation in BE network order, i.e.
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
std::string to_string(const alphabet &v) noexcept
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
std::shared_ptr< BTGattChar > BTGattCharRef
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
constexpr const jau::fraction_i64 zero(0l, 1lu)
zero is 0/1
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
std::cv_status wait_until(std::condition_variable &cv, std::unique_lock< std::mutex > &lock, const fraction_timespec &absolute_time, const bool monotonic=true) noexcept
wait_until causes the current thread to block until the condition variable is notified,...
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...