Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Ресет USB устройства хостом
Форум разработчиков электроники ELECTRONIX.ru > Интерфейсы > Форумы по интерфейсам > RS232/LPT/USB/PCMCIA/FireWire
Паф
Разработано CDC USB устройство с питанием от шины. Пишется PC программа для настройки и апгрейда устройства.
Из PC программы необходимо сделать ресет устройства для перехода в наш бутлодер.
Пробуем DeviceIoControl(), но что-то не выходит. Кто-нибудь делал такую вещь??? Помогите плиз.
Alex11
Мы делали в системе команд, передаваемых по CDC (виртуальному COM-порту), команду перейти в Boot.
Паф
To Alex11:
Девайс работает под 1С по CAS протоколу. А наша РС программа нужна лишь для апгрейда прошивки, в ней другой протокол и в бутлодере соответственно тоже. Не хотелось бы парсить лишнюю команду в основной программе процом, но видимо придется ввести уникальную на ресет. Вариант с ресетом девайса от хоста выглядит наиболее удачным.
Смысл в разделении протоколов.
Xenia
Цитата(Паф @ Jun 23 2009, 09:20) *
Из PC программы необходимо сделать ресет устройства для перехода в наш бутлодер.
Пробуем DeviceIoControl(), но что-то не выходит. Кто-нибудь делал такую вещь???


В протоколе USB нет и не может быть такой команды, получатель которой делал бы себе харакири smile.gif. Поэтому копать надо не в сторону поиска такой экзотической USB-команды, а в сторону интерпретации уже имеющихся в протоколе команд.
Например, интерфейсная команда SEND_BREAK используется крайне редко, вот на ее обработчик (в вашем USB-устройстве) вы могли бы повесить ресет (блокировать прерывания + поставить самый быстрый WatchDog + войти в вечный цикл). Тогда для ресета микропроцессора было бы достаточно послать на виртуальный COM-порт команду с помощью API-шной Windows-функции SetCommBreak. При этом нет необходимости делать интерпретатор идущего по линии потока данных, поскольку интерфейсные команды поступают иным путем.
P.S. Только не забудьте, сразу же закрыть COM-порт (CloseHandle) со стороны компьютера, а после ресета снова его открыть, иначе после ресета USB-порт откажется разговаривать с устройством, позабывшим свой адрес. Т.е. рискуете тем, что устройство перезапустится на bootloader, но USB-канал зависнет в патовой комбинации, из которой выйти можно только вручную - выдернуть и снова воткнуть USB-кабель.
Паф
Вот есть интересная ссылочка USB Developers FAQ: http://www.lvr.com/usbfaq.htm
"How can my application reset, disable, or restart a USB device?
The DevCon example in the Windows DDK is a command-line utility that shows how to enable, disable, restart, update, remove and query devices using the SetupAPI and CfgMgr32 API functions."
Вот этот пример и не получается разжечь!!!
А если SetCommBreak пошлет не моя программа, а какая-нибудь тулза юзера??
Паф
Получилось! smile.gif
Кому интересно: код функции, которая реализует посылку хостом команды Reset устройству.
В качестве параметра в нее передается USB product string descriptor устройства.

/////////////////////////////////////////////////////////////////////////////
#include "SetupApi.h"
#pragma comment(lib, "SetupApi")
bool ResetPortDevice(const char *Name);

// Name - USB product string descriptor

/////////////////////////////////////////////////////////////////////////////
bool ResetPortDevice(const char *Name) {
BOOL bRes;
LPGUID pClassGuidList, piClassGuidList;
DWORD i, j, need_size;
HDEVINFO DeviceInfoSet;
SP_DEVINFO_DATA DeviceInfoData;
SP_PROPCHANGE_PARAMS PropChange;
BYTE *pData;

pData = new BYTE[1+strlen(Name)];
if (!pData) return false;

// Request number of 'Ports' items
need_size = 0;
pClassGuidList = NULL;
SetupDiClassGuidsFromName("Ports", pClassGuidList, need_size, &need_size);
if (!need_size) {
delete [] pData;
return false;
}

// Request all 'Ports' items
piClassGuidList = pClassGuidList = new GUID[need_size];
if (!pClassGuidList) {
delete [] pData;
return false;
}
bRes = SetupDiClassGuidsFromName("Ports", pClassGuidList, need_size, &need_size);
if (!bRes) {
delete [] pData;
delete [] pClassGuidList;
return false;
}

// Loop by all GUIDs
for (i = 0; i < need_size; i++, pClassGuidList++) {

// Get list of devices
DeviceInfoSet = SetupDiGetClassDevs(pClassGuidList, NULL, NULL, DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) continue;

DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
PropChange.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChange.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChange.StateChange = DICS_PROPCHANGE; // For reset !!!
PropChange.Scope = DICS_FLAG_CONFIGSPECIFIC;
PropChange.HwProfile = 0;

// Loop by all devices by given GUID
for (j = 0; SetupDiEnumDeviceInfo(DeviceInfoSet, j, &DeviceInfoData); j++) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;

// Try get extended information
bRes = SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_LOCATION_INFORMATION, NULL, pData, 1+strlen(Name), NULL);
if (!bRes) continue;
if (strstr((const char *)pData, Name) == NULL) continue;

// Apply function for the found device (i.e. Reset)
bRes = SetupDiSetClassInstallParams(DeviceInfoSet, &DeviceInfoData, &PropChange.ClassInstallHeader, sizeof(PropChange));
if (!bRes) break;
bRes = SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DeviceInfoSet, &DeviceInfoData);
if (!bRes) break;
}

