Поиск на сайте: Расширенный поиск


Новые программы oszone.net Читать ленту новостей RSS
Программа для обнаружения и удаления вредоносных шпионских модулей, таких как программы шпионы (spyware), рекламные банн...
Программа для расширения возможностей веб-камеры, которая позволяет не просто настраивать вашу веб-камеру, но и накладыв...
Vivaldi — это гибкий, настраиваемый браузер, для которого «пользователь на первом месте», утверждают создатели, во главе...
Проигрыватель аудио-файлов. Не смотря на свой маленький размер, программа имеет довольно широкие функции: проигрывание ф...
Программа для обеспечения безопасности при подключении к точкам доступа Wi-Fi. Hotspot Shield создает частную виртуальну...
OSzone.net Microsoft Разработка приложений Windows (до Windows 10) Создание HID-датчика на основе Netduino для WinRT RSS

Создание HID-датчика на основе Netduino для WinRT

Текущий рейтинг: 3.2 (проголосовало 5)
 Посетителей: 735 | Просмотров: 898 (сегодня 0)  Шрифт: - +

Протокол HID (Human Interface Device) изначально предназначался для того, чтобы упростить использование устройств вроде мыши, клавиатуры и джойстика. Однако из-за его уникальных особенностей, в том числе возможностей, не требующих дополнительного описания, производители оборудования стали использовать этот протокол для поддержки медицинских приборов и оборудования, а также для пользовательских датчиков. Если вы новичок в HID API, обратитесь на сайт USB HID Information (bit.ly/1mbtyTz). Еще один великолепный ресурс — книга Йена Экселсона (Jan Axelson) «USB Complete: The Developer’s Guide, Fourth Edition» (Lakeview Research LLC, 2009).

До Windows 8.1, если вы писали приложение для HID-устройства, вы создавали неуправляемое Win32-приложение. Но если вы были веб- или .NET-разработчиком, цена была непомерной. Чтобы устранить эту проблему, Microsoft ввела HID Windows Runtime (WinRT) API с появлением Windows 8.1 (bit.ly/1aot1by). Этот новый API позволяет писать приложения Windows Store для вашего устройства, используя JavaScript, Visual Basic, C# или C++.

Кроме того, Microsoft недавно добавила поддержку нескольких новых транспортов, поэтому вы не ограничены USB-кабелем. Сегодня вы можете создать HID-устройство, которое передает и принимает пакеты по USB, Bluetooth, Bluetooth LE и I2C. (Подробнее на эту тему см. «HID Transports» по ссылке bit.ly/1asvwg6.)

В этой статье я покажу, как можно создать простой датчик температуры, совместимый с протоколом HID. Затем опишу пример приложения Windows Store, способного отображать температурные данные от этого устройства.

Конструирование датчика температуры

Это устройство базируется на плате Netduino (netduino.com). Это плата с открытым исходным кодом, используемая любителями, научными сотрудниками и инженерами в промышленности для построения рабочих прототипов своих устройств. А поскольку Netduino совместима по выводам с Arduino, вы можете подключать имеющиеся у вас насадки (shields) для Arduino для быстрого расширения функционала. (Насадка — это плата со специфической функциональностью, например для беспроводной связи, управления мотором, Ethernet, RS232, ЖК-дисплея и т. д.) В моем устройстве используется насадка с поддержкой RS232 для загрузки прошивки. Для передачи и приема данных задействован разъем USB на самой плате.

Netduino поддерживает .NET Micro Framework, и ее прошивка создается с помощью бесплатной копии Visual C# Express.

Чтобы получать температурные данные, устройство использует датчик Texas Instruments LM35. Датчик принимает пятивольтный ввод от Netduino и преобразует его в выходное напряжение, пропорциональное текущей температуре по Цельсию.

Ниже перечислены детали, которые понадобятся для сборки собственного HID-датчика.

  • Netduino 1 или Netduino Plus 1 (Amazon, amzn.to/1dvTeLh) — макетная плата с программируемым микроконтроллером, который поддерживает .NET Micro Framework.
  • Насадка RS232 (CuteDigi, bit.ly/1j7uaMR) — модуль RS232 для загрузки и отладки прошивки. (Эта насадка необходима для используемой бета-версии прошивки.)
  • Датчик LM35 (DigiKey, bit.ly/KjbQkN) —датчик температуры, который преобразует входное напряжение в выходное в зависимости от текущей температуры.
  • Кабель-преобразователь между RS232 и USB (Parallax, bit.ly/1iVmP0a) — кабель для загрузки прошивки датчика температуры через насадку RS232. (Заметьте, что для совместимости с этой насадкой требуется чипсет FTDI.)
  • Блок питания на 9 В и 650 мА (Amazon, amzn.to/1d6R8LH) — блок питания для платы Netduino.
  • Кабель-переходник с USB на Micro-USB (Amazon, amzn.to/Kjc8Ii) — кабель для отправки HID-пакетов от Netduino на планшет или лэптоп с Windows 8.1.

