Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
ATTPDUTypes.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 ATT_PDU_TYPES_HPP_
27#define ATT_PDU_TYPES_HPP_
28
29#include <cstring>
30#include <exception>
31#include <string>
32#include <memory>
33#include <cstdint>
34#include <vector>
35
36#include <mutex>
37#include <atomic>
38
39#include <jau/basic_types.hpp>
40#include <jau/octets.hpp>
41#include <jau/uuid.hpp>
42
43#include "BTTypes0.hpp"
44
45
46/**
47 * - - - - - - - - - - - - - - -
48 * # Direct-BT Overview
49 *
50 * Direct-BT provides direct Bluetooth LE and BREDR programming,
51 * offering robust high-performance support for embedded & desktop with zero overhead via C++ and Java.
52 *
53 * Direct-BT follows the official [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/)
54 * and its C++ implementation contains detailed references.
55 *
56 * Direct-BT supports a fully event driven workflow from adapter management via device discovery to GATT programming,
57 * using its platform agnostic HCI, GATT, SMP and L2CAP client-side protocol implementation.
58 *
59 * - - - - - - - - - - - - - - -
60 *
61 * ## Direct-BT Layers
62 *
63 * - BTManager for adapter configuration and adapter add/removal notifications (ChangedAdapterSetFunc())
64 * - Using *BlueZ Kernel Manager Control Channel* via MgmtMsg communication.
65 * - *HCI Handling* via HCIHandler using HCIPacket implementing connect/disconnect w/ tracking, device discovery, etc
66 * - *ATT PDU* AttPDUMsg via L2CAP for low level packet communication
67 * - *GATT Support* via BTGattHandler using AttPDUMsg over L2CAPComm, ...
68 * - Central-Client Functionality, i.e. ::GATTRole::Client or BTAdapter in ::BTRole::Master:
69 * - BTGattService
70 * - BTGattChar
71 * - BTGattDesc
72 * - Peripheral-Server Functionality, i.e. ::GATTRole::Server or BTAdapter in ::BTRole::Slave:
73 * - DBGattServer
74 * - DBGattService
75 * - DBGattChar
76 * - DBGattDesc
77 * - *SMP PDU* SMPPDUMsg via L2CAP for Security Manager Protocol (SMP) communication
78 * - *SMP Support* via SMPHandler using SMPPDUMsg over L2CAPComm, providing (Not yet supported by Linux/BlueZ)
79 * - LE Secure Connections
80 * - LE legacy pairing
81 * - On Linux/BlueZ, LE Secure Connections and LE legacy pairing is supported using
82 * - ::BTSecurityLevel setting via BTDevice / L2CAPComm per connection and
83 * - ::SMPIOCapability via BTManager (per adapter) and BTDevice (per connection)
84 * - SMPPDUMsg SMP event tracking over HCI/ACL/L2CAP, observing operations
85 *
86 * BTManager utilizes the *BlueZ Kernel Manager Control Channel*
87 * for adapter configuration and adapter add/removal notifications (ChangedAdapterSetFunc()).
88 *
89 * To support other platforms than Linux/BlueZ, we will have to
90 * - Move specified HCI host features used in BTManager to HCIHandler, SMPHandler,.. - and -
91 * - Add specialization for each new platform using their non-platform-agnostic features.
92 *
93 * - - - - - - - - - - - - - - -
94 *
95 * ## Direct-BT User Hierarchy
96 *
97 * From a user central-client perspective the following hierarchy is provided,
98 * i.e. ::GATTRole::Client or BTAdapter in ::BTRole::Master:
99 * - BTManager has zero or more
100 * - BTAdapter has zero or more
101 * - BTDevice has zero or more
102 * - BTGattService has zero or more
103 * - BTGattChar has zero or more
104 * - BTGattDesc
105 *
106 * From a user peripheral-server perspective the following hierarchy is provided,
107 * i.e. ::GATTRole::Server or BTAdapter in ::BTRole::Slave:
108 * - BTManager has zero or more
109 * - BTAdapter has zero or one
110 * - DBGattServer has zero or more
111 * - DBGattService has zero or more
112 * - DBGattChar has zero or more
113 * - DBGattDesc
114 *
115 * - - - - - - - - - - - - - - -
116 *
117 * ## Direct-BT Object Lifecycle
118 *
119 * Object lifecycle with all instances and marked weak back-references to their owner
120 * - BTManager singleton instance for all
121 * - BTAdapter ownership by DBTManager
122 * - BTDevice ownership by DBTAdapter
123 * - BTGattHandler ownership by BTDevice, with weak BTDevice back-reference
124 * - BTGattService ownership by BTGattHandler, with weak BTGattHandler back-reference
125 * - BTGattChar ownership by BTGattService, with weak BTGattService back-reference
126 * - BTGattDesc ownership by BTGattChar, with weak BTGattChar back-reference
127 *
128 * User application instantiates for peripheral-server functionality:
129 * - DBGattServer ownership by user
130 * - DBGattService ownership by user
131 * - DBGattChar ownership by user
132 * - DBGattDesc
133 *
134 * - - - - - - - - - - - - - - -
135 *
136 * ## Direct-BT Mapped Names C++ vs Java
137 *
138 * Mapped names from C++ implementation to Java implementation and to Java interface:
139 *
140 * C++ <br> `direct_bt` | Java Implementation <br> `jau.direct_bt` | Java Interface <br> `org.direct_bt` |
141 * :-----------------------| :-----------------| :------------------------------------|
142 * BTManager | DBTManager | BTManager |
143 * BTAdapter | DBTAdapter | BTAdapter |
144 * BTDevice | DBTDevice | BTDevice |
145 * BTGattService | DBTGattService | BTGattService |
146 * BTGattChar | DBTGattChar | BTGattChar |
147 * BTGattDesc | DBTGattDesc | BTGattDesc |
148 * DBGattService | | DBGattService |
149 * DBGattChar | | DBGattChar |
150 * DBGattDesc | | DBGattDesc |
151 * AdapterStatusListener | | AdapterStatusListener |
152 * BTGattCharListener | | BTGattCharListener |
153 * ChangedAdapterSetFunc() | | BTManager::ChangedAdapterSetListener |
154 *
155 * - - - - - - - - - - - - - - -
156 *
157 * ## Direct-BT Event Driven Workflow
158 *
159 * A fully event driven workflow from adapter management via device discovery to GATT programming is supported.
160 *
161 * ChangedAdapterSetFunc() allows listening to added and removed BTAdapter via BTManager.
162 *
163 * AdapterStatusListener allows listening to BTAdapter changes and BTDevice discovery.
164 *
165 * BTGattCharListener allows listening to GATT indications and notifications.
166 *
167 * Main event listener can be attached to these objects
168 * which maintain a set of unique listener instances without duplicates.
169 *
170 * - BTManager
171 * - ChangedAdapterSetFunc()
172 *
173 * - BTAdapter
174 * - AdapterStatusListener
175 *
176 * - BTGattChar or BTGattHandler
177 * - BTGattCharListener
178 *
179 * Other API attachment method exists for BTGattCharListener,
180 * however, they only exists for convenience and end up to be attached to BTGattHandler.
181 *
182 *
183 * - - - - - - - - - - - - - - -
184 *
185 * BT Core Spec v5.2: Vol 3, Part A L2CAP Spec: 7.9 PRIORITIZING DATA OVER HCI
186 *
187 * > In order for guaranteed channels to meet their guarantees,
188 * > L2CAP should prioritize traffic over the HCI transport in devices that support HCI.
189 * > Packets for Guaranteed channels should receive higher priority than packets for Best Effort channels.
190 *
191 * - - - - - - - - - - - - - - -
192 *
193 * ATTPDUTypes.hpp Module for ATTPDUMsg Types:
194 *
195 * - BT Core Spec v5.2: Vol 3, Part F Attribute Protocol (ATT)
196 */
197namespace direct_bt {
198
199 /** @defgroup DBTSystemAPI Direct-BT System Level API
200 * System level Direct-BT API types and functionality, [see Direct-BT Overview](namespacedirect__bt.html#details).
201 *
202 * @{
203 */
204
206 protected:
207 AttException(std::string type, std::string const& m, const char* file, int line) noexcept
208 : RuntimeException(std::move(type), m, file, line) {}
209
210 public:
211 AttException(std::string const& m, const char* file, int line) noexcept
212 : RuntimeException("AttException", m, file, line) {}
213 };
214
216 public:
217 AttOpcodeException(std::string const& m, const char* file, int line) noexcept
218 : AttException("AttOpcodeException", m, file, line) {}
219 };
220
222 public:
223 AttValueException(std::string const& m, const char* file, int line) noexcept
224 : AttException("AttValueException", m, file, line) {}
225 };
226
227 /**
228 * Handles the Attribute Protocol (ATT) using Protocol Data Unit (PDU)
229 * encoded messages over L2CAP channel.
230 * <p>
231 * Implementation uses persistent memory w/ ownership
232 * copying PDU data to allow intermediate pipe processing.
233 * </p>
234 * <p>
235 *
236 * Vol 3, Part F 2 - Protocol Overview pp
237 * ---------------------------------------
238 * One attribute := { UUID type; uint16_t handle; permissions for higher layer; },
239 * where
240 *
241 * UUID is an official assigned number,
242 *
243 * handle uniquely references an attribute on a server for client R/W access,
244 * see Vol 3, Part F 3.4.4 - 3.4.6, also 3.4.7 (notified/indicated),
245 * 3.4.3 (discovery) and 3.2.5 (permissions).
246 *
247 * Client sends ATT requests to a server, which shall respond to all.
248 *
249 * A device can take client and server roles concurrently.
250 *
251 * One server per device, ATT handle is unique for all supported bearers.
252 * For each client, server has one set of ATTs.
253 * The server (and hence device) can support multiple clients.
254 *
255 * Services are distinguished by range of handles for each service.
256 * Discovery is of these handle ranges is defined by a higher layer spec.
257 *
258 * ATT Protocol has notification and indication capabilities for efficient
259 * ATT value promotion to client w/o reading them (Vol 3, Part F 3.3).
260 *
261 * All ATT Protocol requests sent over an ATT bearer.
262 * Multiple ATT bearers can be established between two devices.
263 * Each ATT bearer uses a separate L2CAP channel an can have different configurations.
264 *
265 * For LE a single ATT bearer using a fixed L2CAP channel is available ASAP after
266 * ACL connection is established.
267 * Additional ATT bearers can be established using L2CAP (Vol 3, Part F 3.2.11).
268 * </p>
269 *
270 * <p>
271 * Vol 3, Part F 3 - Basics and Types
272 * ------------------------------------
273 * ATT handle is uint16_t and valid if > 0x0000, max is 0xffff.
274 * ATT handle is unique per server.
275 *
276 * ATT value (Vol 3, Part F 3.2.4)
277 *
278 * - ATT value is uint8_t array of fixed or variable length.
279 *
280 * - ATT values might be too large for a single PDU,
281 * hence it must be sent using multiple PDUs.
282 *
283 * - ATT value encoding is defined by the ATT type (UUID).
284 *
285 * - ATT value transmission done via request, response,
286 * notification or indication
287 *
288 * - ATT value variable length is implicit by PDU carrying packet (PDU parent),
289 * implying:
290 * - One ATT value per ATT request... unless ATT values have fixed length.
291 * - Only one ATT value with variable length in a request...
292 * - L2CAP preserves DGRAM boundaries
293 *
294 * Some PDUs include the ATT value length, for which above limitations don't apply.
295 *
296 * Maximum length of an attribute value shall be 512 bytes (Vol 3, Part F 3.2.8),
297 * spread across multiple PDUs.
298 * </p>
299 *
300 * - BT Core Spec v5.2: Vol 3, Part A: BT Logical Link Control and Adaption Protocol (L2CAP)
301 *
302 * - BT Core Spec v5.2: Vol 3, Part F Attribute Protocol (ATT)
303 *
304 * - BT Core Spec v5.2: Vol 3, Part F 3 ATT PDUs (Protocol Data Unit)
305 *
306 * - BT Core Spec v5.2: Vol 3, Part F 3.3 ATT PDUs
307 *
308 * - BT Core Spec v5.2: Vol 3, Part F 4 Security Considerations
309 *
310 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
311 *
312 * AttPDUMsg Base Class
313 * =====================
314 * Attribute Protocol (ATT)'s Protocol Data Unit (PDU) message
315 * Vol 3, Part F 3.3 and Vol 3, Part F 3.4
316 *
317 * Little endian, however, ATT value endianess is defined by above layer.
318 *
319 * ATT_MTU Specification
320 * - BT Core Spec v5.2: Vol 3, Part F ATT: 3.2.8 Exchanging MTU size
321 * - BT Core Spec v5.2: Vol 3, Part F ATT: 3.2.9 Long attribute values
322 * - BT Core Spec v5.2: Vol 3, Part G GATT: 5.2.1 ATT_MTU
323 *
324 * resulting in a ATT_MTU range of
325 *
326 * - ATT_MTU minimum is 23 bytes (Vol 3, Part G: 5.2.1)
327 * - ATT_MTU is negotiated, maximum is 512 bytes (Vol 3, Part F: 3.2.8-9)
328 * - ATT Value sent: [1 .. ATT_MTU-1] (Vol 3, Part F: 3.2.8-9)
329 *
330 *
331 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.3.1 Attribute PDU Format
332 * -----------------------------------------------------------------
333 * ```
334 * { uint8_t opcode, uint8_t param[0..ATT_MTU-X], uint8_t auth_sig[0||12] }
335 * ```
336 * with
337 * ```
338 * opcode bits{ 0-5 method, 6 command-flag, 7 auth-sig-flag }
339 * ```
340 * and
341 * ```
342 * X = 1 if auth-sig flag of ATT-opcode is 0, or
343 * X = 13 if auth-sig flag of ATT-opcode is 1.
344 * ```
345 * </p>
346 */
348 {
349 public:
350 /** ATT Opcode Summary Vol 3, Part F 3.4.8 */
351 enum class Opcode : uint8_t {
352 PDU_UNDEFINED = 0x00, // our own pseudo opcode, indicating no ATT PDU message
353
354 METHOD_MASK = 0x3F, // bits 0 .. 5
355 COMMAND_FLAG = 0x40, // bit 6 (counting from 0)
356 AUTH_SIGNATURE_FLAG = 0x80, // bit 7 (counting from 0)
357
358 ERROR_RSP = 0x01,
359 EXCHANGE_MTU_REQ = 0x02,
360 EXCHANGE_MTU_RSP = 0x03,
361 FIND_INFORMATION_REQ = 0x04,
362 FIND_INFORMATION_RSP = 0x05,
363 FIND_BY_TYPE_VALUE_REQ = 0x06,
364 FIND_BY_TYPE_VALUE_RSP = 0x07,
365 READ_BY_TYPE_REQ = 0x08,
366 READ_BY_TYPE_RSP = 0x09,
367 READ_REQ = 0x0A,
368 READ_RSP = 0x0B,
369 READ_BLOB_REQ = 0x0C,
370 READ_BLOB_RSP = 0x0D,
371 READ_MULTIPLE_REQ = 0x0E,
372 READ_MULTIPLE_RSP = 0x0F,
373 READ_BY_GROUP_TYPE_REQ = 0x10,
374 READ_BY_GROUP_TYPE_RSP = 0x11,
375 WRITE_REQ = 0x12,
376 WRITE_RSP = 0x13,
377 WRITE_CMD = WRITE_REQ + COMMAND_FLAG, // = 0x52
378 PREPARE_WRITE_REQ = 0x16,
379 PREPARE_WRITE_RSP = 0x17,
380 EXECUTE_WRITE_REQ = 0x18,
381 EXECUTE_WRITE_RSP = 0x19,
382
383 READ_MULTIPLE_VARIABLE_REQ = 0x20,
384 READ_MULTIPLE_VARIABLE_RSP = 0x21,
385
386 MULTIPLE_HANDLE_VALUE_NTF = 0x23,
387
388 HANDLE_VALUE_NTF = 0x1B,
389 HANDLE_VALUE_IND = 0x1D,
390 HANDLE_VALUE_CFM = 0x1E,
391
392 SIGNED_WRITE_CMD = WRITE_REQ + COMMAND_FLAG + AUTH_SIGNATURE_FLAG // = 0xD2
393 };
394 static constexpr uint8_t number(const Opcode rhs) noexcept {
395 return static_cast<uint8_t>(rhs);
396 }
397 static std::string getOpcodeString(const Opcode opc) noexcept;
398
399 enum class ReqRespType : bool {
400 REQUEST = true,
401 RESPONSE = false
402 };
403 static constexpr bool is_request(const ReqRespType rhs) noexcept {
404 return static_cast<bool>(rhs);
405 }
406
407 enum class OpcodeType : uint8_t {
408 UNDEFINED = 0,
409 REQUEST = 1,
410 RESPONSE = 2,
411 NOTIFICATION = 3,
412 INDICATION = 4
413 };
414
415 static constexpr OpcodeType get_type(const Opcode rhs) noexcept {
416 switch(rhs) {
418 [[fallthrough]];
421
424
426 [[fallthrough]];
428 [[fallthrough]];
430 [[fallthrough]];
432 [[fallthrough]];
434 [[fallthrough]];
435 case Opcode::READ_RSP:
436 [[fallthrough]];
438 [[fallthrough]];
440 [[fallthrough]];
442 [[fallthrough]];
444 [[fallthrough]];
446 [[fallthrough]];
448 [[fallthrough]];
450 [[fallthrough]];
451 case Opcode::HANDLE_VALUE_CFM: // A response from master/gatt-client to slave/gatt-server
453
455 [[fallthrough]];
457 [[fallthrough]];
459 [[fallthrough]];
461 [[fallthrough]];
462 case Opcode::READ_REQ:
463 [[fallthrough]];
465 [[fallthrough]];
467 [[fallthrough]];
469 [[fallthrough]];
471 [[fallthrough]];
473 [[fallthrough]];
475 [[fallthrough]];
477 [[fallthrough]];
479 [[fallthrough]];
481 return OpcodeType::REQUEST;
482
483 default:
485 }
486 }
487
488 private:
489 static constexpr Opcode bit_and(const Opcode lhs, const Opcode rhs) noexcept {
490 return static_cast<Opcode> ( static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs) );
491 }
492 static constexpr bool bit_test(const Opcode lhs, const Opcode rhs) noexcept {
493 return 0 != ( static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs) );
494 }
495
496 protected:
497 void check_range() {
499 }
500
501 void checkOpcode(const Opcode expected) const
502 {
503 const Opcode has = getOpcode();
504 if( expected != has ) {
505 throw AttOpcodeException("Has opcode "+jau::to_hexstring(number(has))+" "+getOpcodeString(has)+
506 ", but expected "+jau::to_hexstring(number(expected))+" "+getOpcodeString(expected), E_FILE_LINE);
507 }
508 }
509 void checkOpcode(const Opcode exp1, const Opcode exp2) const
510 {
511 const Opcode has = getOpcode();
512 if( exp1 != has && exp2 != has ) {
513 throw AttOpcodeException("Has opcode "+jau::to_hexstring(number(has))+" "+getOpcodeString(has)+
514 ", but expected either "+jau::to_hexstring(number(exp1))+" "+getOpcodeString(exp1)+
515 " or "+jau::to_hexstring(number(exp1))+" "+getOpcodeString(exp1), E_FILE_LINE);
516 }
517 }
518
519 virtual std::string baseString() const noexcept {
520 return "opcode="+jau::to_hexstring(number(getOpcode()))+" "+getOpcodeString(getOpcode())+
521 ", size[total="+std::to_string(pdu.size())+", param "+std::to_string(getPDUParamSize())+"]";
522 }
523 virtual std::string valueString() const noexcept {
524 return "size "+std::to_string(getPDUValueSize())+", data "
525 +jau::bytesHexString(pdu.get_ptr(), getPDUValueOffset(), getPDUValueSize(), true /* lsbFirst */);
526 }
527
528 public:
529 /** actual received PDU */
531
532 /** creation timestamp in milliseconds */
533 const uint64_t ts_creation;
534
535 /**
536 * Return a newly created specialized instance pointer to base class.
537 * <p>
538 * Returned memory reference is managed by caller (delete etc)
539 * </p>
540 */
541 static std::unique_ptr<const AttPDUMsg> getSpecialized(const uint8_t * buffer, jau::nsize_t const buffer_size) noexcept;
542
543 /** Persistent memory, w/ ownership ..*/
544 AttPDUMsg(const uint8_t* source, const jau::nsize_t size)
545 : pdu(source, std::max<jau::nsize_t>(1, size), jau::lb_endian_t::little),
547 { }
548
549 /** Persistent memory, w/ ownership ..*/
550 AttPDUMsg(const Opcode opc, const jau::nsize_t size)
551 : pdu(std::max<jau::nsize_t>(1, size), jau::lb_endian_t::little),
553 {
554 pdu.put_uint8_nc(0, number(opc));
555 }
556
557 AttPDUMsg(const AttPDUMsg &o) = default; // POctets copy-ctor may throw
558 AttPDUMsg(AttPDUMsg &&o) noexcept = default;
559 AttPDUMsg& operator=(const AttPDUMsg &o) noexcept = delete; // const ts_creation
560 AttPDUMsg& operator=(AttPDUMsg &&o) noexcept = delete; // const ts_creation
561
562 virtual ~AttPDUMsg() noexcept = default;
563
564 /** ATT PDU Format Vol 3, Part F 3.3.1 */
565 constexpr Opcode getOpcode() const noexcept { return static_cast<Opcode>(pdu.get_uint8_nc(0)); }
566
567 /** ATT PDU Format Vol 3, Part F 3.3.1 */
568 constexpr Opcode getOpMethod() const noexcept { return bit_and(getOpcode(), Opcode::METHOD_MASK); }
569
570 /** ATT PDU Format Vol 3, Part F 3.3.1 */
571 constexpr bool getOpCommandFlag() const noexcept { return bit_test(getOpcode(), Opcode::COMMAND_FLAG); }
572
573 /** ATT PDU Format Vol 3, Part F 3.3.1 */
574 constexpr bool getOpAuthSigFlag() const noexcept { return bit_test(getOpcode(), Opcode::AUTH_SIGNATURE_FLAG); }
575
576 /**
577 * ATT PDU Format Vol 3, Part F 3.3.1
578 * <p>
579 * The ATT Authentication Signature size in octets.
580 * </p>
581 * <p>
582 * This auth-signature comes at the very last of the PDU.
583 * </p>
584 */
585 constexpr jau::nsize_t getAuthSigSize() const noexcept { return getOpAuthSigFlag() ? 12 : 0; }
586
587 /**
588 * ATT PDU Format Vol 3, Part F 3.3.1
589 * <p>
590 * The ATT PDU parameter size in octets
591 * less opcode (1 byte) and auth-signature (0 or 12 bytes).
592 * </p>
593 * <pre>
594 * param-size := pdu.size - getAuthSigSize() - 1
595 * </pre>
596 * <p>
597 * Note that the PDU parameter include the PDU value below.
598 * </p>
599 * <p>
600 * Note that the optional auth-signature is at the end of the PDU.
601 * </p>
602 */
603 constexpr jau::nsize_t getPDUParamSize() const noexcept {
604 return pdu.size() - getAuthSigSize() - 1 /* opcode */;
605 }
606
607 /**
608 * Returns the octet offset to the value segment in this PDU
609 * including the mandatory opcode,
610 * i.e. the number of octets until the first value octet.
611 * <p>
612 * Note that the ATT PDU value is part of the PDU param,
613 * where it is the last segment.
614 * </p>
615 * <p>
616 * The value offset is ATT PDU specific and may point
617 * to the variable user data post handle etc within the PDU Param block.
618 * </p>
619 * <p>
620 * Note that the opcode must be included in the implementation,
621 * as it may be used to reference the value in the pdu
622 * conveniently.
623 * </p>
624 */
625 constexpr_cxx20 virtual jau::nsize_t getPDUValueOffset() const noexcept { return 1; /* default: opcode */ }
626
627 /**
628 * Returns this PDU's minimum size, i.e.
629 * <pre>
630 * opcode + param - value + auth_signature
631 * </pre>
632 * Value is excluded as it might be flexible.
633 */
636 }
637
638 /**
639 * Returns the net octet size of this PDU's attributes value,
640 * i.e.
641 * - `pdu.size - getAuthSigSize() - value-offset` or
642 * - `getPDUParamSize() - getPDUValueOffset() + 1`
643 * <p>
644 * Note that the opcode size of 1 octet is re-added as included in getPDUValueOffset()
645 * for convenience but already taken-off in getPDUParamSize() for spec compliance!
646 * </p>
647 * <pre>
648 * value-size := param-size - value-offset + 1
649 * param-size := pdu.size - getAuthSigSize() - 1
650 *
651 * value-size := pdu.size - getAuthSigSize() - 1 - value-offset + 1
652 * value-size := pdu.size - getAuthSigSize() - value-offset
653 * </pre>
654 */
656
657 /**
658 * Returns the theoretical maximum value size of a PDU's attribute value.
659 * <pre>
660 * ATT_MTU - getAuthSigSize() - value-offset
661 * </pre>
662 */
664 return mtu - getAuthSigSize() - getPDUValueOffset();
665 }
666
667 virtual std::string getName() const noexcept {
668 return "AttPDUMsg";
669 }
670
671 virtual std::string toString() const noexcept{
672 return getName()+"["+baseString()+", value["+valueString()+"]]";
673 }
674 };
675
676 /**
677 * Our own pseudo opcode, indicating no ATT PDU message.
678 * <p>
679 * ATT_PDU_UNDEFINED
680 * </p>
681 */
682 class AttPDUUndefined final : public AttPDUMsg
683 {
684 public:
685 AttPDUUndefined(const uint8_t* source, const jau::nsize_t length) : AttPDUMsg(source, length) {
686 check_range();
688 }
689
690 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1; }
691
692 std::string getName() const noexcept override {
693 return "AttPDUUndefined";
694 }
695 };
696
697 /**
698 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.1.1 ATT_ERROR_RSP
699 *
700 * Used to send a error reply for any request.
701 */
702 class AttErrorRsp final : public AttPDUMsg
703 {
704 public:
705 enum class ErrorCode : uint8_t {
706 /** Direct-BT's extension to indicate no error */
707 NO_ERROR = 0x00,
708 INVALID_HANDLE = 0x01,
709 NO_READ_PERM = 0x02,
710 NO_WRITE_PERM = 0x03,
711 INVALID_PDU = 0x04,
712 INSUFF_AUTHENTICATION = 0x05,
713 UNSUPPORTED_REQUEST = 0x06,
714 INVALID_OFFSET = 0x07,
715 INSUFF_AUTHORIZATION = 0x08,
716 PREPARE_QUEUE_FULL = 0x09,
717 ATTRIBUTE_NOT_FOUND = 0x0A,
718 ATTRIBUTE_NOT_LONG = 0x0B,
719 INSUFF_ENCRYPTION_KEY_SIZE = 0x0C,
720 INVALID_ATTRIBUTE_VALUE_LEN = 0x0D,
721 UNLIKELY_ERROR = 0x0E,
722 INSUFF_ENCRYPTION = 0x0F,
723 UNSUPPORTED_GROUP_TYPE = 0x10,
724 INSUFFICIENT_RESOURCES = 0x11,
725 DB_OUT_OF_SYNC = 0x12,
726 FORBIDDEN_VALUE = 0x13
727 };
728 static constexpr uint8_t number(const ErrorCode rhs) noexcept {
729 return static_cast<uint8_t>(rhs);
730 }
731 static std::string getErrorCodeString(const ErrorCode errorCode) noexcept;
732
733 AttErrorRsp(const uint8_t* source, const jau::nsize_t length) : AttPDUMsg(source, length) {
734 check_range();
736 }
737
738 AttErrorRsp(const ErrorCode error_code, const Opcode cause_opc, const uint16_t cause_handle)
739 : AttPDUMsg(Opcode::ERROR_RSP, 1+1+2+1)
740 {
741 pdu.put_uint8(1, AttPDUMsg::number(cause_opc));
742 pdu.put_uint16(2, cause_handle);
743 pdu.put_uint8(4, number(error_code));
744 check_range();
745 }
746
747 /** opcode + reqOpcodeCause + handleCause + errorCode */
748 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 1 + 2 + 1; }
749
750 constexpr Opcode getCausingOpcode() const noexcept { return static_cast<Opcode>( pdu.get_uint8_nc(1) ); }
751
752 constexpr uint16_t getCausingHandle() const noexcept { return pdu.get_uint16_nc(2); }
753
754 constexpr ErrorCode getErrorCode() const noexcept { return static_cast<ErrorCode>(pdu.get_uint8_nc(4)); }
755
756 std::string getName() const noexcept override {
757 return "AttErrorRsp";
758 }
759
760 protected:
761 std::string valueString() const noexcept override {
762 const Opcode opc = getCausingOpcode();
763 const ErrorCode ec = getErrorCode();
764 return "error "+jau::to_hexstring(number(ec)) + ": " + getErrorCodeString(ec)+
765 ", cause(opc "+jau::to_hexstring(AttPDUMsg::number(opc))+": "+getOpcodeString(opc)+
766 ", handle "+jau::to_hexstring(getCausingHandle())+")";
767 }
768 };
769
770 /**
771 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.2.1 ATT_EXCHANGE_MTU_REQ
772 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.2.2 ATT_EXCHANGE_MTU_RSP
773 *
774 * Used for
775 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.3.1 Exchange MTU (Server configuration)
776 */
777 class AttExchangeMTU final : public AttPDUMsg
778 {
779 public:
780 AttExchangeMTU(const uint8_t* source, const jau::nsize_t length)
781 : AttPDUMsg(source, length)
782 {
783 check_range();
785 }
786
787 AttExchangeMTU(const ReqRespType type, const uint16_t mtuSize)
788 : AttPDUMsg(is_request(type) ? Opcode::EXCHANGE_MTU_REQ : Opcode::EXCHANGE_MTU_RSP, 1+2)
789 {
790 pdu.put_uint16(1, mtuSize);
791 check_range();
792 }
793
794 /** opcode + mtu-size */
795 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1+2; }
796
797 constexpr uint16_t getMTUSize() const noexcept { return pdu.get_uint16_nc(1); }
798
799 std::string getName() const noexcept override {
800 return "AttExchangeMTU";
801 }
802
803 protected:
804 std::string valueString() const noexcept override {
805 return "mtu "+std::to_string(getMTUSize());
806 }
807 };
808
809 /**
810 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.3 ATT_READ_REQ
811 *
812 * Used for
813 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.1 Read Characteristic Value
814 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.1 Read Characteristic Descriptors
815 */
816 class AttReadReq final : public AttPDUMsg
817 {
818 public:
819 AttReadReq(const uint8_t* source, const jau::nsize_t length)
820 : AttPDUMsg(source, length)
821 {
822 check_range();
824 }
825
826 AttReadReq(const uint16_t handle)
827 : AttPDUMsg(Opcode::READ_REQ, getPDUValueOffset())
828 {
829 pdu.put_uint16(1, handle);
830 check_range();
831 }
832
833 /** opcode + handle */
834 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1+2; }
835
836 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
837
838 std::string getName() const noexcept override {
839 return "AttReadReq";
840 }
841
842 protected:
843 std::string valueString() const noexcept override {
844 return "handle "+jau::to_hexstring(getHandle());
845 }
846 };
847
848 /**
849 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.5 ATT_BLOB_READ_REQ
850 *
851 * Used for
852 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.3 Read Long Characteristic Value
853 * - For any follow up request, which previous request reply couldn't fit in ATT_MTU
854 */
855 class AttReadBlobReq final : public AttPDUMsg
856 {
857 public:
858 AttReadBlobReq(const uint8_t* source, const jau::nsize_t length)
859 : AttPDUMsg(source, length)
860 {
861 check_range();
863 }
864
865 AttReadBlobReq(const uint16_t handle, const uint16_t value_offset)
866 : AttPDUMsg(Opcode::READ_BLOB_REQ, getPDUValueOffset())
867 {
868 pdu.put_uint16(1, handle);
869 pdu.put_uint16(3, value_offset);
870 check_range();
871 }
872
873 /** opcode + handle + value_offset */
874 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 2 + 2; }
875
876 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
877
878 constexpr uint16_t getValueOffset() const noexcept { return pdu.get_uint16_nc( 1 + 2 ); }
879
880 std::string getName() const noexcept override {
881 return "AttReadBlobReq";
882 }
883
884 protected:
885 std::string valueString() const noexcept override {
886 return "handle "+jau::to_hexstring(getHandle())+", valueOffset "+jau::to_hexstring(getValueOffset());
887 }
888 };
889
890 /**
891 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.4 ATT_READ_RSP
892 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.6 ATT_READ_BLOB_RSP
893 *
894 * Used for
895 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.1 Read Characteristic Value
896 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.1 Read Characteristic Descriptors
897 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.3 Read Long Characteristic Value (Blob)
898 *
899 * Note:
900 * ------
901 * If expected value size exceeds getValueSize(), continue with ATT_READ_BLOB_REQ (3.4.4.5),
902 * see shallReadBlobReq(..)
903 */
904 class AttReadNRsp final : public AttPDUMsg
905 {
906 private:
907 const jau::TOctetSlice view;
908
909 constexpr static jau::nsize_t pdu_value_offset = 1;
910
911 public:
912 AttReadNRsp(const uint8_t* source, const jau::nsize_t length)
913 : AttPDUMsg(source, length),
915 {
916 check_range();
918 }
919
920 AttReadNRsp(const bool blobRsp, const jau::TROOctets & value, jau::nsize_t value_offset=0)
921 : AttPDUMsg(blobRsp ? Opcode::READ_BLOB_RSP : Opcode::READ_RSP, getPDUValueOffset()+value.size()-value_offset),
923 {
924 if( value_offset > value.size() ) { // Blob: value_size == value_offset -> OK, ends communication
925 throw AttValueException(getName()+": Invalid value offset "+std::to_string(value_offset)+
926 " > value-size "+std::to_string(value.size()), E_FILE_LINE);
927 }
928 pdu.put_bytes(getPDUValueOffset(), value.get_ptr()+value_offset, value.size()-value_offset);
929 check_range();
930 }
931
932 /** opcode */
933 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
934
935 constexpr uint8_t const * getValuePtr() const noexcept { return pdu.get_ptr_nc( pdu_value_offset ); }
936
937 constexpr jau::TOctetSlice const & getValue() const noexcept { return view; }
938
939 std::string getName() const noexcept override {
940 return "AttReadNRsp";
941 }
942
943 protected:
944 std::string valueString() const noexcept override {
945 return "size "+std::to_string(getPDUValueSize())+", data "+view.toString();
946 }
947 };
948
949 /**
950 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.1 ATT_WRITE_REQ
951 *
952 * Reply
953 * - ATT_WRITE_RSP -> AttWriteRsp
954 *
955 * Used for:
956 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value
957 * - BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration
958 */
959 class AttWriteReq final : public AttPDUMsg
960 {
961 private:
962 const jau::TOctetSlice view;
963
964 constexpr static jau::nsize_t pdu_value_offset = 1 + 2;
965
966 public:
967 AttWriteReq(const uint8_t* source, const jau::nsize_t length)
968 : AttPDUMsg(source, length),
970 {
971 check_range();
973 }
974
975 AttWriteReq(const uint16_t handle, const jau::TROOctets & value)
976 : AttPDUMsg(Opcode::WRITE_REQ, getPDUValueOffset()+value.size()),
978 {
979 pdu.put_uint16(1, handle);
980 pdu.put_bytes(getPDUValueOffset(), value.get_ptr(), value.size());
981 check_range();
982 }
983
984 /** opcode + handle */
985 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
986
987 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
988
989 constexpr uint8_t const * getValuePtr() const noexcept { return pdu.get_ptr_nc( pdu_value_offset ); }
990
991 constexpr jau::TOctetSlice const & getValue() const noexcept { return view; }
992
993 std::string getName() const noexcept override {
994 return "AttWriteReq";
995 }
996
997 protected:
998 std::string valueString() const noexcept override {
999 return "handle "+jau::to_hexstring(getHandle())+", data "+view.toString();
1000 }
1001 };
1002
1003 /**
1004 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.2 ATT_WRITE_RSP
1005 *
1006 * Used for:
1007 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value
1008 */
1009 class AttWriteRsp final : public AttPDUMsg
1010 {
1011 public:
1012 AttWriteRsp(const uint8_t* source, const jau::nsize_t length)
1013 : AttPDUMsg(source, length)
1014 {
1015 check_range();
1017 }
1018
1020 : AttPDUMsg(Opcode::WRITE_RSP, 1)
1021 {
1022 check_range();
1023 }
1024
1025 /** opcode */
1026 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1; }
1027
1028 std::string getName() const noexcept override {
1029 return "AttWriteRsp";
1030 }
1031 };
1032
1033 /**
1034 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.3 ATT_WRITE_CMD
1035 *
1036 * Reply
1037 * - None
1038 *
1039 * Used for:
1040 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.1 Write Characteristic Value without Response
1041 */
1042 class AttWriteCmd final : public AttPDUMsg
1043 {
1044 private:
1045 const jau::TOctetSlice view;
1046
1047 constexpr static jau::nsize_t pdu_value_offset = 1 + 2;
1048
1049 public:
1050 AttWriteCmd(const uint8_t* source, const jau::nsize_t length)
1051 : AttPDUMsg(source, length),
1053 {
1054 check_range();
1056 }
1057
1058 AttWriteCmd(const uint16_t handle, const jau::TROOctets & value)
1059 : AttPDUMsg(Opcode::WRITE_CMD, getPDUValueOffset()+value.size()),
1061 {
1062 pdu.put_uint16(1, handle);
1063 pdu.put_bytes(getPDUValueOffset(), value.get_ptr(), value.size());
1064 check_range();
1065 }
1066
1067 /** opcode + handle */
1068 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
1069
1070 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
1071
1072 constexpr uint8_t const * getValuePtr() const noexcept { return pdu.get_ptr_nc( pdu_value_offset ); }
1073
1074 constexpr jau::TOctetSlice const & getValue() const noexcept { return view; }
1075
1076 std::string getName() const noexcept override {
1077 return "AttWriteCmd";
1078 }
1079
1080 protected:
1081 std::string valueString() const noexcept override {
1082 return "handle "+jau::to_hexstring(getHandle())+", data "+view.toString();
1083 }
1084 };
1085
1086 /**
1087 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.1 ATT_PREPARE_WRITE_REQ
1088 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.2 ATT_PREPARE_WRITE_RSP
1089 *
1090 * Used for:
1091 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.4 Write Long Characteristic Values
1092 */
1093 class AttPrepWrite final : public AttPDUMsg
1094 {
1095 private:
1096 const jau::TOctetSlice view;
1097
1098 constexpr static jau::nsize_t pdu_value_offset = 1 + 2 + 2;
1099
1100 public:
1101 AttPrepWrite(const uint8_t* source, const jau::nsize_t length)
1102 : AttPDUMsg(source, length),
1104 {
1105 check_range();
1107 }
1108
1109 AttPrepWrite(const bool isReq, const uint16_t handle, const jau::TROOctets & value, const uint16_t value_offset)
1110 : AttPDUMsg(isReq ? Opcode::PREPARE_WRITE_REQ : Opcode::PREPARE_WRITE_RSP, getPDUValueOffset()+value.size()),
1112 {
1113 pdu.put_uint16(1, handle);
1114 pdu.put_uint16(3, value_offset);
1115 pdu.put_bytes(getPDUValueOffset(), value.get_ptr(), value.size());
1116 check_range();
1117 }
1118
1119 AttPrepWrite(const bool isReq, const AttPrepWrite& other)
1120 : AttPDUMsg(isReq ? Opcode::PREPARE_WRITE_REQ : Opcode::PREPARE_WRITE_RSP, getPDUValueOffset()+other.getValue().size()),
1122 {
1123 pdu.put_uint16(1, other.getHandle());
1124 pdu.put_uint16(3, other.getValueOffset());
1126 check_range();
1127 }
1128
1130 : AttPDUMsg(other.getOpcode(), getPDUValueOffset()+other.getValue().size()),
1132 {
1133 pdu.put_uint16(1, other.getHandle());
1134 pdu.put_uint16(3, other.getValueOffset());
1136 check_range();
1137 }
1138
1139 /** opcode + handle + value_offset */
1140 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
1141
1142 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
1143
1144 constexpr uint16_t getValueOffset() const noexcept { return pdu.get_uint16_nc( 1 + 2 ); }
1145
1146 constexpr uint8_t const * getValuePtr() const noexcept { return pdu.get_ptr_nc( pdu_value_offset ); }
1147
1148 constexpr jau::TOctetSlice const & getValue() const noexcept { return view; }
1149
1150 std::string getName() const noexcept override {
1151 return "AttPrepWrite";
1152 }
1153
1154 protected:
1155 std::string valueString() const noexcept override {
1156 return "handle "+jau::to_hexstring(getHandle())+", offset "+std::to_string(getValueOffset())+", data "+view.toString();
1157 }
1158 };
1159
1160 /**
1161 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.3 ATT_EXECUTE_WRITE_REQ
1162 *
1163 * Used for:
1164 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.4 Write Long Characteristic Values
1165 */
1166 class AttExeWriteReq final : public AttPDUMsg
1167 {
1168 public:
1169 AttExeWriteReq(const uint8_t* source, const jau::nsize_t length)
1170 : AttPDUMsg(source, length)
1171 {
1172 check_range();
1174 }
1175
1176 AttExeWriteReq(const uint8_t flags)
1177 : AttPDUMsg(Opcode::EXECUTE_WRITE_REQ, 1+1)
1178 {
1179 pdu.put_uint8(1, flags);
1180 check_range();
1181 }
1182
1183 /** opcode */
1184 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1+1; }
1185
1186 constexpr uint8_t getFlags() const noexcept { return pdu.get_uint8_nc( 1 ); }
1187
1188 std::string getName() const noexcept override {
1189 return "AttExeWriteReq";
1190 }
1191 };
1192
1193 /**
1194 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.4 ATT_EXECUTE_WRITE_RSP
1195 *
1196 * Used for:
1197 * - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.4 Write Long Characteristic Values
1198 */
1199 class AttExeWriteRsp final : public AttPDUMsg
1200 {
1201 public:
1202 AttExeWriteRsp(const uint8_t* source, const jau::nsize_t length)
1203 : AttPDUMsg(source, length)
1204 {
1205 check_range();
1207 }
1208
1210 : AttPDUMsg(Opcode::EXECUTE_WRITE_RSP, 1)
1211 {
1212 check_range();
1213 }
1214
1215 /** opcode */
1216 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1; }
1217
1218 std::string getName() const noexcept override {
1219 return "AttExeWriteRsp";
1220 }
1221 };
1222
1223 /**
1224 * ATT Protocol PDUs Vol 3, Part F 3.4.7.1 and 3.4.7.2
1225 * <p>
1226 * A received ATT_HANDLE_VALUE_NTF or ATT_HANDLE_VALUE_IND from server.
1227 * </p>
1228 * Used in:
1229 * <p>
1230 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.10 Characteristic Value Notification
1231 * </p>
1232 * <p>
1233 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.11 Characteristic Value Indications
1234 * </p>
1235 * <p>
1236 * Send by server to notify or indicate an ATT value (at any time).
1237 * </p>
1238 */
1239 class AttHandleValueRcv final : public AttPDUMsg
1240 {
1241 private:
1242 const jau::TOctetSlice view;
1243
1244 constexpr static jau::nsize_t pdu_value_offset = 1 + 2;
1245
1246 public:
1247 AttHandleValueRcv(const uint8_t* source, const jau::nsize_t length)
1248 : AttPDUMsg(source, length),
1250 {
1251 check_range();
1253 }
1254
1255 AttHandleValueRcv(const bool isNotify, const uint16_t handle, const jau::TROOctets & value, const jau::nsize_t mtu)
1256 : AttPDUMsg(isNotify ? Opcode::HANDLE_VALUE_NTF : Opcode::HANDLE_VALUE_IND, getPDUValueOffset()+std::min(mtu-pdu_value_offset, value.size())),
1258 {
1259 pdu.put_uint16(1, handle);
1260 pdu.put_bytes(getPDUValueOffset(), value.get_ptr(), std::min(mtu-pdu_value_offset, value.size()));
1261 check_range();
1262 }
1263
1264 /** opcode + handle */
1265 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
1266
1267 constexpr uint16_t getHandle() const noexcept { return pdu.get_uint16_nc(1); }
1268
1269 constexpr uint8_t const * getValuePtr() const noexcept { return pdu.get_ptr_nc( pdu_value_offset ); }
1270
1271 jau::TOctetSlice const & getValue() const noexcept { return view; }
1272
1273 bool isNotification() const noexcept {
1275 }
1276
1277 bool isIndication() const noexcept {
1279 }
1280
1281 std::string getName() const noexcept override {
1282 return "AttHandleValueRcv";
1283 }
1284
1285 protected:
1286 std::string valueString() const noexcept override {
1287 return "handle "+jau::to_hexstring(getHandle())+", size "+std::to_string(getPDUValueSize())+", data "+view.toString();
1288 }
1289 };
1290
1291 /**
1292 * ATT Protocol PDUs Vol 3, Part F 3.4.7.3
1293 * <p>
1294 * ATT_HANDLE_VALUE_CFM to server, acknowledging ATT_HANDLE_VALUE_IND
1295 * </p>
1296 * Used in:
1297 * <p>
1298 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.11 Characteristic Value Indications
1299 * </p>
1300 */
1301 class AttHandleValueCfm final : public AttPDUMsg
1302 {
1303 public:
1304 AttHandleValueCfm(const uint8_t* source, const jau::nsize_t length)
1305 : AttPDUMsg(source, length)
1306 {
1307 check_range();
1309 }
1310
1312 : AttPDUMsg(Opcode::HANDLE_VALUE_CFM, 1)
1313 {
1314 check_range();
1315 }
1316
1317 /** opcode */
1318 jau::nsize_t getPDUValueOffset() const noexcept override { return 1; }
1319
1320 std::string getName() const noexcept override {
1321 return "AttHandleValueCfm";
1322 }
1323 };
1324
1325 /**
1326 * List of elements.
1327 *
1328 * { element_size, element[element_size] }, with
1329 *
1330 * element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
1331 *
1332 */
1334 {
1335 protected:
1336 AttElementList(const uint8_t* source, const jau::nsize_t length)
1337 : AttPDUMsg(source, length) {}
1338
1339 AttElementList(const Opcode opc, const jau::nsize_t size)
1340 : AttPDUMsg(opc, size) {}
1341
1342 virtual std::string addValueString() const { return ""; }
1343 virtual std::string elementString(const jau::nsize_t idx) const { (void)idx; return "not implemented"; }
1344
1345 std::string valueString() const noexcept override {
1346 std::string res = "size "+std::to_string(getPDUValueSize())+", "+addValueString()+"elements[count "+std::to_string(getElementCount())+", "+
1347 "size [total "+std::to_string(getElementSize())+", value "+std::to_string(getElementValueSize())+"]: ";
1348 const jau::nsize_t count = getElementCount();
1349 for(jau::nsize_t i=0; i<count; i++) {
1350 res += std::to_string(i)+"["+elementString(i)+"],";
1351 }
1352 res += "]";
1353 return res;
1354 }
1355
1356 public:
1357 ~AttElementList() noexcept override = default;
1358
1359 /** Total size of one element */
1360 virtual jau::nsize_t getElementSize() const = 0;
1361
1362 /**
1363 * Fixate element length
1364 * @param element_length
1365 */
1366 virtual void setElementSize(const uint8_t element_length) = 0;
1367
1368 /**
1369 * Net element-value size, i.e. element size less handles.
1370 * <p>
1371 * element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
1372 * </p>
1373 */
1374 virtual jau::nsize_t getElementValueSize() const = 0;
1375
1376 /** Number of elements */
1378 /** getPDUValueSize() =
1379 * - `pdu.size - getAuthSigSize() - value-offset` or
1380 * - `getPDUParamSize() - getPDUValueOffset() + 1`
1381 */
1382 return getPDUValueSize() / getElementSize();
1383 }
1384
1385 /**
1386 * Fixate element count
1387 * @param count
1388 */
1389 void setElementCount(const jau::nsize_t count) {
1390 const jau::nsize_t element_length = getElementSize();
1391 const jau::nsize_t new_size = getPDUValueOffset() + element_length * count;
1392 if( pdu.size() < new_size ) {
1394 " + element[len "+std::to_string(element_length)+
1395 " * count "+std::to_string(count)+" > pdu "+std::to_string(pdu.size()), E_FILE_LINE);
1396 }
1397 pdu.resize( new_size );
1398 if( getPDUValueSize() % getElementSize() != 0 ) {
1399 throw AttValueException(getName()+": Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
1400 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
1401 }
1402 }
1403
1405 return getPDUValueOffset() + elementIdx * getElementSize();
1406 }
1407
1408 uint8_t const * getElementPtr(const jau::nsize_t elementIdx) const {
1409 return pdu.get_ptr(getElementPDUOffset(elementIdx));
1410 }
1411
1412 std::string getName() const noexcept override {
1413 return "AttElementList";
1414 }
1415 };
1416
1417 /**
1418 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.1 ATT_READ_BY_TYPE_REQ
1419 * <p>
1420 * ATT_READ_BY_TYPE_REQ
1421 * </p>
1422 *
1423 * <p>
1424 * and
1425 * </p>
1426 *
1427 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.9 ATT_READ_BY_GROUP_TYPE_REQ
1428 * <p>
1429 * ATT_READ_BY_GROUP_TYPE_REQ
1430 * </p>
1431 * Used in:
1432 * <p>
1433 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.1 Discover All Primary Services
1434 * </p>
1435 * <p>
1436 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service
1437 * </p>
1438 * <p>
1439 * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1 Characteristic Declaration Attribute Value
1440 * </p>
1441 */
1442 class AttReadByNTypeReq final : public AttPDUMsg
1443 {
1444 private:
1445 jau::uuid_t::TypeSize getUUIFormat() const {
1447 }
1448
1449 public:
1450 AttReadByNTypeReq(const uint8_t* source, const jau::nsize_t length)
1451 : AttPDUMsg(source, length)
1452 {
1453 check_range();
1455 }
1456
1457 AttReadByNTypeReq(const bool groupTypeReq, const uint16_t startHandle, const uint16_t endHandle, const jau::uuid_t & uuid)
1458 : AttPDUMsg(groupTypeReq ? Opcode::READ_BY_GROUP_TYPE_REQ : Opcode::READ_BY_TYPE_REQ, getPDUValueOffset()+uuid.getTypeSizeInt())
1459 {
1461 throw jau::IllegalArgumentException("Only UUID16 and UUID128 allowed: "+uuid.toString(), E_FILE_LINE);
1462 }
1463 pdu.put_uint16(1, startHandle);
1464 pdu.put_uint16(3, endHandle);
1465 pdu.put_uuid(5, uuid);
1466 check_range();
1467 }
1468
1469 /** opcode + handle-start + handle-end */
1470 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 2 + 2; }
1471
1472 constexpr uint16_t getStartHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
1473
1474 constexpr uint16_t getEndHandle() const noexcept { return pdu.get_uint16_nc( 1 + 2 /* 1 handle size */ ); }
1475
1476 std::string getName() const noexcept override {
1477 return "AttReadByNTypeReq";
1478 }
1479
1480 std::unique_ptr<const jau::uuid_t> getNType() const {
1481 return pdu.get_uuid( getPDUValueOffset(), getUUIFormat() );
1482 }
1483
1484 protected:
1485 std::string valueString() const noexcept override {
1487 "], uuid "+getNType()->toString();
1488 }
1489 };
1490
1491 /**
1492 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.2 ATT_READ_BY_TYPE_RSP
1493 * <p>
1494 * ATT_READ_BY_TYPE_RSP
1495 * </p>
1496 * <p>
1497 * Contains a list of elements, each comprised of handle-value pairs.
1498 * The handle is comprised of two octets, i.e. uint16_t.
1499 * <pre>
1500 * element := { uint16_t handle, uint8_t value[value-size] }
1501 * </pre>
1502 * </p>
1503 * Used in:
1504 * <p>
1505 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service
1506 * </p>
1507 * <p>
1508 * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1 Characteristic Declaration Attribute Value
1509 * </p>
1510 */
1512 {
1513 public:
1514 /**
1515 * element := { uint16_t handle, uint8_t value[value-size] }
1516 */
1517 class Element {
1518 private:
1519 const jau::TOctetSlice view;
1520
1521 public:
1523 : view(p.pdu, p.getElementPDUOffset(idx), p.getElementSize()) {}
1524
1525 constexpr uint16_t getHandle() const noexcept { return view.get_uint16_nc(0); }
1526
1527 constexpr uint8_t const * getValuePtr() const noexcept { return view.get_ptr_nc(2 /* handle size */); }
1528
1529 constexpr jau::nsize_t getValueSize() const noexcept { return view.size() - 2 /* handle size */; }
1530
1531 std::string toString() const {
1532 return "handle "+jau::to_hexstring(getHandle())+
1533 ", data "+jau::bytesHexString(getValuePtr(), 0, getValueSize(), true /* lsbFirst */);
1534 }
1535 };
1536
1537 AttReadByTypeRsp(const uint8_t* source, const jau::nsize_t length)
1538 : AttElementList(source, length)
1539 {
1540 check_range();
1542
1543 if( getPDUValueSize() % getElementSize() != 0 ) {
1544 throw AttValueException("AttReadByTypeRsp: Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
1545 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
1546 }
1547 }
1548
1549 /** opcode + element-size */
1550 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 1; }
1551
1552 /** Returns size of each element, i.e. handle-value pair. */
1553 constexpr_cxx20 jau::nsize_t getElementSize() const noexcept override {
1554 return pdu.get_uint8_nc(1);
1555 }
1556
1557 /**
1558 * Fixate element length
1559 * @param element_length
1560 */
1561 void setElementSize(const uint8_t element_length) override {
1562 pdu.put_uint8_nc(1, element_length);
1563 }
1564
1565 /**
1566 * Net element-value size, i.e. element size less handle.
1567 * <p>
1568 * element := { uint16_t handle, uint8_t value[value-size] }
1569 * </p>
1570 */
1572 return getElementSize() - 2;
1573 }
1574
1575 /**
1576 * Create an incomplete response with maximal (MTU) length.
1577 *
1578 * User shall set all elements via the set*() methods
1579 * and finally use setElementSize() to fixate element length and element count.
1580 *
1581 * @param total_length maximum
1582 */
1583 AttReadByTypeRsp(const jau::nsize_t total_length)
1584 : AttElementList(Opcode::READ_BY_TYPE_RSP, total_length)
1585 {
1586 pdu.put_uint8(1, 2 + 1 + 2 + 2); // dummy element_size: handle + property + handle + uuid
1587 check_range();
1588 }
1589
1590 Element getElement(const jau::nsize_t elementIdx) const {
1591 return Element(*this, elementIdx);
1592 }
1593
1594 uint16_t getElementHandle(const jau::nsize_t elementIdx) const {
1595 return pdu.get_uint16( getElementPDUOffset(elementIdx) );
1596 }
1597 void setElementHandle(const jau::nsize_t elementIdx, const uint16_t h) {
1598 pdu.put_uint16_nc( getElementPDUOffset(elementIdx), h );
1599 }
1600
1601 uint8_t * getElementValuePtr(const jau::nsize_t elementIdx) {
1602 return pdu.get_wptr() + getElementPDUOffset(elementIdx) + 2 /* handle size */;
1603 }
1604
1605 std::string getName() const noexcept override {
1606 return "AttReadByTypeRsp";
1607 }
1608
1609 protected:
1610 std::string elementString(const jau::nsize_t idx) const override {
1611 return getElement(idx).toString();
1612 }
1613 };
1614
1615
1616 /**
1617 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.10 ATT_READ_BY_GROUP_TYPE_RSP
1618 * <p>
1619 * ATT_READ_BY_GROUP_TYPE_RSP
1620 * </p>
1621 * <p>
1622 * Contains a list of elements, each comprised of { start_handle, end_handle, value } triple.
1623 * Both handle are each comprised of two octets, i.e. uint16_t.
1624 * <pre>
1625 * element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
1626 * </pre>
1627 * </p>
1628 * Used in:
1629 * <p>
1630 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.1 Discover All Primary Services
1631 * </p>
1632 */
1634 {
1635 public:
1636 /**
1637 * element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
1638 */
1639 class Element {
1640 private:
1641 const jau::TOctetSlice view;
1642
1643 public:
1645 : view(p.pdu, p.getElementPDUOffset(idx), p.getElementSize()) {}
1646
1647 constexpr uint16_t getStartHandle() const noexcept { return view.get_uint16_nc(0); }
1648
1649 constexpr uint16_t getEndHandle() const noexcept { return view.get_uint16_nc(2); }
1650
1651 constexpr uint8_t const * getValuePtr() const noexcept { return view.get_ptr_nc(4 /* handle size */); }
1652
1653 constexpr jau::nsize_t getValueSize() const noexcept { return view.size() - 4 /* handle size */; }
1654 };
1655
1656 AttReadByGroupTypeRsp(const uint8_t* source, const jau::nsize_t length)
1657 : AttElementList(source, length)
1658 {
1659 check_range();
1661
1662 if( getPDUValueSize() % getElementSize() != 0 ) {
1663 throw AttValueException("AttReadByGroupTypeRsp: Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
1664 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
1665 }
1666 }
1667
1668 /** opcode + element-size */
1669 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 1; }
1670
1671 /** Returns size of each element, i.e. handle-value triple. */
1672 constexpr_cxx20 jau::nsize_t getElementSize() const noexcept override {
1673 return pdu.get_uint8_nc(1);
1674 }
1675
1676 /**
1677 * Fixate element length
1678 * @param element_length
1679 */
1680 void setElementSize(const uint8_t element_length) override {
1681 pdu.put_uint8_nc(1, element_length);
1682 check_range();
1683 }
1684
1685 /**
1686 * Net element-value size, i.e. element size less handles.
1687 * <p>
1688 * element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
1689 * </p>
1690 */
1692 return getElementSize() - 4;
1693 }
1694
1695 /**
1696 * Create an incomplete response with maximal (MTU) length.
1697 *
1698 * User shall set all elements via the set*() methods
1699 * and finally use setElementSize() to fixate element length and element count.
1700 *
1701 * @param total_length maximum
1702 */
1704 : AttElementList(Opcode::READ_BY_GROUP_TYPE_RSP, total_length)
1705 {
1706 pdu.put_uint8(1, 2+2+2); // dummy element_size: handle + handle + uuid
1707 check_range();
1708 }
1709
1710 Element getElement(const jau::nsize_t elementIdx) const {
1711 return Element(*this, elementIdx);
1712 }
1713
1714 uint16_t getElementStartHandle(const jau::nsize_t elementIdx) const {
1715 return pdu.get_uint16( getElementPDUOffset(elementIdx) );
1716 }
1717 void setElementStartHandle(const jau::nsize_t elementIdx, const uint16_t h) {
1718 pdu.put_uint16_nc( getElementPDUOffset(elementIdx), h );
1719 }
1720
1721 uint16_t getElementEndHandle(const jau::nsize_t elementIdx) const {
1722 return pdu.get_uint16( getElementPDUOffset(elementIdx) + 2 /* 1 handle size */ );
1723 }
1724 void setElementEndHandle(const jau::nsize_t elementIdx, const uint16_t h) {
1725 pdu.put_uint16_nc( getElementPDUOffset(elementIdx) + 2, h );
1726 }
1727
1728 uint8_t * getElementValuePtr(const jau::nsize_t elementIdx) {
1729 return pdu.get_wptr() + getElementPDUOffset(elementIdx) + 4 /* 2 handle size */;
1730 }
1731 void setElementValueUUID(const jau::nsize_t elementIdx, const jau::uuid_t& v) {
1732 uint8_t * b = getElementValuePtr(elementIdx);
1733 v.put(b + 0, jau::lb_endian_t::little);
1734 }
1735
1736 std::string getName() const noexcept override {
1737 return "AttReadByGroupTypeRsp";
1738 }
1739
1740 protected:
1741 std::string elementString(const jau::nsize_t idx) const override {
1742 Element e = getElement(idx);
1743 return "handle ["+jau::to_hexstring(e.getStartHandle())+".."+jau::to_hexstring(e.getEndHandle())+
1744 "], data "+jau::bytesHexString(e.getValuePtr(), 0, e.getValueSize(), true /* lsbFirst */);
1745 }
1746 };
1747
1748 /**
1749 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.1 ATT_FIND_INFORMATION_REQ
1750 * <p>
1751 * ATT_FIND_INFORMATION_REQ
1752 * </p>
1753 * Used in:
1754 * <p>
1755 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.7.1 Discover All Characteristic Descriptors
1756 * </p>
1757 */
1758 class AttFindInfoReq final : public AttPDUMsg
1759 {
1760 public:
1761 AttFindInfoReq(const uint8_t* source, const jau::nsize_t length)
1762 : AttPDUMsg(source, length)
1763 {
1764 check_range();
1766 }
1767
1768 AttFindInfoReq(const uint16_t startHandle, const uint16_t endHandle)
1769 : AttPDUMsg(Opcode::FIND_INFORMATION_REQ, 1+2+2)
1770 {
1771 pdu.put_uint16(1, startHandle);
1772 pdu.put_uint16(3, endHandle);
1773 check_range();
1774 }
1775
1776 /** opcode + handle_start + handle_end */
1777 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 2 + 2; }
1778
1779 constexpr uint16_t getStartHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
1780
1781 constexpr uint16_t getEndHandle() const noexcept { return pdu.get_uint16_nc( 1 + 2 ); }
1782
1783 std::string getName() const noexcept override {
1784 return "AttFindInfoReq";
1785 }
1786
1787 protected:
1788 std::string valueString() const noexcept override {
1789 return "handle ["+jau::to_hexstring(getStartHandle())+".."+jau::to_hexstring(getEndHandle())+"]";
1790 }
1791 };
1792
1793 /**
1794 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.2 ATT_FIND_INFORMATION_RSP
1795 * <p>
1796 * ATT_FIND_INFORMATION_RSP
1797 * </p>
1798 * <p>
1799 * Contains a list of elements, each comprised of { handle, [UUID16 | UUID128] } pair.
1800 * The handle is comprised of two octets, i.e. uint16_t.
1801 * The UUID is either comprised of 2 octets for UUID16 or 16 octets for UUID128
1802 * depending on the given format.
1803 * <pre>
1804 * element := { uint16_t handle, UUID value }, with a UUID of UUID16 or UUID128
1805 * </pre>
1806 * </p>
1807 * Used in:
1808 * <p>
1809 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.7.1 Discover All Characteristic Descriptors
1810 * </p>
1811 */
1812 class AttFindInfoRsp final : public AttElementList
1813 {
1814 private:
1815 static jau::uuid_t::TypeSize toTypeSize(const uint8_t format) {
1816 if( 0x01 == format ) {
1818 } else if( 0x02 == format ) {
1820 }
1821 throw AttValueException("AttFindInfoRsp: Invalid format "+std::to_string(format)+", not UUID16 (1) or UUID128 (2)", E_FILE_LINE);
1822 }
1823
1824 static uint8_t toFormatCode(const jau::uuid_t::TypeSize tsz) {
1825 switch( tsz ) {
1826 case jau::uuid_t::TypeSize::UUID16_SZ: return 0x01;
1827 case jau::uuid_t::TypeSize::UUID128_SZ: return 0x02;
1828 default: break;
1829 }
1830 throw AttValueException("AttFindInfoRsp: Invalid TypeSize "+jau::uuid_t::getTypeSizeString(tsz)+", not UUID16_SZ (1) or UUID128_SZ (2)", E_FILE_LINE);
1831 }
1832
1833 public:
1834 /**
1835 * element := { uint16_t handle, UUID value }, with a UUID of UUID16 or UUID128
1836 */
1837 class Element {
1838 public:
1839 const uint16_t handle;
1840 const std::unique_ptr<const jau::uuid_t> uuid;
1841
1843 : handle( p.getElementHandle(idx) ), uuid( p.getElementValue(idx) )
1844 { }
1845 };
1846
1847 AttFindInfoRsp(const uint8_t* source, const jau::nsize_t length)
1848 : AttElementList(source, length)
1849 {
1850 check_range();
1852 if( getPDUValueSize() % getElementSize() != 0 ) {
1853 throw AttValueException("AttFindInfoRsp: Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
1854 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
1855 }
1856 }
1857
1858 /** opcode + format */
1859 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1 + 1; }
1860
1861 /**
1862 * Returns element size.
1863 * <p>
1864 * element := { uint16_t handle, UUID value }, with a UUID of UUID16 or UUID128
1865 * </p>
1866 */
1867 jau::nsize_t getElementSize() const override {
1868 return 2 /* handle */ + getElementValueSize();
1869 }
1870
1872 return toTypeSize( pdu.get_uint8_nc(1) );
1873 }
1874
1875 /**
1876 * Net element-value size, i.e. element size less handles.
1877 * <p>
1878 * element := { uint16_t handle, UUID value }, with a UUID of UUID16 or UUID128
1879 * </p>
1880 */
1883 }
1884
1885 /**
1886 * Fixate element length
1887 * @param element_length
1888 */
1889 void setElementSize(const uint8_t element_length) override {
1890 const jau::nsize_t tsz_i = element_length - 2 /* handle */;
1892 pdu.put_uint8_nc(1, toFormatCode(tsz));
1893 check_range();
1894 }
1895
1896 /**
1897 * Create an incomplete response with maximal (MTU) length.
1898 *
1899 * User shall set all elements via the set*() methods
1900 * and finally use setElementSize() to fixate element length and setElementCount() to set element count.
1901 *
1902 * @param total_length maximum
1903 */
1904 AttFindInfoRsp(const jau::nsize_t total_length)
1905 : AttElementList(Opcode::FIND_INFORMATION_RSP, total_length)
1906 {
1907 pdu.put_uint8(1, 2); // dummy format: uuid16_t
1908 check_range();
1909 }
1910
1911 Element getElement(const jau::nsize_t elementIdx) const {
1912 return Element(*this, elementIdx);
1913 }
1914
1915 uint16_t getElementHandle(const jau::nsize_t elementIdx) const {
1916 return pdu.get_uint16( getElementPDUOffset(elementIdx) );
1917 }
1918 void setElementHandle(const jau::nsize_t elementIdx, const uint16_t h) {
1919 pdu.put_uint16_nc( getElementPDUOffset(elementIdx), h );
1920 }
1921
1922 std::unique_ptr<const jau::uuid_t> getElementValue(const jau::nsize_t elementIdx) const {
1923 return pdu.get_uuid( getElementPDUOffset(elementIdx) + 2, getElementValueFormat() );
1924 }
1925 void setElementValueUUID(const jau::nsize_t elementIdx, const jau::uuid_t& v) {
1926 uint8_t * b = pdu.get_wptr() + getElementPDUOffset(elementIdx) + 2 /* handle size */;
1927 v.put(b + 0, jau::lb_endian_t::little);
1928 }
1929
1930 std::string getName() const noexcept override {
1931 return "AttFindInfoRsp";
1932 }
1933
1934 protected:
1935 std::string addValueString() const override { return "format "+std::to_string(pdu.get_uint8_nc(1))+", "; }
1936
1937 std::string elementString(const jau::nsize_t idx) const override {
1938 Element e = getElement(idx);
1939 return "handle "+jau::to_hexstring(e.handle)+
1940 ", uuid "+e.uuid.get()->toString();
1941 }
1942 };
1943
1944 /**
1945 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.3 ATT_FIND_BY_TYPE_VALUE_REQ
1946 * <p>
1947 * FIND_BY_TYPE_VALUE_REQ
1948 * </p>
1949 * Used in:
1950 * <p>
1951 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.2 Discover Primary Service by Service UUID
1952 * </p>
1953 */
1955 {
1956 private:
1957 jau::uuid_t::TypeSize getAttValueTypeSize() const {
1959 }
1960
1961 constexpr static jau::nsize_t pdu_value_offset = 1 + 2 + 2 + 2;
1962
1963 public:
1964 AttFindByTypeValueReq(const uint8_t* source, const jau::nsize_t length)
1965 : AttPDUMsg(source, length)
1966 {
1967 check_range();
1969
1970 if( getPDUValueSize() == 0 ) {
1971 throw AttValueException("AttFindByTypeValueReq: Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
1972 " not > 0 ", E_FILE_LINE);
1973 }
1974 getAttValueTypeSize(); // validates att-value type-size
1975 }
1976
1977 AttFindByTypeValueReq(const uint16_t startHandle, const uint16_t endHandle,
1978 const jau::uuid16_t &att_type, const jau::uuid_t& att_value)
1979 : AttPDUMsg(Opcode::FIND_BY_TYPE_VALUE_REQ, getPDUValueOffset()+att_value.getTypeSizeInt())
1980 {
1981 pdu.put_uint16(1, startHandle);
1982 pdu.put_uint16(1+2, endHandle);
1983 pdu.put_uuid (1+2+2, att_type);
1984 pdu.put_uuid (1+2+2+2, att_value);
1985 check_range();
1986 }
1987
1988 /** opcode + handle_start + handle_end + att_type */
1989 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return pdu_value_offset; }
1990
1991 constexpr uint16_t getStartHandle() const noexcept { return pdu.get_uint16_nc( 1 ); }
1992
1993 constexpr uint16_t getEndHandle() const noexcept { return pdu.get_uint16_nc( 1 + 2 ); }
1994
1995 jau::uuid16_t getAttType() const noexcept { return pdu.get_uuid16_nc( 1 + 2 + 2 ); }
1996
1997 std::unique_ptr<const jau::uuid_t> getAttValue() const noexcept {
1998 try {
1999 return pdu.get_uuid(pdu_value_offset, getAttValueTypeSize());
2000 } catch (const jau::ExceptionBase &e) {
2001 ERR_PRINT("invalid att uuid: %s", e.message().c_str());
2002 } catch (...) {
2003 ERR_PRINT("invalid att uuid: Unknown exception");
2004 }
2005 return std::make_unique<jau::uuid16_t>(0);
2006 }
2007
2008 std::string getName() const noexcept override {
2009 return "AttFindByTypeValueReq";
2010 }
2011
2012 protected:
2013 std::string valueString() const noexcept override {
2015 "], type "+getAttType().toString()+", value "+getAttValue()->toString();
2016 }
2017 };
2018
2019 /**
2020 * BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.4 ATT_FIND_BY_TYPE_VALUE_RSP
2021 * <p>
2022 * FIND_BY_TYPE_VALUE_RSP
2023 * </p>
2024 * <p>
2025 * Contains a list of elements, each comprised of { att_handle_start, group_end_handle } pair.
2026 * The handles are comprised of two octets, i.e. uint16_t,
2027 * hence one element is of size 4 octets.
2028 * <pre>
2029 * element := { uint16_t handle_start, uint16_t handle_end }
2030 * </pre>
2031 * </p>
2032 * Used in:
2033 * <p>
2034 * BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.2 Discover Primary Service by Service UUID
2035 * </p>
2036 */
2038 {
2039 public:
2040 AttFindByTypeValueRsp(const uint8_t* source, const jau::nsize_t length)
2041 : AttPDUMsg(source, length)
2042 {
2043 check_range();
2045 if( getPDUValueSize() % getElementSize() != 0 ) {
2046 throw AttValueException("AttFindInfoRsp: Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
2047 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
2048 }
2049 }
2050
2051 /** opcode */
2052 constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override { return 1; }
2053
2054 /**
2055 * Returns element size, 4 octets
2056 * <p>
2057 * element := { uint16_t handle_start, uint16_t handle_end }
2058 * </p>
2059 */
2060 constexpr jau::nsize_t getElementSize() const noexcept {
2061 return 2 /* handle */ + 2 /* handle_end */;
2062 }
2063
2064 /** Number of elements */
2066 /** getPDUValueSize() =
2067 * - `pdu.size - getAuthSigSize() - value-offset` or
2068 * - `getPDUParamSize() - getPDUValueOffset() + 1`
2069 */
2070 return getPDUValueSize() / getElementSize();
2071 }
2072
2073 /**
2074 * Fixate element count
2075 * @param count
2076 */
2077 void setElementCount(const jau::nsize_t count) {
2078 const jau::nsize_t element_length = getElementSize();
2079 const jau::nsize_t new_size = getPDUValueOffset() + element_length * count;
2080 if( pdu.size() < new_size ) {
2082 " + element[len "+std::to_string(element_length)+
2083 " * count "+std::to_string(count)+" > pdu "+std::to_string(pdu.size()), E_FILE_LINE);
2084 }
2085 pdu.resize( new_size );
2086 if( getPDUValueSize() % getElementSize() != 0 ) {
2087 throw AttValueException(getName()+": Invalid packet size: pdu-value-size "+std::to_string(getPDUValueSize())+
2088 " not multiple of element-size "+std::to_string(getElementSize()), E_FILE_LINE);
2089 }
2090 check_range();
2091 }
2092
2093 jau::nsize_t getElementPDUOffset(const jau::nsize_t elementIdx) const noexcept {
2094 return getPDUValueOffset() + elementIdx * getElementSize();
2095 }
2096
2097 uint8_t const * getElementPtr(const jau::nsize_t elementIdx) const {
2098 return pdu.get_ptr(getElementPDUOffset(elementIdx));
2099 }
2100
2101 /**
2102 * Create an incomplete response with maximal (MTU) length.
2103 *
2104 * User shall set all elements via the set*() methods
2105 * and finally use setElementCount() to fixate element count.
2106 *
2107 * @param total_length maximum
2108 */
2110 : AttPDUMsg(Opcode::FIND_BY_TYPE_VALUE_RSP, total_length)
2111 {
2112 check_range();
2113 }
2114
2115 uint16_t getElementHandle(const jau::nsize_t elementIdx) const {
2116 return pdu.get_uint16( getElementPDUOffset(elementIdx) );
2117 }
2118 uint16_t getElementHandleEnd(const jau::nsize_t elementIdx) const {
2119 return pdu.get_uint16( getElementPDUOffset(elementIdx) + 2 );
2120 }
2121
2122 void setElementHandles(const jau::nsize_t elementIdx, const uint16_t handle, const uint16_t handle_end) {
2123 const jau::nsize_t offset = getElementPDUOffset(elementIdx);
2124 pdu.put_uint16( offset, handle );
2125 pdu.put_uint16( offset, handle_end );
2126 }
2127
2128 std::string getName() const noexcept override {
2129 return "AttFindByTypeValueRsp";
2130 }
2131
2132 protected:
2133 std::string elementString(const jau::nsize_t idx) const {
2134 return "handle["+jau::to_hexstring(getElementHandle(idx))+
2136 }
2137
2138 std::string valueString() const noexcept override {
2139 std::string res = "size "+std::to_string(getPDUValueSize())+", elements[count "+std::to_string(getElementCount())+", "+
2140 "size "+std::to_string(getElementSize())+": ";
2141 const jau::nsize_t count = getElementCount();
2142 for(jau::nsize_t i=0; i<count; i++) {
2143 res += std::to_string(i)+"["+elementString(i)+"],";
2144 }
2145 res += "]";
2146 return res;
2147 }
2148
2149 };
2150
2151 /**@}*/
2152
2153} // namespace direct_bt
2154
2155/** \example dbt_scanner10.cpp
2156 * This _dbt_scanner10_ C++ scanner ::BTRole::Master GATT client example uses an event driven workflow
2157 * and multithreading, i.e. one thread processes each found device when notified.
2158 *
2159 * _dbt_scanner10_ represents the recommended utilization of Direct-BT.
2160 *
2161 * ### dbt_scanner10 Invocation Examples:
2162 * Using `scripts/run-dbt_scanner10.sh` from `dist` directory:
2163 *
2164 * * Scan and read all devices (using default auto-sec w/ keyboard iocap)
2165 * ~~~
2166 * ../scripts/run-dbt_scanner10.sh
2167 * ~~~
2168 *
2169 * * Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap)
2170 * ~~~
2171 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1
2172 * ~~~
2173 *
2174 * * Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap) from adapter 01:02:03:04:05:06
2175 * ~~~
2176 * ../scripts/run-dbt_scanner10.sh -adapter adapter 01:02:03:04:05:06 -dev C0:26:DA:01:DA:B1
2177 * ~~~
2178 *
2179 * * Read device C0:26:DA:01:DA:B1 (enforcing no security)
2180 * ~~~
2181 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1
2182 * ~~~
2183 *
2184 * * Read any device containing C0:26:DA (enforcing no security)
2185 * ~~~
2186 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA -seclevel C0:26:DA 1
2187 * ~~~
2188 *
2189 * * Read any device containing name `TAIDOC` (enforcing no security)
2190 * ~~~
2191 * ../scripts/run-dbt_scanner10.sh -dev 'TAIDOC' -seclevel 'TAIDOC' 1
2192 * ~~~
2193 *
2194 * * Read device C0:26:DA:01:DA:B1, basic debug flags enabled (using default auto-sec w/ keyboard iocap)
2195 * ~~~
2196 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug true
2197 * ~~~
2198 *
2199 * * Read device C0:26:DA:01:DA:B1, all debug flags enabled (using default auto-sec w/ keyboard iocap)
2200 * ~~~
2201 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
2202 * ~~~
2203 *
2204 * ## Special Actions
2205 * * To do a BT adapter removal/add via software, assuming the device is '1-4' (Bus 1.Port 4):
2206 * ~~~
2207 * echo '1-4' > /sys/bus/usb/drivers/usb/unbind
2208 * echo '1-4' > /sys/bus/usb/drivers/usb/bind
2209 * ~~~
2210 */
2211
2212/** \example dbt_peripheral00.cpp
2213 * This _dbt_peripheral00__ C++ peripheral ::BTRole::Slave GATT server example uses an event driven workflow.
2214 *
2215 * ### dbt_peripheral00 Invocation Examples:
2216 * Using `scripts/run-dbt_peripheral00.sh` from `dist` directory:
2217 *
2218 * * Serving clients as `TestDevice001` using adapter 00:1A:7D:DA:71:03; Using ENC_ONLY (JUST_WORKS) encryption.
2219 * ~~~
2220 * ../scripts/run-dbt_peripheral00.sh -adapter 00:1A:7D:DA:71:03 -name TestDevice001 -seclevel 2
2221 * ~~~
2222 */
2223
2224/** \example dbt_repeater00.cpp
2225 * This _dbt_repeater00_ C++ repeater example implementing a GATT repeater,
2226 * i.e. forwarding client requests to a GATT server and passing the results back.
2227 *
2228 * The repeater can be used in between an existing Bluetooth LE client and server,
2229 * acting as a forwarder and to analyze the GATT client/server protocol.
2230 *
2231 * ### dbt_repeater00 Invocation Examples:
2232 * Using `scripts/run-dbt_repeater00.sh` from `dist` directory:
2233 *
2234 * * Connection to server `TAIDOC TD1107` using adapter `DC:FB:48:00:90:19`; Serving client as `TAIDOC TD1108` using adapter `00:1A:7D:DA:71:03`; Using ENC_ONLY (JUST_WORKS) encryption.
2235 * ~~~
2236 * ../scripts/run-dbt_repeater00.sh -adapterToServer DC:FB:48:00:90:19 -adapterToClient 00:1A:7D:DA:71:03 -server 'TAIDOC TD1107' -nameToClient 'TAIDOC TD1108' -seclevelToServer 'TAIDOC TD1107' 2 -seclevelToClient 2 -quiet
2237 * ~~~
2238 */
2239
2240#endif /* ATT_PDU_TYPES_HPP_ */
#define E_FILE_LINE
virtual std::string addValueString() const
virtual jau::nsize_t getElementValueSize() const =0
Net element-value size, i.e.
constexpr_cxx20 jau::nsize_t getElementCount() const noexcept
Number of elements.
virtual jau::nsize_t getElementSize() const =0
Total size of one element.
AttElementList(const uint8_t *source, const jau::nsize_t length)
~AttElementList() noexcept override=default
std::string getName() const noexcept override
jau::nsize_t getElementPDUOffset(const jau::nsize_t elementIdx) const
uint8_t const * getElementPtr(const jau::nsize_t elementIdx) const
virtual std::string elementString(const jau::nsize_t idx) const
virtual void setElementSize(const uint8_t element_length)=0
Fixate element length.
std::string valueString() const noexcept override
void setElementCount(const jau::nsize_t count)
Fixate element count.
AttElementList(const Opcode opc, const jau::nsize_t size)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.1.1 ATT_ERROR_RSP.
AttErrorRsp(const uint8_t *source, const jau::nsize_t length)
constexpr uint16_t getCausingHandle() const noexcept
static constexpr uint8_t number(const ErrorCode rhs) noexcept
AttErrorRsp(const ErrorCode error_code, const Opcode cause_opc, const uint16_t cause_handle)
static std::string getErrorCodeString(const ErrorCode errorCode) noexcept
Definition: ATTPDUTypes.cpp:86
constexpr Opcode getCausingOpcode() const noexcept
constexpr ErrorCode getErrorCode() const noexcept
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + reqOpcodeCause + handleCause + errorCode
std::string getName() const noexcept override
std::string valueString() const noexcept override
AttException(std::string const &m, const char *file, int line) noexcept
AttException(std::string type, std::string const &m, const char *file, int line) noexcept
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.2.1 ATT_EXCHANGE_MTU_REQ BT Core Spec v5....
std::string valueString() const noexcept override
AttExchangeMTU(const ReqRespType type, const uint16_t mtuSize)
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + mtu-size
AttExchangeMTU(const uint8_t *source, const jau::nsize_t length)
constexpr uint16_t getMTUSize() const noexcept
std::string getName() const noexcept override
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.3 ATT_EXECUTE_WRITE_REQ.
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode
AttExeWriteReq(const uint8_t flags)
std::string getName() const noexcept override
AttExeWriteReq(const uint8_t *source, const jau::nsize_t length)
constexpr uint8_t getFlags() const noexcept
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.4 ATT_EXECUTE_WRITE_RSP.
AttExeWriteRsp(const uint8_t *source, const jau::nsize_t length)
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode
std::string getName() const noexcept override
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.3 ATT_FIND_BY_TYPE_VALUE_REQ.
AttFindByTypeValueReq(const uint16_t startHandle, const uint16_t endHandle, const jau::uuid16_t &att_type, const jau::uuid_t &att_value)
jau::uuid16_t getAttType() const noexcept
std::string getName() const noexcept override
constexpr uint16_t getEndHandle() const noexcept
constexpr uint16_t getStartHandle() const noexcept
std::unique_ptr< const jau::uuid_t > getAttValue() const noexcept
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle_start + handle_end + att_type
AttFindByTypeValueReq(const uint8_t *source, const jau::nsize_t length)
std::string valueString() const noexcept override
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.4 ATT_FIND_BY_TYPE_VALUE_RSP.
AttFindByTypeValueRsp(const jau::nsize_t total_length)
Create an incomplete response with maximal (MTU) length.
AttFindByTypeValueRsp(const uint8_t *source, const jau::nsize_t length)
void setElementHandles(const jau::nsize_t elementIdx, const uint16_t handle, const uint16_t handle_end)
std::string getName() const noexcept override
void setElementCount(const jau::nsize_t count)
Fixate element count.
uint8_t const * getElementPtr(const jau::nsize_t elementIdx) const
constexpr_cxx20 jau::nsize_t getElementCount() const noexcept
Number of elements.
constexpr jau::nsize_t getElementSize() const noexcept
Returns element size, 4 octets.
uint16_t getElementHandleEnd(const jau::nsize_t elementIdx) const
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode
std::string elementString(const jau::nsize_t idx) const
std::string valueString() const noexcept override
jau::nsize_t getElementPDUOffset(const jau::nsize_t elementIdx) const noexcept
uint16_t getElementHandle(const jau::nsize_t elementIdx) const
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.1 ATT_FIND_INFORMATION_REQ.
std::string valueString() const noexcept override
constexpr uint16_t getStartHandle() const noexcept
AttFindInfoReq(const uint8_t *source, const jau::nsize_t length)
AttFindInfoReq(const uint16_t startHandle, const uint16_t endHandle)
jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle_start + handle_end
constexpr uint16_t getEndHandle() const noexcept
std::string getName() const noexcept override
element := { uint16_t handle, UUID value }, with a UUID of UUID16 or UUID128
Element(const AttFindInfoRsp &p, const jau::nsize_t idx)
const std::unique_ptr< const jau::uuid_t > uuid
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.2 ATT_FIND_INFORMATION_RSP.
std::string elementString(const jau::nsize_t idx) const override
void setElementSize(const uint8_t element_length) override
Fixate element length.
AttFindInfoRsp(const jau::nsize_t total_length)
Create an incomplete response with maximal (MTU) length.
void setElementHandle(const jau::nsize_t elementIdx, const uint16_t h)
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + format
std::string addValueString() const override
jau::uuid_t::TypeSize getElementValueFormat() const
uint16_t getElementHandle(const jau::nsize_t elementIdx) const
std::unique_ptr< const jau::uuid_t > getElementValue(const jau::nsize_t elementIdx) const
jau::nsize_t getElementSize() const override
Returns element size.
std::string getName() const noexcept override
AttFindInfoRsp(const uint8_t *source, const jau::nsize_t length)
void setElementValueUUID(const jau::nsize_t elementIdx, const jau::uuid_t &v)
jau::nsize_t getElementValueSize() const override
Net element-value size, i.e.
Element getElement(const jau::nsize_t elementIdx) const
ATT Protocol PDUs Vol 3, Part F 3.4.7.3.
jau::nsize_t getPDUValueOffset() const noexcept override
opcode
std::string getName() const noexcept override
AttHandleValueCfm(const uint8_t *source, const jau::nsize_t length)
ATT Protocol PDUs Vol 3, Part F 3.4.7.1 and 3.4.7.2.
constexpr uint8_t const * getValuePtr() const noexcept
AttHandleValueRcv(const uint8_t *source, const jau::nsize_t length)
bool isNotification() const noexcept
bool isIndication() const noexcept
jau::TOctetSlice const & getValue() const noexcept
std::string getName() const noexcept override
std::string valueString() const noexcept override
constexpr uint16_t getHandle() const noexcept
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle
AttHandleValueRcv(const bool isNotify, const uint16_t handle, const jau::TROOctets &value, const jau::nsize_t mtu)
AttOpcodeException(std::string const &m, const char *file, int line) noexcept
Handles the Attribute Protocol (ATT) using Protocol Data Unit (PDU) encoded messages over L2CAP chann...
const uint64_t ts_creation
creation timestamp in milliseconds
virtual std::string valueString() const noexcept
static constexpr uint8_t number(const Opcode rhs) noexcept
Opcode
ATT Opcode Summary Vol 3, Part F 3.4.8.
constexpr jau::nsize_t getAuthSigSize() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
AttPDUMsg & operator=(AttPDUMsg &&o) noexcept=delete
static constexpr bool is_request(const ReqRespType rhs) noexcept
jau::POctets pdu
actual received PDU
static std::string getOpcodeString(const Opcode opc) noexcept
Definition: ATTPDUTypes.cpp:78
static constexpr OpcodeType get_type(const Opcode rhs) noexcept
virtual std::string getName() const noexcept
constexpr_cxx20 jau::nsize_t getPDUMinSize() const noexcept
Returns this PDU's minimum size, i.e.
constexpr bool getOpAuthSigFlag() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
virtual std::string toString() const noexcept
static std::unique_ptr< const AttPDUMsg > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
virtual ~AttPDUMsg() noexcept=default
void checkOpcode(const Opcode expected) const
constexpr_cxx20 jau::nsize_t getPDUValueSize() const noexcept
Returns the net octet size of this PDU's attributes value, i.e.
AttPDUMsg & operator=(const AttPDUMsg &o) noexcept=delete
AttPDUMsg(const uint8_t *source, const jau::nsize_t size)
Persistent memory, w/ ownership .
virtual std::string baseString() const noexcept
virtual constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept
Returns the octet offset to the value segment in this PDU including the mandatory opcode,...
void checkOpcode(const Opcode exp1, const Opcode exp2) const
constexpr Opcode getOpcode() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
constexpr Opcode getOpMethod() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
constexpr_cxx20 jau::nsize_t getMaxPDUValueSize(const jau::nsize_t mtu) const noexcept
Returns the theoretical maximum value size of a PDU's attribute value.
AttPDUMsg(AttPDUMsg &&o) noexcept=default
constexpr jau::nsize_t getPDUParamSize() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
AttPDUMsg(const Opcode opc, const jau::nsize_t size)
Persistent memory, w/ ownership .
AttPDUMsg(const AttPDUMsg &o)=default
constexpr bool getOpCommandFlag() const noexcept
ATT PDU Format Vol 3, Part F 3.3.1.
Our own pseudo opcode, indicating no ATT PDU message.
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
Returns the octet offset to the value segment in this PDU including the mandatory opcode,...
std::string getName() const noexcept override
AttPDUUndefined(const uint8_t *source, const jau::nsize_t length)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.6.1 ATT_PREPARE_WRITE_REQ BT Core Spec v5....
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle + value_offset
std::string getName() const noexcept override
AttPrepWrite(const uint8_t *source, const jau::nsize_t length)
AttPrepWrite(const bool isReq, const uint16_t handle, const jau::TROOctets &value, const uint16_t value_offset)
constexpr uint16_t getValueOffset() const noexcept
constexpr jau::TOctetSlice const & getValue() const noexcept
constexpr uint16_t getHandle() const noexcept
std::string valueString() const noexcept override
constexpr uint8_t const * getValuePtr() const noexcept
AttPrepWrite(const bool isReq, const AttPrepWrite &other)
AttPrepWrite(const AttPrepWrite &other)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.5 ATT_BLOB_READ_REQ.
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle + value_offset
constexpr uint16_t getHandle() const noexcept
std::string getName() const noexcept override
AttReadBlobReq(const uint16_t handle, const uint16_t value_offset)
constexpr uint16_t getValueOffset() const noexcept
std::string valueString() const noexcept override
AttReadBlobReq(const uint8_t *source, const jau::nsize_t length)
element := { uint16_t startHandle, uint16_t endHandle, uint8_t value[value-size] }
constexpr jau::nsize_t getValueSize() const noexcept
constexpr uint8_t const * getValuePtr() const noexcept
constexpr uint16_t getEndHandle() const noexcept
Element(const AttReadByGroupTypeRsp &p, const jau::nsize_t idx)
constexpr uint16_t getStartHandle() const noexcept
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.10 ATT_READ_BY_GROUP_TYPE_RSP.
void setElementSize(const uint8_t element_length) override
Fixate element length.
void setElementEndHandle(const jau::nsize_t elementIdx, const uint16_t h)
void setElementValueUUID(const jau::nsize_t elementIdx, const jau::uuid_t &v)
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + element-size
uint16_t getElementStartHandle(const jau::nsize_t elementIdx) const
AttReadByGroupTypeRsp(const uint8_t *source, const jau::nsize_t length)
constexpr_cxx20 jau::nsize_t getElementSize() const noexcept override
Returns size of each element, i.e.
Element getElement(const jau::nsize_t elementIdx) const
constexpr_cxx20 jau::nsize_t getElementValueSize() const noexcept override
Net element-value size, i.e.
std::string getName() const noexcept override
uint16_t getElementEndHandle(const jau::nsize_t elementIdx) const
uint8_t * getElementValuePtr(const jau::nsize_t elementIdx)
std::string elementString(const jau::nsize_t idx) const override
AttReadByGroupTypeRsp(const jau::nsize_t total_length)
Create an incomplete response with maximal (MTU) length.
void setElementStartHandle(const jau::nsize_t elementIdx, const uint16_t h)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.1 ATT_READ_BY_TYPE_REQ.
AttReadByNTypeReq(const bool groupTypeReq, const uint16_t startHandle, const uint16_t endHandle, const jau::uuid_t &uuid)
std::string getName() const noexcept override
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle-start + handle-end
std::unique_ptr< const jau::uuid_t > getNType() const
std::string valueString() const noexcept override
constexpr uint16_t getStartHandle() const noexcept
AttReadByNTypeReq(const uint8_t *source, const jau::nsize_t length)
constexpr uint16_t getEndHandle() const noexcept
element := { uint16_t handle, uint8_t value[value-size] }
constexpr uint16_t getHandle() const noexcept
Element(const AttReadByTypeRsp &p, const jau::nsize_t idx)
constexpr uint8_t const * getValuePtr() const noexcept
constexpr jau::nsize_t getValueSize() const noexcept
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.2 ATT_READ_BY_TYPE_RSP.
Element getElement(const jau::nsize_t elementIdx) const
void setElementHandle(const jau::nsize_t elementIdx, const uint16_t h)
uint16_t getElementHandle(const jau::nsize_t elementIdx) const
std::string getName() const noexcept override
uint8_t * getElementValuePtr(const jau::nsize_t elementIdx)
constexpr_cxx20 jau::nsize_t getElementValueSize() const noexcept override
Net element-value size, i.e.
AttReadByTypeRsp(const jau::nsize_t total_length)
Create an incomplete response with maximal (MTU) length.
constexpr_cxx20 jau::nsize_t getElementSize() const noexcept override
Returns size of each element, i.e.
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + element-size
std::string elementString(const jau::nsize_t idx) const override
void setElementSize(const uint8_t element_length) override
Fixate element length.
AttReadByTypeRsp(const uint8_t *source, const jau::nsize_t length)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.4 ATT_READ_RSP BT Core Spec v5.2: Vol 3,...
std::string valueString() const noexcept override
std::string getName() const noexcept override
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode
constexpr uint8_t const * getValuePtr() const noexcept
AttReadNRsp(const uint8_t *source, const jau::nsize_t length)
constexpr jau::TOctetSlice const & getValue() const noexcept
AttReadNRsp(const bool blobRsp, const jau::TROOctets &value, jau::nsize_t value_offset=0)
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.4.3 ATT_READ_REQ.
std::string valueString() const noexcept override
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle
constexpr uint16_t getHandle() const noexcept
AttReadReq(const uint16_t handle)
std::string getName() const noexcept override
AttReadReq(const uint8_t *source, const jau::nsize_t length)
AttValueException(std::string const &m, const char *file, int line) noexcept
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.3 ATT_WRITE_CMD.
AttWriteCmd(const uint16_t handle, const jau::TROOctets &value)
std::string valueString() const noexcept override
std::string getName() const noexcept override
constexpr jau::TOctetSlice const & getValue() const noexcept
AttWriteCmd(const uint8_t *source, const jau::nsize_t length)
constexpr uint16_t getHandle() const noexcept
constexpr uint8_t const * getValuePtr() const noexcept
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.1 ATT_WRITE_REQ.
constexpr jau::TOctetSlice const & getValue() const noexcept
constexpr uint8_t const * getValuePtr() const noexcept
std::string valueString() const noexcept override
constexpr uint16_t getHandle() const noexcept
std::string getName() const noexcept override
AttWriteReq(const uint16_t handle, const jau::TROOctets &value)
AttWriteReq(const uint8_t *source, const jau::nsize_t length)
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode + handle
BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.5.2 ATT_WRITE_RSP.
AttWriteRsp(const uint8_t *source, const jau::nsize_t length)
std::string getName() const noexcept override
constexpr_cxx20 jau::nsize_t getPDUValueOffset() const noexcept override
opcode
const std::string & message() const noexcept
Persistent endian aware octet data, i.e.
Definition: octets.hpp:560
POctets & resize(const nsize_t newCapacity, const nsize_t newSize)
Resizes this instance, including its capacity.
Definition: octets.hpp:839
RuntimeException(std::string type, std::string const &m, const char *file, int line) noexcept
Transient endian aware octet data slice, i.e.
Definition: octets.hpp:495
std::string toString() const noexcept
Definition: octets.hpp:546
constexpr nsize_t size() const noexcept
Definition: octets.hpp:521
constexpr uint16_t get_uint16_nc(const nsize_t i) const noexcept
Definition: octets.hpp:535
constexpr uint8_t const * get_ptr_nc(const nsize_t i) const noexcept
Definition: octets.hpp:542
constexpr void put_uint16_nc(const nsize_t i, const uint16_t v) noexcept
Definition: octets.hpp:343
constexpr void put_uint8_nc(const nsize_t i, const uint8_t v) noexcept
Definition: octets.hpp:335
uint8_t * get_wptr() noexcept
Definition: octets.hpp:474
void put_uint16(const nsize_t i, const uint16_t v)
Definition: octets.hpp:339
void put_uuid(const nsize_t i, const uuid_t &v)
Definition: octets.hpp:466
void put_bytes(const nsize_t i, const uint8_t *source, const nsize_t byte_count)
Definition: octets.hpp:412
void put_uint8(const nsize_t i, const uint8_t v)
Definition: octets.hpp:331
Transient read only and endian aware octet data, i.e.
Definition: octets.hpp:67
constexpr uint16_t get_uint16_nc(const nsize_t i) const noexcept
Definition: octets.hpp:184
std::unique_ptr< const uuid_t > get_uuid(const nsize_t i, const uuid_t::TypeSize tsize) const
Definition: octets.hpp:267
constexpr nsize_t size() const noexcept
Returns the used memory size for read and write operations, may be zero.
Definition: octets.hpp:162
uuid16_t get_uuid16_nc(const nsize_t i) const noexcept
Definition: octets.hpp:255
uint16_t get_uint16(const nsize_t i) const
Definition: octets.hpp:180
void check_range(const nsize_t i, const nsize_t count, const char *file, int line) const
Definition: octets.hpp:148
constexpr uint8_t get_uint8_nc(const nsize_t i) const noexcept
Definition: octets.hpp:168
constexpr uint8_t const * get_ptr() const noexcept
Definition: octets.hpp:272
constexpr uint8_t const * get_ptr_nc(const nsize_t i) const noexcept
Definition: octets.hpp:277
std::string toString() const noexcept override
Returns the string representation in BE network order, i.e.
Definition: uuid.cpp:135
static TypeSize toTypeSize(const jau::nsize_t size)
Definition: uuid.cpp:47
static constexpr jau::nsize_t number(const TypeSize rhs) noexcept
Definition: uuid.hpp:63
virtual jau::nsize_t put(uint8_t *const buffer, lb_endian_t const le_or_be) const noexcept=0
TypeSize getTypeSize() const noexcept
Definition: uuid.hpp:125
TypeSize
Underlying integer value present octet count.
Definition: uuid.hpp:60
std::string getTypeSizeString() const noexcept
Definition: uuid.hpp:127
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: '.
Definition: debug.hpp:109
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
Definition: byte_util.hpp:227
@ little
Identifier for little endian, equivalent to endian::little.
std::string to_string(const alphabet &v) noexcept
Definition: base_codec.hpp:97
#define constexpr_cxx20
constexpr qualifier replacement for C++20 constexpr.
constexpr T min(const T x, const T y) noexcept
Returns the minimum of two integrals (w/ branching) in O(1)
Definition: base_math.hpp:177
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
Definition: base_math.hpp:191
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.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:64
STL namespace.