diff options
Diffstat (limited to 'include/ble/att.h')
-rw-r--r-- | include/ble/att.h | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/include/ble/att.h b/include/ble/att.h new file mode 100644 index 0000000..3c7914f --- /dev/null +++ b/include/ble/att.h @@ -0,0 +1,186 @@ +#pragma once + +#include <experimental/optional> +#include <variant> +#include <vector> + +#include "ble/ByteBuffer.h" +#include "ble/misc.h" + +namespace trygvis { +namespace bluetooth { + +template<typename T> +using o = std::experimental::optional<T>; + +/** + * BLUETOOTH SPECIFICATION Version 4.0 [Vol 3] - Attribute Protocol (ATT) - 3.4.8 Attribute Opcode Summary + * Table 3.37 + */ +enum AttPduType { + ERROR = 0x01, + EXCHANGE_MTU_REQ = 0x02, + EXCHANGE_MTU_RES = 0x03, + FIND_INFORMATION_REQ = 0x04, + FIND_INFORMATION_RES = 0x05, + FIND_BY_TYPE_VALUE_REQ = 0x06, + FIND_BY_TYPE_VALUE_RES = 0x07, + READ_BY_TYPE_REQ = 0x08, + READ_BY_TYPE_RES = 0x09, + READ_REQ = 0x0a, + READ_RES = 0x0b, + READ_BLOB_REQ = 0x0c, + READ_BLOB_RES = 0x0d, + READ_MULTIPLE_REQ = 0x0e, + READ_MULTIPLE_RES = 0x0f, + READ_BY_GROUP_TYPE_REQ = 0x10, + READ_BY_GROUP_TYPE_RES = 0x11, + WRITE_REQ = 0x12, + WRITE_RES = 0x13, + + WRITE_CMD = 0x52, + PREPARE_WRITE_REQ = 0x16, + PREPARE_WRITE_RES = 0x17, + EXECUTE_WRITE_REQ = 0x18, + EXECUTE_WRITE_RES = 0x19, + HANDLE_VALUE_NOTIFICATION = 0x1b, + HANDLE_VALUE_INDICATION = 0x1d, + HANDLE_VALUE_CONFIRMATION = 0x1e, + SIGNED_WRITE_COMMAND = 0xd2, +}; + +std::string to_string(AttPduType t); + +class AttributeData; + +/** + * Application Error 0x80 – 0xFF Application error code defined by a higher layer specification. + * + * BLUETOOTH SPECIFICATION Version 4.0 [Vol 3] - 3.4.1.1 Error Response - Table 3.3 + */ +enum ErrorCode : uint8_t { + INVALID_HANDLE = 0x01, ///< The attribute handle given was not valid on this server. + READ_NOT_PERMITTED = 0x02,///< The attribute cannot be read. + WRITE_NOT_PERMITTED = 0x03,///< The attribute cannot be written. + INVALID_PDU = 0x04, ///<The attribute PDU was invalid. + INSUFFICIENT_AUTHENTICATION = 0x05, ///<The attribute requires authentication before it can be read or written. + REQUEST_NOT_SUPPORTED = 0x06, ///<Attribute server does not support the request received from the client. + INVALID_OFFSET = 0x07, ///<Offset specified was past the end of the attribute. + INSUFFICIENT_AUTHORIZATION = 0x08, ///<The attribute requires authorization before it can be read or written. + PREPARE_QUEUE_FULL = 0x09, ///<Too many prepare writes have been queued. + ATTRIBUTE_NOT_FOUND = 0x0a, ///<No attribute found within the given attribute handle range. + ATTRIBUTE_NOT_LONG = 0x0b, ///<The attribute cannot be read or written using the Read Blob Request + INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0c, ///<The Encryption Key Size used for encrypting this link is insufficient. + INVALID_ATTRIBUTE_VALUE_LENGTH = 0x0d, ///<The attribute value length is invalid for the operation + UNLIKELY_ERROR = 0x0e, ///<The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested. + INSUFFICIENT_ENCRYPTION = 0x0f, ///<The attribute requires encryption before it can be read or written. + UNSUPPORTED_GROUP_TYPE = 0x10, ///<The attribute type is not a supported grouping attribute as defined by a higher layer specification. + INSUFFICIENT_RESOURCES = 0x11, ///<Insufficient Resources to complete the request Reserved 0x012 – 0x7F Reserved for future use. +}; + +struct ErrorRes { + static constexpr auto att_pdu_type = AttPduType::EXCHANGE_MTU_REQ; + + /** + * The request that generated this error response. + */ + uint8_t requestOpcode; + + /** + * The attribute handle that generated this error response. + */ + uint16_t attributeHandle; + + /** + * The reason why the request has generated an error response. + */ + uint8_t errorCode; + + static ErrorRes parse(ByteBuffer& buffer) { + return {buffer.read8(), buffer.read16le(), buffer.read8()}; + } +}; + +struct ExchangeMtuReq { + static constexpr auto att_pdu_type = AttPduType::EXCHANGE_MTU_REQ; + + uint16_t clientRxMtu; +}; + +struct ExchangeMtuRes { + static constexpr auto att_pdu_type = AttPduType::EXCHANGE_MTU_RES; + + uint16_t serverRxMtu; +}; + +struct ReadByGroupTypeRes { + static constexpr auto att_pdu_type = AttPduType::READ_BY_GROUP_TYPE_RES; + + std::vector<AttributeData> attributes; +}; + +struct ReadByTypeRes { + static constexpr auto att_pdu_type = AttPduType::READ_BY_TYPE_RES; + + std::vector<AttributeData> attributes; +}; + +using AttVariant = std::variant<std::monostate, + ErrorRes, + ExchangeMtuReq, ExchangeMtuRes, + ReadByGroupTypeRes, ReadByTypeRes>; + +o<AttPduType> attPduType(const AttVariant& v); + +class AttPdu { +public: + explicit AttPdu(ByteBuffer &bytes); + + AttPdu(ByteBuffer &bytes, AttPduType type); + + AttPduType getType(); + + static AttVariant parse(ByteBuffer &bytes); + + static ExchangeMtuReq parseExchangeMtuReq(ByteBuffer &bytes); + static ExchangeMtuRes parseExchangeMtuRes(ByteBuffer &bytes); + + static void parseRead(ByteBuffer &bytes); + + static void parseWrite(ByteBuffer &bytes); + + static void makeExchangeMtuRes(ByteBuffer &bytes, uint16_t serverRxMtu); + + static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid); + + static void makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, ShortUuid uuid); + + static void makeRead(ByteBuffer &bytes, uint16_t handle); + + static void makeWrite(ByteBuffer &req, uint16_t handle, const ByteBuffer &bytes); + +private: +// static void checkType(ByteBuffer &bytes, AttPduType type); + + static std::vector<AttributeData> parseAttributeData(ByteBuffer &bytes); + + ByteBuffer &bytes; +}; + +class AttributeData { +public: + ~AttributeData(); + + static AttributeData fromByteBuffer(ByteBuffer &value); + + const uint16_t handle; + ByteBuffer value; + +private: + AttributeData(uint16_t handle, ByteBuffer value, std::shared_ptr<uint8_t[]> raw); + + std::shared_ptr<uint8_t[]> raw; +}; + +} // namespace bluetooth +} // namespace trygvis |