Собранный HID-датчик температуры показан на рис. 1.

*
Рис. 1. Полностью собранный HID-датчик температуры

Насадка RS232 подключается к верхней части Netduino. Макетная плата содержит датчик LM35, который подключается к 5 В, земле и разъему 0. (Разъем 0 — один из шести разъемов аналого-цифрового преобразователя [АЦП] на плате.) Итак, начнем.

Прошивка, с которой поставляется Netduino 1 (или Netduino Plus 1), не поддерживает протокол HID. Вам придется сконфигурировать свою макетную плату, установив бета-версию прошивки 4.1.1, которая включает поддержку HID. Эту прошивку вы найдете по ссылке bit.ly/1a7f6MB. (Чтобы скачать этот файл, нужно создать учетную запись, зарегистрировавшись в Secret Labs.)

Страница скачивания на этом веб-сайте включает инструкции по обновлению прошивки. Однако эти инструкции довольно сложны, особенно если вы новичок в Netduino. По ссылке bit.ly/1d73P9x вы найдете полезный видеоролик с четким описанием всего процесса.

После обновления прошивки платы вы готовы приступить к конструированию схемы датчика температуры. На первом этапе вы должны подключить насадку RS232 к своей плате. (Как уже упоминалось, Netduino совместима по выводам с Arduino, поэтому, если вы уже работали с Arduino и у вас есть насадка RS232, вы можете воспользоваться ею.) Вставьте насадку RS232 в Netduino, как показано на рис. 2.

*
рис. 2. Подключение насадки RS232 к Netduino

После подключения насадки RS232 следующий этап — подключение датчика температуры к пятивольтному источнику, земле и коннектору 0 в Netduino. Разъемы датчика, взятые из спецификации TI, показаны на рис. 3.

*
рис. 3. Разъемы датчика

Установка прошивки датчика

Существует два уровня, или экземпляра, прошивки в Netduino. Первый — это прошивка от производителя, которая включает .NET Micro Framework; второй — прошивка вашего устройства. Прошивка от производителя обрабатывает запросы от прошивки устройства. Прошивка от производителя загружается в макетную плату и выполняется каждый раз, когда вы включаете устройство. В противоположность этому вы обычно многократно обновляете прошивку своего устройства в процессе разработки или испытания прототипа.

Чтобы установить прошивку какого-либо устройства, вам нужно сначала установить на компьютер разработки экземпляр Visual C# Express 2010. Ссылку на его скачивание вы найдете на bit.ly/1eRBed1.

В большинстве проектов с применением Netduino вы можете загружать и отлаживать свою прошивку, используя «родное» USB-соединение. Однако бета-версия прошивки от производителя требует RS232-соединения (вот зачем нужна насадка RS232).

После установки Visual C# Express подключите кабель RS232-USB и откройте диспетчер устройств в Windows, чтобы определить, какой COM-порт Windows назначила этому кабелю.

Например, когда я подключаю к своему компьютеру разработки конвертер Parallax RS232-to-USB, Windows сопоставляет его с COM6, как показано на рис. 4.

*
рис. 4. COM-порт, назначенный кабелю RS232-USB

Теперь, зная COM-порт, связанный с конвертером, я могу включить свою Netduino Plus 1, присоединить кабель RS232-USB и запустить экземпляр Visual C# Express, чтобы выполнить загрузку.

После запуска Visual C# Express первым делом нужно идентифицировать корректный транспорт и COM-порт. Для этого щелкните правой кнопкой мыши имя проекта в Solution Explorer и выберите Properties.

Когда появится диалог Properties, выберите вкладку .NET Micro Framework и укажите соответствующие параметры, как показано на рис. 5.

*
рис. 5. Настройка свойств .NET Micro Framework

Указав Transport и Device, можно устанавливать прошивку. И вновь щелкните правой кнопкой мыши имя проекта в Solution Explorer, но на этот раз выберите Deploy. По окончании установки Visual C# Express сообщит об успехе в секции Output.

Теперь вы готовы подключить свое устройство к планшету или лэптопу с Windows 8.1 и протестировать его с приложением-примером Custom Temperature Sensor.