// Clear list of devices
bRes = SetupDiDestroyDeviceInfoList(DeviceInfoSet);

if (!bRes) break;
}

// Clear arrays
delete [] piClassGuidList;
delete [] pData;

if (!bRes) return false;

return true;
}
/////////////////////////////////////////////////////////////////////////////
Xenia
Цитата(Паф @ Jun 24 2009, 11:18) *
Получилось! smile.gif
Кому интересно: код функции, которая реализует посылку хостом команды Reset устройству.


Ресет USB-устройства и ресет удаленного микропроцессора - вещи совершенно разные! Reset USB-устройства это разрыв логического соединения, а затем его новое соединение с повторным чтением всех дескрипторов и присвоением нового адреса (SET_ADDRESS). Эта процедура происходит на уровне протоколов. Напротив, ресет микроконтроллера означает его физический перезапуск, вследствие чего он имеет возможность запуститься с загрузчика.
Никаким ресетом порта вам не заставить перезапусться микроконтроллер!

Цитата(Паф @ Jun 24 2009, 11:18) *
А если SetCommBreak пошлет не моя программа, а какая-нибудь тулза юзера??


Отвечу вам в тон: а что если тулза юзера сделает то же самое, что делает код вашей функции?
Паф
Может я не совсем точно сформулировал сабж.
То что мы хотели, мы получили: микроконтроллер получает стандартную команду от хоста и переходит в бут. Никаких лишних интерпретаций основного протокола.

Какова вероятность того что от хоста случайно придет SetCommBreak или несколько байт с правильной CRC(команда)? По-моему второе значительно надежнее.
Седой
Цитата(Паф @ Jun 24 2009, 16:43) *
Может я не совсем точно сформулировал сабж.
То что мы хотели, мы получили: микроконтроллер получает стандартную команду от хоста и переходит в бут. Никаких лишних интерпретаций основного протокола.


Вы сделали программный вызов функции стандартного Class Installer, что соответствует последовательности пунктов меню устройства в Диспетчере устройств Отключить и Задействовать - это не способ перевода устройства в режим загрузчика. Пользователь имеет полное право выбирать эти пункты меню и ... ваше устройство перешло в режим upgrade. Вы предусмотрели выход из такой ситуации?
HARMHARM
Цитата(Xenia @ Jun 23 2009, 11:06) *
Только не забудьте, сразу же закрыть COM-порт (CloseHandle) со стороны компьютера, а после ресета снова его открыть, иначе после ресета USB-порт откажется разговаривать с устройством, позабывшим свой адрес. Т.е. рискуете тем, что устройство перезапустится на bootloader, но USB-канал зависнет в патовой комбинации, из которой выйти можно только вручную - выдернуть и снова воткнуть USB-кабель.

Это все правда. Но для загрузчика можно иметь другой VID/PID, и тогда это будет другой порт.
Паф
Цитата(Седой @ Jun 26 2009, 22:37) *
Вы сделали программный вызов функции стандартного Class Installer, что соответствует последовательности пунктов меню устройства в Диспетчере устройств Отключить и Задействовать - это не способ перевода устройства в режим загрузчика. Пользователь имеет полное право выбирать эти пункты меню и ... ваше устройство перешло в режим upgrade. Вы предусмотрели выход из такой ситуации?

Юзер может Отключить и Задействовать видеокарту например, это его право. Да устройство перейдет в режим upgrade и выйдет из него через несколько секунд в application не получив команд от PC программы.
Подскажите пожалуйста другое более правильное решение, если знаете. За этим и создан топик.
Седой
Цитата(Паф @ Jun 29 2009, 11:17) *
Юзер может Отключить и Задействовать видеокарту например, это его право. Да устройство перейдет в режим upgrade и выйдет из него через несколько секунд в application не получив команд от PC программы.
Подскажите пожалуйста другое более правильное решение, если знаете. За этим и создан топик.


Зачем изобретать велосипед, см.
Device Class Specification for Device Firmware Upgrade
http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf
Паф
Спасибо.
Это то что нужно.
Седой
Цитата(Паф @ Jun 30 2009, 11:59) *
Спасибо.
Это то что нужно.


Да, если серьезно заинтересованы, то могу выложить продолжение проекта http://projects.caxapa.ru/?ID=45
Он сильно видоизменился.
1. Появился CoInstaller драйвера.
2. Программа загрузки интегрирована в CoInstaller и теперь можно обновлять firmware из Диспетчера устройств.
Вам всего лишь нужно будет реализовать собственно загрузчик в устройстве в соответствии со спецификацией USB класса DFU1.1
3. Появилось API c низко и высокоуровневыми функциями DFU, а также также для работы с DFU файлами. И если не устраивает встроенная
программа загрузки, то можете написать свою, а встроенную отключить. API интегрировано в CoInstaller dll драйвера.
Паф
Мы уже реализовали наш подход. Тестируем на пилотных образцах.
Но в дальнейшем планируем сделать поддержку DFU. Ваш проект несомненно нам интересен.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.