Чтение GATT-характеристик Bluetooth устройства

в 12:15, , рубрики: Action Script, actionscript 3.0, adobe air, Adobe Native Extension, bluetooth le, flash, Flash-платформа, Блог компании Mail.Ru Group, Программирование, метки: , , , ,

Привет, читатели!

Работая над своей ANE библиотекой для работы с Bluetooth LE в AIR приложении для iOS+OSX, обнаружил что помимо ваших собственных сервисов и характеристик для обмена информацией, у bluetooth-устройств есть стандартные. Статья о том, как считывать информацию с этих характеристик. Скажу сразу я не большой знаток bluetooth и всего что с ним связано, и для мне все это в новинку :) Поехали…

Сервисы и характеристики OSX устройства

Сканируя сервисы и характеристики своего macbook, увидел следующие сервисы:

  • UUID: 180A — Device Information
  • UUID: D0611E78-BBB4-4591-A5F8-487910AE4366 — Continuity
  • ...

Сервис Continuity

Сервис Continuity служит для передачи данных между связанными Apple устройствами, подробнее здесь: www.apple.com/ru/ios/whats-new/continuity/. Если будет время разобраться в формате передаваемых данных — напишу об этом отдельный пост.

Сервис 180A (Device Information)

Рассмотрим сервис 180A — информация об устройстве. Этот сервис является часть GATT-профиля. Открываем страницу GATT-сервисов, находим сервис по идентификатору 180A. В списке доступных указаны различные характеристики:

  • Manufacturer Name String
  • Model Number String
  • … и еще много всего

Конкретно мое устройство показало только две доступные характеристики:

  • UUID: 2A29 — Manufacturer Name String
  • UUID: 2A24 — Model Number String

Открываем страницу GATT-характеристик, находим там нужную характеристику по uuid, например 2A29. В описании сказано что характеристика имеет одно единственное поле и оно имеет формат utf8s:
Чтение GATT-характеристик Bluetooth устройства - 1
Это значит что прочитать значение в AIR приложении можно следующим способом:

var bytes:ByteArray = ...;
var string:String = bytes.readUTFBytes(bytes.bytesAvailable);

В моем случае я получил значения:

2A29 - Apple Inc
2A24 - MacBookPro10,2

С этими характеристиками было все просто, идем дальше.

Сервисы и характеристики iOS устройства

Попробуем теперь сканировать iOS устройство и заглянуть какие данные оно предоставляет. Мой iPhone показал мне следующие сервисы:

  • UUID: 180F
  • UUID: 1805
  • UUID: 7905F431-B5CE-4E99-A40F-4B1E122D00D0

Сервис 7905F431-B5CE-4E99-A40F-4B1E122D00D0, это сервис центра уведомлений Apple, подробнее здесь: developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Specification/Specification.html. Будет время, попробую разобраться в формате данных и напишу отдельный пост по работе с bluetooth-сервисами устройств Apple.

Сервис 180F (Battery Service)

Сервис 180F — это информация о заряде батареи. Этот сервис имеет одну единственную характеристику 2A19, в описании которой сказано что характеристика имеет одно единственное поле формата uint8:
Чтение GATT-характеристик Bluetooth устройства - 2
Прочитать эту информацию в AIR приложении можно так:

var bytes:ByteArray = ...;
var level:int = bytes.readByte();

Получим значение от 0 до 100, соответствующее уровню заряда батареи устройства.

Сервис 1805 (Current Time Service)

Как видим из описания сервиса 1805 — это информация о текущем времени. Мое iOS устройство показало только две характеристики у этого сервиса:

  • UUID: 2A0F — Local Time Information
  • UUID: 2A2B — Current Time

Характеристика 2A0F (Local Time Information)

Характеристика 2A0F имеет два поля:
Чтение GATT-характеристик Bluetooth устройства - 3

Открываем описание первого поля Time Zone и видим что оно содержит в себе одно поле формата sint8.

Второе поле у сервиса 2A0F это Daylight Saving Time — информация о переходе на летнее время, формат: uint8.

Итак, чтобы прочитать характеристику 2A0F в AIR приложении используем следующий код:

var bytes:ByteArray = ...;
var timeZoneValue:int = bytes.readByte(); // считываем Time Zone
var dstValue:int = bytes.readUnsignedByte(); // считываем Daylight Saving Time

В моем случае я получил значения:

TimeZone: 12
Daylight Saving Time: 0

Значение 12 в поле TimeZone соответствует временной зоне UTC+3:00, согласно XML файлу:

Список временных зон в XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2011 Bluetooth SIG, Inc. All rights reserved. -->
<Characteristic xsi:noNamespaceSchemaLocation="http://schemas.bluetooth.org/Documents/characteristic.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Time Zone" type="org.bluetooth.characteristic.time_zone" uuid="2A0E">
	<InformativeText>
	</InformativeText>
	<Value>
		<Field name="Time Zone">
			<Requirement>Mandatory</Requirement>
			<Format>sint8</Format>
			<Minimum>-48</Minimum>
			<Maximum>56</Maximum>
			<Enumerations>
				<Enumeration key="-48" value="UTC-12:00" />
				<Enumeration key="-44" value="UTC-11:00" />
				<Enumeration key="-40" value="UTC-10:00" />
				<Enumeration key="-38" value="UTC-9:30" />
				<Enumeration key="-36" value="UTC-9:00" />
				<Enumeration key="-32" value="UTC-8:00" />
				<Enumeration key="-28" value="UTC-7:00" />
				<Enumeration key="-24" value="UTC-6:00" />
				<Enumeration key="-20" value="UTC-5:00" />
				<Enumeration key="-18" value="UTC-4:30" />
				<Enumeration key="-16" value="UTC-4:00" />
				<Enumeration key="-14" value="UTC-3:30" />
				<Enumeration key="-12" value="UTC-3:00" />
				<Enumeration key="-8" value="UTC-2:00" />
				<Enumeration key="-4" value="UTC-1:00" />
				<Enumeration key="0" value="UTC+0:00" />
				<Enumeration key="4" value="UTC+1:00" />
				<Enumeration key="8" value="UTC+2:00" />
				<Enumeration key="12" value="UTC+3:00" />
				<Enumeration key="14" value="UTC+3:30" />
				<Enumeration key="16" value="UTC+4:00" />
				<Enumeration key="18" value="UTC+4:30" />
				<Enumeration key="20" value="UTC+5:00" />
				<Enumeration key="22" value="UTC+5:30" />
				<Enumeration key="23" value="UTC+5:45" />
				<Enumeration key="24" value="UTC+6:00" />
				<Enumeration key="26" value="UTC+6:30" />
				<Enumeration key="28" value="UTC+7:00" />
				<Enumeration key="32" value="UTC+8:00" />
				<Enumeration key="35" value="UTC+8:45" />
				<Enumeration key="36" value="UTC+9:00" />
				<Enumeration key="38" value="UTC+9:30" />
				<Enumeration key="40" value="UTC+10:00" />
				<Enumeration key="42" value="UTC+10:30" />
				<Enumeration key="44" value="UTC+11:00" />
				<Enumeration key="46" value="UTC+11:30" />
				<Enumeration key="48" value="UTC+12:00" />
				<Enumeration key="51" value="UTC+12:45" />
				<Enumeration key="52" value="UTC+13:00" />
				<Enumeration key="56" value="UTC+14:00" />
			</Enumerations>
            <AdditionalValues>
				<Enumeration key="-128" value="time zone offset is not known"/>
			</AdditionalValues> 
		</Field>
	</Value>
</Characteristic>

cкачать который можно в описании поля Time Zone нажав кнопку Download / View напротив имени поля.

Характеристика 2A2B (Current Time)

Характеристика 2A2B представляет текущее время на устройстве, и она имеет многоуровневую вложенность полей, ознакомиться с описаниями и форматами которых вы можете самостоятельно. Я приведу только код, для считывания полной информации о текущем времени устройства:

var bytes:ByteArray = ...;
bytes.endian = Endian.LITTLE_ENDIAN;
//
var year:int = b.readUnsignedShort(); // год 
var month:int = b.readUnsignedByte(); // месяц (начинается с 1)
var day:int = b.readUnsignedByte(); // день  (начинается с 1)
var hours:int = b.readUnsignedByte(); // часы
var minutes:int = b.readUnsignedByte(); // минуты
var seconds:int = b.readUnsignedByte(); // секунды
//
var dayOfWeek:int = b.readUnsignedByte(); // день недели  (начинается с 0)
var fraction:int = b.readUnsignedByte(); // миллисекунды
var adjustReason:int = b.readUnsignedByte(); // ???

Здесь есть несколько важных моментов.
Первое: в примечаниях всех GATT спецификаций сказано:

The fields in the above table are in the order of LSO to MSO. Where LSO = Least Significant Octet and MSO = Most Significant Octet. 

Это значит что в ByteArray первым идет младший байт, в AIR это можно указать с помощью свойства endian:

bytes.endian = Endian.LITTLE_ENDIAN;

Второе: поле fraction, как следует из описания — это 1/256я секунды, т.е. чтобы получить миллисекунды пишем код:

var milliseconds:int = Math.floor(fraction/256*1000);

И третье: я так и не разобрался что такое Adjust Reason. Кто знает — поделитесь информацией :).

Ссылки:

  • GATT сервисы
  • GATT характеристики
  • Видео, демонстрирующие чтение GATT-характеристик с OSX и iOS устройств в AIR приложении
  • ANE библиотека для работы с Bluetooth в AIR приложении. Там же есть готовые iOS и OSX приложения для сканирования сервисов и получения информации с имеющихся характеристик

Автор: FlashPress

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js