Сначала отключите RS232-кабель, выключите Netduino, а затем перезапустите его с использованием вспомогательного источника питания. Дайте устройству несколько секунд на переход в рабочий режим и подключите USB-кабель к Netduino. После этого вы должны увидеть свое устройство добавленным в набор HID-устройств в диспетчере устройств. (VID и PID на рис. 6 соответствуют VID и PID образца устройства; эти сокращения расшифровываются как идентификаторы поставщика [vendor] и продукта.)

*
рис. 6. VID и PID образца устройства

Установив устройство в Windows 8.1, вы захотите создать и установить пример-приложения. При запуске этого приложения можно выбрать датчик и начать мониторинг температуры воздуха в вашем офисе.

Прошивка устройства

Теперь подробно рассмотрим прошивку датчика температуры. Прежде всего я хотел бы поблагодарить сотрудников Secret Labs (производителя Netduino) за ту работу, которую они проделали для поддержки HID по USB на платформе Netduino. Базой для этой прошивки послужил проект-пример UsbHidEchoNetduinoApp на форуме (bit.ly/1eUYxAM).

Поддержка транспорта USB Как говорилось ранее, Microsoft поддерживает HID-устройства, работающие по USB, Bluetooth, Bluetooth LE и I2C. Однако устройство-образец, описываемое в этой статье, использует транспорт USB. Это означает, что USB-драйверы будут перемещать пакеты в обоих направлениях: пакеты, исходящие от устройства, передаются драйверу HID (а тот передает их в API, если есть приложения, заинтересованные в этих пакетах), а пакеты, исходящие от драйвера HID, передаются устройству.

Чтобы определить, какие USB-драйверы должны быть загружены, Windows использует специфические данные, выдаваемые устройством при подключении.

После запуска Visual C# Express первым делом нужно идентифицировать корректный транспорт и COM-порт.

Определение классов в прошивке Прошивка для датчика температуры создается на основе двух классов: Program и Sensor. Класс Program поддерживает одну процедуру Main, вызываемую при запуске. Класс Sensor определяет параметры USB и HID для датчика температуры. Кроме того, он поддерживает методы, которые отправляют отчеты ввода (input reports) и считывают отчеты вывода (output reports).

Класс Sensor содержит весь код, необходимый для конфигурирования транспорта USB. К нему относится код, который:

  • настраивает конечную точку для чтения;
  • настраивает конечную точку для записи;
  • указывает Vendor ID (VID);
  • указывает Product ID (PID);
  • указывает описательные названия (название производителя, название продукта и т. д.);
  • указывает другие необходимые параметры USB для HID-устройства.

Большая часть конфигурационного кода для USB находится в методе ConfigureHID в модуле Sensors.cs. В свою очередь этот метод создает и инициализирует объект Configuration (bit.ly/1i1IcQ3), который содержит параметры USB для устройства (конечные точки, VID, PID и др.).

Конечная точка для чтения позволяет устройству принимать пакеты от API и драйвера HID, а конечная точка для записи дает возможность драйверу посылать пакеты вверх по стеку драйверов в API.

Windows использует VID, PID и другие параметры USB (которые были указаны в методе ConfigureHID), чтобы определять, является ли устройство допустимым USB-устройством, а затем загружать соответствующие драйверы.

Открытие соединения с устройством Класс Sensor включает метод Open, вызываемый из процедуры Main класса Program. Как видно из рис. 7, метод Open:

  • получает список доступных контроллеров USB;
  • вызывает метод ConfigureHID, чтобы задать параметры USB и HID для устройства;
  • вызывает метод Start применительно к первому доступному контроллеру;
  • создает объект потока данных USB с конечными точками для чтения и записи.

рис. 7. Метод Open

public bool Open()
{
  bool succeed = true;
  started = false;
  UsbController[] usbControllers = UsbController.GetControllers();
  if (usbControllers.Length < 1)
  {
    succeed = false;
  }
  if (succeed)
  {
    usbController = usbControllers[0];
    try
    {
      succeed = ConfigureHID();
      if (succeed)
      {
        succeed = usbController.Start();
      }
      if (succeed)
      {
        stream = usbController.CreateUsbStream(WRITE_ENDPOINT,
           READ_ENDPOINT);
      }
    }
    catch (Exception)
    {
      succeed = false;
    }
  }
  started = true;
  return succeed;
}

Класс Sensor также включает метод Close, вызываемый, когда устройство отключается от хоста (лэптопа или планшета).

Поддержка протокола HID

Протокол HID базируется на отчетах возможностей (feature reports), ввода (input reports) и вывода (output reports). Отчеты возможностей отправляются либо хостом (т. е. подключенным лэптопом или планшетом), либо устройством. Отчеты ввода передаются устройством хосту, а отчеты вывода — хостом устройству.

