Antilatency Device Network Library

Antilatency Device Network Library

Библиотека для взаимодействия с устройствами Antilatency, работающими по протоколу ADN.
Прежде, чем начать:

Содержание

Возможности библиотеки

Библиотека DeviceNetwork позволяет работать с устройствами, поддерживающими протокол ADN. Она формирует иерархию подключённых устройств и абстрагирует пользователя от деталей их физического подключения. Так, в текущей версии ADN поддерживается подключение устройств по USB и при помощи IP-сети. Кроме того, некоторые устройства могут быть подключены через другие устройства (например, по радиопротоколу).
Библиотека предоставляет относительно низкоуровневый интерфейс для работы с ADN-устройствами. Основные функции библиотеки:

Использование библиотеки

Все библиотеки, которые используются для работы с устройствами Antilatency, взаимодействуют с библиотекой DeviceNetwork.
Стандартный сценарий использования DeviceNetwork:
  1. загрузка библиотеки;
  2. получение ILibrary;
  3. создание пустого фильтра устройств IDeviceFilter c помощью createFilter;
  4. добавление в фильтр IDeviceFilter необходимых USB и IP устройств методами addUsbDevice и addIpDevice;
  5. создание экземпляра сети INetwork с ранее заполненным фильтром – createNetwork;
  6. отслеживание изменений UpdateId с помощью getUpdateId;
  7. по необходимости: чтение свойств различных устройств;
  8. поиск устройств, которые поддерживают необходимый Task, и запуск этого таска.
Разобрать сценарий использования можно в примере на C# или C++.
Данное демо-приложение выводит информацию о подключенных узлах дерева ADN при каждом изменении UpdateId. Для дерева устройств, состоящего из Universal Radio Socket с Alt и Bracer без Alt, приложение вывело следующую информацию:

ILibrary

В ILibrary пользователь может узнать текущую версию библиотеки с помощью getVersion и задать необходимый уровень LogLevel с помощью setLogLevel. По умолчанию LogLevel=Off.
Для создания сети ADN необходимо создать и заполнить фильтр устройств IDeviceFilter, с помощью которого будут выбираться устройства для добавления в сеть INetwork. После создания фильтра и добавления в него устройств можно создать экземпляр INetwork используя ILibrary.createNetwork.
Нельзя создать экземпляр INetwork с пустым фильтром.

IDeviceFilter

IDeviceFilter проводит отбор устройств для подключения к конкретному экземпляру INetwork. Фильтр работает по принципу добавления: он создаётся пустым, затем в него нужно добавить маски устройств, которые следует подключить к экземпляру ADN.
Сначала создайте IDeviceFilter методом ILibrary.createFilter, затем добавьте туда USB-устройства addUsbDevice и IP-устройства addIpDevice. В один фильтр можно добавить оба типа устройств.
Пример на C#:
/*
 * Get a device filter for Antilatency USB Sockets (HMD Radio Socket and Wired USB Socket).
 */
private static Antilatency.DeviceNetwork.IDeviceFilter GetAntilatencyUsbSocketDevicesFilter(Antilatency.DeviceNetwork.ILibrary deviceNetworkLibrary) {
    var result = deviceNetworkLibrary.createFilter();

    var usbDeviceFilter = new Antilatency.DeviceNetwork.UsbDeviceFilter() {
        vid = UsbVendorId.Antilatency, pid = 0x0000, pidMask = 0xFFFF
    };
    result.addUsbDevice(usbDeviceFilter);
    
    return result;
}

В подавляющем большинстве случаев достаточно создать фильтр для всех устройств, используя константы: AllUsbDevices, AllIpDevicesMask и AllIpDevicesIp.
Примеры на C#:
#region DeviceFilter samples
/*
 * Get a device filter for all Antilatency USB devices.
 */
private static Antilatency.DeviceNetwork.IDeviceFilter GetAllUsbDevicesFilter(Antilatency.DeviceNetwork.ILibrary deviceNetworkLibrary) {
    var result = deviceNetworkLibrary.createFilter();
    result.addUsbDevice(Antilatency.DeviceNetwork.Constants.AllUsbDevices);
    return result;
}

/*
 * Get a device filter for all IP devices.
 */
private static Antilatency.DeviceNetwork.IDeviceFilter GetAllIpDevicesFilter(Antilatency.DeviceNetwork.ILibrary deviceNetworkLibrary) {
    var result = deviceNetworkLibrary.createFilter();
    result.addIpDevice(Antilatency.DeviceNetwork.Constants.AllIpDevicesIp, Antilatency.DeviceNetwork.Constants.AllIpDevicesMask);
    return result;
}

После создания INetwork пользователь может получить IDeviceFilter методом INetwork.getDeviceFilter и проверить используемые маски и устройства с помощью getIpDeviceMask, getIpDevice и getUsbDevice. После создания экземпляра INetwork фильтр можно только просматривать, но не изменять.
IDeviceFilter позволяет распределить подключённые устройства по нескольким экземплярам ADN, запущенным на одном Host. Для этого нужно создать столько же непересекающихся фильтров, сколько работающих одновременно экземпляров ADN. Нельзя создать объекты INetwork с пересекающимися фильтрами.

Маски для фильтра устройств

