# # Copyright 2022 aiohomekit team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # from __future__ import annotations import logging import struct from enum import Enum from aiohomekit.enum import EnumWithDescription logger = logging.getLogger(__name__) class OpCode(Enum): CHAR_SIG_READ = 0x01 CHAR_WRITE = 0x02 CHAR_READ = 0x03 CHAR_TIMED_WRITE = 0x04 CHAR_EXEC_WRITE = 0x05 SERV_SIG_READ = 0x06 UNK_09_READ_GATT = 0x09 UNK_0B_SUBSCRIBE = 0x0B UNK_0C_UNSUBSCRIBE = 0x0C class PDUStatus(EnumWithDescription): SUCCESS = 0, "Success" UNSUPPORTED_PDU = 1, "Unsupported PDU" MAX_PROCEDURES = 2, "Max procedures" INSUFFICIENT_AUTHORIZATION = 3, "Insufficient authorization" INVALID_INSTANCE_ID = 4, "Invalid instance ID" INSUFFICIENT_AUTHENTICATION = 5, "Insufficient authentication" INVALID_REQUEST = 6, "Invalid request" # custom error states TID_MISMATCH = 256, "Transaction ID mismatch" BAD_CONTROL = 257, "Control field doesn't have expected bits set" def encode_pdu(opcode: OpCode, tid: int, iid: int, data: bytes) -> bytes: buf = struct.pack(" bytes: iids_data = zip(iids, data) req_pdu = b"".join( [ encode_pdu( opcode, idx, iid_data[0], iid_data[1], ) for (idx, iid_data) in enumerate(iids_data) ] ) return req_pdu def decode_pdu(expected_tid: int, data: bytes) -> tuple[int, bytes | PDUStatus]: control, tid, status, body_len = struct.unpack(" list[tuple[int, bytes | PDUStatus]]: idx = starting_tid offset = 0 res = [] while True: body_len, body = decode_pdu(idx, data[offset:]) res.append(body) idx += 1 offset += 5 + body_len if offset >= len(data): break return res