В случае нашего датчика температуры отчет ввода — это очень простой двухбайтовый пакет. Первый байт указывает текущую температуру в градусах Фаренгейта, а второй — текущий интервал отчетов в миллисекундах. (Прошивка датчика выдает отчет ввода с частотой, заданной интервалом отчетов.)

Отчет вывода для нашего устройства еще проще: всего один байт, указывающий интервал отчетов. (Это целое значение, представляющее интервал в миллисекундах.)

Создание дескриптора отчета Как уже говорилось, одна из особенностей HID-устройства — отсутствие необходимости в дополнительном описании возможностей: при подключении к хосту устройство само предоставляет описание своего предназначения, возможностей и формата пакетов в виде так называемого дескриптора отчетов (report descriptor). Этот дескриптор указывает, какое место данное устройство занимает в мире HID (является ли оно мышью, клавиатурой или устройством, определенным поставщиком). Дескриптор также сообщает формат отчетов индивидуальных возможностей, ввода и вывода.

Дескриптор отчетов для датчика температуры находится в Sensors.cs (рис. 8).

Рис. 8. Дескриптор отчетов для датчика температуры

hidGenericReportDescriptorPayload = new byte[]
{
  0x06,0x55,0xFF, //HID_USAGE_PAGE_VENDOR_DEFINED
  0x09,0xA5,      //HID_USAGE (vendor_defined)
  0xA1,0x01,      //HID_COLLECTION(Application),
  // Отчет ввода (передаваемые устройством данные)
  0x09,0xA7,      //HID_USAGE (vendor_defined)
  // Мин. температура - 0 градусов F
  0x15,0x00,      //HID_LOGICAL_MIN_8(0),
  // Макс. поддерживаемая температура - 150 градусов F
  0x25,0x96,      //HID_LOGICAL_MAX_8(150),
  0x75,0x08,      //HID_REPORT_SIZE(8),
  0x95,0x01,      //HID_REPORT_COUNT(1),
  0x81,0x02,      //HID_INPUT(Data_Var_Abs),
  0x09,0xA8,      //HID_USAGE (vendor_defined)
  0x15,0x4B,      //HID_LOGICAL_MIN_8(75),  // мин. 75 мс
  0x25,0xFF,      //HID_LOGICAL_MAX_8(255), // макс. 255 мс
  0x75,0x08,      //HID_REPORT_SIZE(8),
  0x95,0x01,      //HID_REPORT_COUNT(1),
  0x81,0x02,      //HID_INPUT(Data_Var_Abs),
  // Отчет вывода (принимаемые устройством данные)
  0x09,0xA9,      //HID_USAGE (vendor_defined)
  0x15,0x4B,      //HID_LOGICAL_MIN_8(75),  // мин. 75 мс
  0x25,0xFF,      //HID_LOGICAL_MAX_8(255), // макс. 255 мс
  0x75,0x08,      //HID_REPORT_SIZE(8),
  0x95,0x01,      //HID_REPORT_COUNT(1),
  0x91,0x02,      //HID_OUTPUT(Data_Var_Abs),
  0xC0            //HID_END_COLLECTION
};

Первые две строки дескриптора информируют хост о том, что данное устройство определено поставщиком (vendor_defined):

0x06,0x55,0xFF,     //HID_USAGE_PAGE_VENDOR_DEFINED
0x09,0xA5,          //HID_USAGE (vendor_defined)

Строки 4–15 задают формат двухбайтового отчета ввода. Строки 4–9 описывают первый байт отчета ввода, который сообщает показание температуры:

0x09,0xA7,          //HID_USAGE (vendor_defined)
0x15,0x00,          //HID_LOGICAL_MIN_8(0), // Мин. температура - 0 градусов F
0x25,0x96,          //HID_LOGICAL_MAX_8(150), // Макс. поддерживаемая температура -  150 градусов F
0x75,0x08,          //HID_REPORT_SIZE(8),
0x95,0x01,          //HID_REPORT_COUNT(1),
0x81,0x02,          //HID_INPUT(Data_Var_Abs),

Протокол HID базируется на отчетах возможностей, ввода и вывода.

Строки 10–15 описывают второй байт отчета ввода, который указывает интервал отчетов (в миллисекундах):

0x09,0xA8,          //HID_USAGE (vendor_defined)
0x15,0x4B,          //HID_LOGICAL_MIN_8(75),   // мин. 75 мс
0x25,0xFF,          //HID_LOGICAL_MAX_8(255),  // макс. 255 мс
0x75,0x08,          //HID_REPORT_SIZE(8),
0x95,0x01,          //HID_REPORT_COUNT(1),
0x81,0x02,          //HID_INPUT(Data_Var_Abs),