USB-устройства определяются с помощью Vendor ID и Product ID (VID&PID), где Vendor ID — это идентификатор производителя (зарегистрированный в USB IF), Product ID — идентификатор конкретной модели устройства. Vendor ID устройств Antilatency = 0x3237, и эту константу можно получить из UsbVendorId.
Далее, чтобы добавить одно или несколько устройств в фильтр, нужно задать pid-маски. Рассмотрим заданный pid (Target Pid), маску (Mask) и возможные pid устройств (Possible Device Pid). Каждая 1 в маске означает, что этот бит в pid подключенного устройства должен быть равен соответствующему биту в заданном pid (Target Pid). 0 в маске означает, что соответствующий бит может принимать любое значение. Смотрите на примере:
Для IP-устройств действует аналогичное правило составления маски, как и для USB-устройств.
Изменить значение свойства usb/Pid устройств Antilatency можно в AntilatencyService.

INetwork

С помощью INetwork можно восстановить иерархию подключения всех устройств, так как для каждого узла можно узнать его родителя. Для этого воспользуйтесь getNodes и nodeGetParent.
Ещё одна функция INetwork – работа со свойствами узлов.
Подробнее работа со свойствами и кэшем свойств описана в статье про ADN и в разделе IPropertyCotask.
Кроме того, INetwork используется при работе с тасками (Task) устройств. Методы INetwork не используются напрямую для запуска тасков, для этого разработан механизм котасков и котаск-конструкторов.

INetwork: синхронизация времени

Начиная с версии Antilatency SDK 4.0.0, в библиотеке ADN появилась поддержка синхронизации времени для USB-устройств. В INetwork добавлены новые методы:
Мы используем адаптивный алгоритм, который выполняет периодическую синхронизацию времени с устройством Antilatency. В результате мы получаем совпадение времени между приложением и устройствами с точностью около 100-200 микросекунд. Совпадение времени на радиоустройствах достигается с точностью около 10 микросекунд.

NodeStatus

NodeStatus – это состояние узла, которое следует проверять перед запуском какого‑либо таска. Значения TaskRunning и Idle показывают, выполняется ли в данный момент какой‑либо таск на данном узле или нет. Если устройство было отключено или стало недоступно, то на запрос nodeGetStatus будет получено значение Invalid, и на этом устройстве нельзя запустить какой‑либо таск. По умолчанию, при подключении устройства его NodeStatus будет Idle.

UpdateId

В библиотеке существует специальный счётчик UpdateId. Этот счётчик инкрементируется каждый раз, когда подключается/отключается какое-либо устройство и когда запускается/завершается таск на любом узле. Узнать текущее значение счётчика можно методом INetwork.getUpdateId. Инкрементация счётчика может сигнализировать об изменениях в экземпляре INetwork: следует обновить список подключенных устройств getNodes и проверить их состояние nodeGetStatus.

ICotask и ICotaskConstructor

Таск, котаск и котаск-конструктор (Task, Cotask, CotaskConstructor) – это взаимосвязанные инструменты SDK для управления функциями и задачами устройств. К каждому таску привязан свой котаск (возможно не один) и его котаск-конструктор.
Котаск — связующее звено между таском (Task) и пользователем. Котаск скрывает в себе передачу данных, логику работы и предоставляет интерфейс для работы с таском. Чтобы получить котаск, нужно сначала создать экземпляр ICotaskConstructor. Котаск-конструктор проверяет узлы на поддержку таска и запускает этот таск, возвращает экземпляр ICotask.
Подробнее про работу котасков и котаск-конструкторов можно прочитать здесь.
Библиотека DeviceNetwork содержит интерфейсы ICotask и ICotaskConstructor. Все котаски других библиотек наследуют метод ICotask.isTaskFinished, который проверяет, завершился ли соответствующий таск. Все котаск-конструкторы наследуют методы isSupported (поддерживается ли конкретный таск) и findSupportedNodes (найти узлы, которые его поддерживают). Методы ICotaskConstructor перекрывают низкоуровневые методы интерфейса INetwork: явное использование nodeIsTaskSupported и nodeStartTask не требуется.

IPropertyCotask

Котаск для работы со свойствами устройств. IPropertyCotask запускается с помощью INetwork.nodeStartPropertyTask. Так как это тоже таск, на устройстве нужно сначала завершить предыдущий таск и затем запустить этот. Соответственно при чтении свойств используются значения непосредственно с устройства, а не из кэша свойств, кэш автоматически обновляется.
IPropertyCotask позволяет читать, писать и удалять конкретные свойства. Кроме того, можно получить имя свойства getPropertyKey по индексу, что позволяет узнать полный набор свойств на устройстве.

IPropertyCotask: асинхронные методы

В SDK 4.2.0 добавлены копии методов IPropertyCotask, но с окончанием Deferred. Это асинхронные варианты одноимённых методов, которые не блокируют вызывающий их поток. Пример: метод для удаления свойства доступен в вариантах deleteProperty и deletePropertyDeferred.
Новые методы возвращают интерфейс IFuture или его производные, например IFutureString. Это позволяет заказать чтение, запись или удаление свойства, не останавливая поток на выполнение этой операции. Вместо этого, можно позже обратиться к объекту IFuture и проверить, завершилась ли операция, или подождать на этом объекте её завершения.
Все объекты интерфейса IFuture (и его производных) имеют два метода:
  • isDone сигнализирует о завершении операции (в том числе безуспешном). Возвращает false, только если операция ещё не завершена;
  • wait – ожидать завершения операции.

Исключения и ошибки

Полезные ссылки