| # Copyright 2021-2022 Google LLC |
| # |
| # 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 |
| # |
| # https://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. |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Imports |
| # ----------------------------------------------------------------------------- |
| import struct |
| from typing import Tuple |
| |
| from ..gatt import ( |
| GATT_DEVICE_INFORMATION_SERVICE, |
| GATT_FIRMWARE_REVISION_STRING_CHARACTERISTIC, |
| GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC, |
| GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC, |
| GATT_MODEL_NUMBER_STRING_CHARACTERISTIC, |
| GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC, |
| GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC, |
| GATT_SYSTEM_ID_CHARACTERISTIC, |
| GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC, |
| Service, |
| Characteristic, |
| DelegatedCharacteristicAdapter, |
| UTF8CharacteristicAdapter |
| ) |
| |
| |
| # ----------------------------------------------------------------------------- |
| class DeviceInformationService(Service): |
| @staticmethod |
| def pack_system_id(oui, manufacturer_id): |
| return struct.pack('<Q', oui << 40 | manufacturer_id) |
| |
| @staticmethod |
| def unpack_system_id(buffer): |
| system_id = struct.unpack('<Q', buffer)[0] |
| return (system_id >> 40, system_id & 0xFFFFFFFFFF) |
| |
| def __init__( |
| self, |
| manufacturer_name: str = None, |
| model_number: str = None, |
| serial_number: str = None, |
| hardware_revision: str = None, |
| firmware_revision: str = None, |
| software_revision: str = None, |
| system_id: Tuple[int, int] = None, # (OUI, Manufacturer ID) |
| ieee_regulatory_certification_data_list: bytes = None |
| # TODO: pnp_id |
| ): |
| characteristics = [ |
| Characteristic( |
| uuid, |
| Characteristic.READ, |
| Characteristic.READABLE, |
| field |
| ) |
| for (field, uuid) in ( |
| (manufacturer_name, GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC), |
| (model_number, GATT_MODEL_NUMBER_STRING_CHARACTERISTIC), |
| (serial_number, GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC), |
| (hardware_revision, GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC), |
| (firmware_revision, GATT_FIRMWARE_REVISION_STRING_CHARACTERISTIC), |
| (software_revision, GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC) |
| ) |
| if field is not None |
| ] |
| |
| if system_id is not None: |
| characteristics.append(Characteristic( |
| GATT_SYSTEM_ID_CHARACTERISTIC, |
| Characteristic.READ, |
| Characteristic.READABLE, |
| self.pack_system_id(*system_id) |
| )) |
| |
| if ieee_regulatory_certification_data_list is not None: |
| characteristics.append(Characteristic( |
| GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC, |
| Characteristic.READ, |
| Characteristic.READABLE, |
| ieee_regulatory_certification_data_list |
| )) |
| |
| super().__init__(GATT_DEVICE_INFORMATION_SERVICE, characteristics) |
| |
| |
| # ----------------------------------------------------------------------------- |
| class DeviceInformationServiceProxy: |
| def __init__(self, service_proxy): |
| self.service_proxy = service_proxy |
| |
| for (field, uuid) in ( |
| ('manufacturer_name', GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC), |
| ('model_number', GATT_MODEL_NUMBER_STRING_CHARACTERISTIC), |
| ('serial_number', GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC), |
| ('hardware_revision', GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC), |
| ('firmware_revision', GATT_FIRMWARE_REVISION_STRING_CHARACTERISTIC), |
| ('software_revision', GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC) |
| ): |
| if characteristics := service_proxy.get_characteristics_by_uuid(uuid): |
| characteristic = UTF8CharacteristicAdapter(characteristics[0]) |
| else: |
| characteristic = None |
| self.__setattr__(field, characteristic) |
| |
| if characteristics := service_proxy.get_characteristics_by_uuid(GATT_SYSTEM_ID_CHARACTERISTIC): |
| self.system_id = DelegatedCharacteristicAdapter( |
| characteristics[0], |
| encode=lambda v: DeviceInformationService.pack_system_id(*v), |
| decode=DeviceInformationService.unpack_system_id |
| ) |
| else: |
| self.system_id = None |
| |
| if characteristics := service_proxy.get_characteristics_by_uuid(GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC): |
| self.ieee_regulatory_certification_data_list = characteristics[0] |
| else: |
| self.ieee_regulatory_certification_data_list = None |