Дескриптор отчета для устройства-образца включается в объект UsbController.Configuration (bit.ly/1cvcq5G), создаваемый в методе ConfigureHID в Sensor.cs.

Поддержка HID-отчета ввода Отчет ввода определяется как структура в модуле Sensor.cs:

struct InputReport
{
  public byte Temperature; // Температура в градусах Фаренгейта
  public byte Interval;    // Интервал отчетов (или частота) в секундах
}

Прошивка выдает отчеты ввода, используя объект UsbStream (bit.ly/1kElfUZ), созданный в методе Open. Эти отчеты ввода отправляются методом SendInputReport, когда прошивка вызывает метод stream.Write:

protected void SendInputReport(InputReport report)
{
  byte[] inputReport = new byte[2];
  inputReport[0] = (byte)report.Temperature;
  inputReport[1] = (byte)report.Interval;
  stream.Write(inputReport, 0, 2);
}

Передача температурных данных в отчетах ввода Метод Update класса Sensor выдает отчет ввода подключенному хосту:

public int Update(int iTemperature, int iInterval)
{
  InputReport inputReport = new InputReport();
  byte Interval = 0;
  inputReport.Temperature = (byte)iTemperature;
  inputReport.Interval = (byte)iInterval;
  SendInputReport(inputReport);
  Interval = GetOutputReport();
  return (int)Interval;
}

Метод Update вызывается из бесконечного цикла while (рис. 9), который выполняется в процедуре Main прошивки (в Program.cs).

рис. 9. Цикл while, вызывающий метод Update

while (true)
{
  // Получаем текущее показание температуры
  // Read возвращает значение в указанном диапазоне
  milliVolts = (double)voltsPin.Read();
  // Датчик возвращает 10 мВ на градус шкалы Цельсия
  tempC = milliVolts / 10.0;
  // Преобразуем в градусы по Фаренгейту
  tempF = 1.8 * tempC + 32;
  simpleTemp = (int)tempF;
  // Поскольку при подключении внешнего блока питания
  // к Netduino возникают флуктуации напряжения,
  // используем скользящее среднее (running average)
  // для "сглаживания" значений
  if (firstReading)
  {
    firstReading = false;
    currentTemp = simpleTemp;
    for (i = 0; i < 12; i++)
      tempArray[i] = simpleTemp;
    }
  else
  {
    // Смещаем элементы массива и вставляем новую температуру
    tempArray = Shift(simpleTemp, tempArray);
    // Вычисляем скользящее среднее по последним 12 показаниям
    currentTemp = Average(tempArray);
  }
  RequestedInterval = sensor.Update(
    currentTemp, CurrentInterval);
  // Проверяем, не был ли запрошен новый интервал
  // через отчет вывода
  if (RequestedInterval != 0)
  {
    CurrentInterval = RequestedInterval;
  }
  led.Write(true);
  Thread.Sleep(CurrentInterval);
  led.Write(false);
  }
}

Этот новый API позволяет вашему приложению получать данные от HID-устройств, а также управлять ими.

Поддержка HID-отчета вывода Отчет вывода определяется как структура в модуле Sensor.cs:

struct OutputReport
{
  public byte Interval; // Интервал отчетов (или частота) в секундах
}

Прошивка принимает отчеты вывода через тот же объект UsbStream, созданный в методе Open. Эти отчеты вывода принимаются методом GetOutputReport:

protected byte GetOutputReport()
{
  byte[] outputReport = new byte[1];
  int bytesRead = 0;
  if (stream.CanRead)
  {
  bytesRead = stream.Read(outputReport, 0, 1);
  }
  if (bytesRead > 0)
  return outputReport[0];
  else
  return 0;
}

Регулировка интервала отчетов с помощью отчетов вывода Прошивка поддерживает задание интервала отчетов в миллисекундах от 75 до 255. Приложение запрашивает новый интервал, отправляя отчет вывода устройству. Устройство в свою очередь сообщает текущий интервал в каждом отчете ввода, который передается подключенному приложению.

Прошивка применяет текущий интервал вызовом метода Thread.Sleep (bit.ly/LaSYVF) на то число секунд, которое указано текущим интервалом:

led.Write(true);
Thread.Sleep(CurrentInterval);
led.Write(false);

Приостанавливая цикл while на это время, зарегистрированные приложения принимают отчеты ввода через определенный интервал.

Приложение для HID-датчика температуры

Приложение-пример демонстрирует, как можно отображать температурные данные от подключенного HID-датчика температуры, используя новый HID WinRT API для Windows 8.1. Этот новый API позволяет вашему приложению получать данные от HID-устройств, а также управлять ими.

Пример рассчитан на работу с подключенным HID-устройством, которое распознает температуры в диапазоне от 0 до 150 градусов по Фаренгейту. Приложение отслеживает и отображает текущее показание датчика температуры.

Приложение поддерживает три «сценария», каждый из которых связан со специфическими функциями в UI этого приложения. Кроме того, каждый сценарий сопоставлен с соответствующими XAML и файлом исходного кода на C#. Ниже перечислены все сценарии, их модули и то, для чего они предназначены.

Device Connect (Scenario1_ConnectToSensor.xaml и Scenario1_ConnectToSensor.xaml.cs):

  • поддерживает подключение HID-устройства к компьютеру с Windows 8.1;
  • перечисляет подключенные датчики температуры, чтобы пользователь мог выбрать нужный;
  • устанавливает сторож устройства (device watcher), который следит за состоянием устройства. (Сторож устройства генерирует событие, когда пользователь отключает или заново подключает выбранное HID-устройство.)

Get Temperature Data (Scenario2_GetTemperatureData.xaml и Scenario2_GetTemperatureData.xaml.cs):

  • ведет мониторинг выбранного датчика температуры;
  • рисует температурную шкалу и визуализирует текущее показание, используя элемент управления «ползунок».

Set Report Interval (Scenario3_SetReportInterval.xaml и Scenario3_SetReportInterval.xaml.cs):

  • позволяет контролировать частоту, с которой датчик температуры сообщает о своем состоянии. (Интервал по умолчанию — 250 мс, но пользователь может выбрать любой интервал от 75 до 250 мс.)

Поддержка соединений устройства

Сценарий соединений с устройством охватывает несколько аспектов подключения HID-устройства к компьютеру с Windows 8.1: перечисление подключенных устройств, установку сторожа устройства, обработку отключения устройства и его повторное подключение.

Установление соединения с устройством Код, обрабатывающий соединения устройства, находится в трех модулях: Scenario1_ConnectToSensor.xaml.cs, EventHandlerForDevices.cs и DeviceList.cs. (Первый модуль содержит основной код для этого сценария; остальные два включают вспомогательную функциональность.)

Первая фаза соединения осуществляется до того, как UI становится видимым. В этой фазе приложение создает объект DeviceWatcher, который уведомляет приложение о добавлении, удалении или изменении устройств. Вторая фаза наступает после отображения UI, и пользователь может выбрать конкретное устройство из числа подключенных HID-устройств. Приложение выводит строку DeviceInstanceId для каждого подключенного устройства; эта строка включает VID и PID для данного устройства. В случае нашего датчика температуры строка DeviceInstanceId имеет вид:

HID\VID_16C0&PID_0012\6&523698d&0&0000

На рис. 10 показано приложение по окончании перечисления и после того, как пользователь подключился к устройству.

*
рис. 10. Приложение Windows 8.1, подключенное к HID-устройству

Первая фаза соединения с устройством Ниже кратко описываются методы, вызываемые в первой фазе соединения с устройством (до отображения UI), а также задачи, выполняемые каждым методом:

DeviceConnect (Scenario1_DeviceConnect.xaml.cs) вызывает метод CustomTemperatureSensor.InitializeComponent, который инициализирует UI-компоненты приложения, такие как блоки текста и кнопки.

InitializeDeviceWatchers (Scenario1_DeviceConnect.xaml.cs) вызывает метод HidDevice.GetDeviceSelector, чтобы получить строку селектора устройств. (Селектор необходим для создания сторожа устройства.) Получив селектор, приложение вызывает DeviceInformation.CreateWatcher, чтобы создать объект DeviceWatcher, а потом вызывает EventHandlerForDevice.Current.AddDeviceWatcher. (Последний метод позволяет отслеживать изменения в состоянии устройства.)

AddDeviceWatcher (EventHandlerForDevices.cs) создает обработчики трех событий устройств: Enumeration Completed (перечисление завершено), Device Added (добавлено устройство) и Device Removed (устройство удалено).

SelectDeviceInList (Scenario1_DeviceConnect.xaml.cs) проверяет, выбрал ли пользователь какое-то устройство, и, если да, сохраняет индекс для этого устройства.

В терминах HID API основной код находится в методе InitializeDeviceWatchers (рис. 11). Этот код вызывает метод HidDevice.GetDeviceSelector (bit.ly/1eGQI1k) и передает параметры UsagePage, UsageId, VID и PID для датчика температуры.

рис. 11. Метод InitializeDeviceWatchers

private void InitializeDeviceWatchers()
{
  // Пользовательский датчик
  var CustomSensorSelector =
    HidDevice.GetDeviceSelector(CustomSensor.Device.UsagePage,
    CustomSensor.Device.UsageId, CustomSensor.Device.Vid,
    CustomSensor.Device.Pid);
  // Создаем сторож устройства для поиска
  // экземпляров пользовательского датчика
  var CustomSensorWatcher =
    DeviceInformation.CreateWatcher(CustomSensorSelector);
  // Разрешаем EventHandlerForDevice обрабтывать события
  // сторожа устройства, которые относятся к устройству
  // или влияют на него (удаление устройства, добавление,
  // приостановка/возобновление работы приложения)
  AddDeviceWatcher(CustomSensorWatcher, CustomSensorSelector);
}

Значения UsagePage и UsageId определены в файле constants.cs:

public class Device
{
  public const UInt16 Vid = 0x16C0;
  public const UInt16 Pid = 0x0012;
  public const UInt16 UsagePage = 0xFF55;
  public const UInt16 UsageId = 0xA5;
}

Эти члены класса соответствуют значениям, указанным в HID-дескрипторе отчета, который определен в прошивке устройства:

hidGenericReportDescriptorPayload = new byte[]
{
  0x06,0x55,0xFF,     //HID_USAGE_PAGE_VENDOR_DEFINED
  0x09,0xA5,          //HID_USAGE (vendor_defined)

Метод GetDeviceSelector возвращает строку Advanced Query Syntax (AQS) в переменной CustomSensorSelector. Приложение использует эту строку, когда создает устройство и когда перечисляет объекты DeviceInformation.

Вторая фаза соединения с устройством В этой фазе пользователь может сделать выбор в списке подключенных устройств. Тем самым определяется текущее выбранное устройство. Ниже перечислены вызываемые при этом методы (все они содержатся в EventHandlerForDevices.cs) и кратко описано, что делает каждый из них.

OpenDeviceAsync открывает соединение с устройством.

RegisterForAppEvents выполняет регистрацию на события приостановки и возобновления работы приложения.

RegisterForDeviceAccessStatusChange прослушивает изменения в разрешениях на доступ к устройству.

RegisterForDeviceWatcherEvents выполняет регистрацию на события добавления и удаления.

StartDeviceWatcher запускает сторож устройства.

SelectDeviceInList проверяет, выбрал ли пользователь какое-то устройство, и, если да, сохраняет индекс для этого устройства. Кроме того, он записывает строку «Currently connected…» в окно вывода, если соединение установлено успешно.

В терминах HID API основной код находится в методе OpenDeviceAsync. Этот код вызывает метод HidDevice.FromIdAsync (bit.ly/1hyhVpI), возвращающий объект HidDevice (bit.ly/1dsD2rR), который используется приложением для доступа к устройству, получения отчетов ввода и отправки отчетов вывода:

public async Task<Boolean> OpenDeviceAsync(DeviceInformation deviceInfo,
  String deviceSelector)
  {
// В этом примере для открытия устройства используется
    // FileAccessMode.ReadWrite, поскольку вы не захотите,
    // чтобы другие приложения открывали это устройство
    // и изменяли его состояние. В ином случае можно было бы
    // задействовать FileAccessMode.Read.
    device = await HidDevice.FromIdAsync(deviceInfo.Id,
		FileAccessMode.ReadWrite);
...

Поддержка сторожа устройства Перечисление устройств происходит, когда приложение еще только запускается — даже до отображения UI. По окончании перечисления приложение отслеживает состояние устройств.

О состоянии устройств сообщает объект DeviceWatcher (bit.ly/1dBPMPd). Как и предполагает его имя, этот объект «следит» за подключенными устройствами: если пользователь удаляет или подключает свое устройство, сторож уведомляет приложение об этом событии. (Об этих событиях сообщается только по окончании процесса перечисления.)

Получение отчетов ввода

В сценарии получения показаний температуры осуществляется мониторинг отчетов ввода, выдаваемых датчиком температуры, и используется элемент управления «ползунок» для отображения текущей температуры, как показано на рис. 12. (Заметьте, что этот элемент управления ограничен выводом температурных данных. Свойства IsDoubleTapEnabled, IsHoldingEnabled, IsRightTapEnabled и IsTapEnabled выставлены в False.)

*
рис. 12. Отображение текущей температуры

Основной метод, поддерживающий этот сценарий, заключен в обработчик событий OnInputReportEvent, содержащийся в Scenario2_GetTemperatureData.xaml.cs. Приложение регистрирует этот обработчик событий, когда пользователь выбирает сценарий получения температурных данных и нажимает кнопку Register for Temperature Detection. Регистрация обработчика осуществляется в методе RegisterForInputReportEvents. Помимо регистрации обработчика, этот метод сохраняет маркер события, чтобы регистрацию данного обработчика можно было потом отменить:

private void RegisterForInputReportEvents()
{
  if (!isRegisteredForInputReportEvents)
  {
    inputReportEventHandler = new TypedEventHandler<HidDevice,
      HidInputReportReceivedEventArgs>(this.OnInputReportEvent);
    registeredDevice = EventHandlerForDevice.Current.Device;
    registeredDevice.InputReportReceived += inputReportEventHandler;
    isRegisteredForInputReportEvents = true;
  }
}

После регистрации обработчик событий считывает каждый отчет ввода, выдаваемый датчиком, и использует новое показание температуры для обновления элемента управления TemperatureSlider. Затем этот метод записывает значения текущей температуры и интервала отчетов в раздел Output приложения, как показано на рис. 13.

рис. 13. Чтение и отображение данных датчика

private async void OnInputReportEvent(HidDevice sender,
  HidInputReportReceivedEventArgs eventArgs)
{
  // Получаем данные от датчика
  HidInputReport inputReport = eventArgs.Report;
  IBuffer buffer = inputReport.Data;
  DataReader dr = DataReader.FromBuffer(buffer);
  byte[] bytes = new byte[inputReport.Data.Length];
  dr.ReadBytes(bytes);
  // Визуализируем данные от датчика
  await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  {
    CurrentReadingText.TextAlignment = TextAlignment.Center;
    CurrentReadingText.Text = bytes[1].ToString();
    TemperatureSlider.Value = (int)bytes[1];
    rootPage.NotifyUser(bytes[1].ToString() +
     " degrees Fahrenheit, " +
      bytes[2].ToString() +
      " millisecond report-interval", NotifyType.StatusMessage);
  });
}

Отправка отчетов вывода

В сценарии с заданием интервала отчетов датчику температуры посылается отчет вывода и записывается количество байтов, а также значение, выводимое в секцию Output окна приложения. Приложение посылает отчет вывода после того, как пользователь выбирает сценарий Set Report Interval, указав значение в раскрывающемся списке Value to Write, а затем нажимает кнопку Send Output Report.

рис. 14 иллюстрирует этот сценарий и раскрывающийся список, заполняемый значениями интервала отчетов. (Эти значения представляют интервал отчетов в миллисекундах, поэтому, если выбирается 100, приложение будет принимать 10 показаний в секунду.)

*
рис. 14. Установка интервала отчетов

Основной метод в сценарии с заданием интервала отчетов — SetReportIntervalAsync, содержащийся в модуле Scenario3_SetReportInterval.xaml.cs (рис. 15). Этот метод вызывает метод HidDevice.SendOutputReportAsync (bit.ly/1ad6unK) для отправки устройству отчета вывода.

Рис. 15. SetReportIntervalAsync

private async Task SetReportIntervalAsync(Byte valueToWrite)
{
  var outputReport =
    EventHandlerForDevice.Current.Device.CreateOutputReport();
  var dataWriter = new DataWriter();
  // Первый байт содержит идентификатор отчета
  dataWriter.WriteByte((Byte)outputReport.Id);
  dataWriter.WriteByte((Byte)valueToWrite);
  outputReport.Data = dataWriter.DetachBuffer();
  uint bytesWritten =
    await EventHandlerForDevice.Current.Device.
    SendOutputReportAsync(outputReport);
  rootPage.NotifyUser("Bytes written:  " +
	bytesWritten.ToString() + ";
    Value Written: " + valueToWrite.ToString(),
		NotifyType.StatusMessage);
}

Заключение

Итак, сначала я кратко рассмотрел построение HID-устройства, которое отслеживает напряжение, генерируемое простым датчиком. Пример того, как можно отслеживать датчик, который переключает разъем цифрового ввода-вывода (вместо генерации диапазона напряжений), см. в MSDN (датчик движения) по ссылке bit.ly/1gWOlcC.

Затем мы обсудили написание простого приложения, способного отслеживать HID-устройство и управлять им. Подробнее о HID WinRT API см. по ссылке bit.ly/1aot1by.

Автор: Донн Морс  •  Иcточник: MSDN Magazine  •  Опубликована: 17.07.2014
Нашли ошибку в тексте? Сообщите о ней автору: выделите мышкой и нажмите CTRL + ENTER
Теги:   WinRT.


Оценить статью:
Вверх
Комментарии посетителей RSS

Чтобы оставить комментарий, зарегистрируйтесь или войдите с учетной записью социальной сети.