И второй вопрос: как я понял, размер пакета для нулевой EP ограничен снизу, для FS USB 2.0 у меня меньше 16 байтов не работает. Действительно ли есть такое ограничение, или где-то в коде ошибка?
Нет. Только что проверил на 8-битной точке, все работает.
Так вот такой вопрос: как лучше (как принято): принимать указатель на функцию или std::function?
Не думаю, что вам это поможет, но в моем варианте за разбиение данных по размеру endpoint'a (кроме ep0) отвечает юзерский код, вызываемый по колбэку endpoint_IN. Но у меня Си, не С++.
COKPOWEHEU писал(а):Только что проверил на 8-битной точке, все работает.
Эх, а я уж понадеялся, что все нормально. А на какой ОС, можете сказать? Просто вроде проскакивало здесь, что тот же Linux более лояльный (у меня самая свежая Win10).
COKPOWEHEU писал(а): за разбиение данных по размеру endpoint'a (кроме ep0) отвечает юзерский код
Выбирал, как сделать, решил попробовать освободить юзера от необходимости разбивать самостоятельно. Но, возможно, тоже приду к тому, что это сам пользователь должен делать, если окажется слишком накладно.
А что именно вы хотите настолько эффективно посылать? В том смысле что в USB весь обмен хост-центрчен, то есть он дает устройству команду "мне нужно столько-то байт", устройство посылает и спит до следующей команды. То есть информация о завершении ему просто не нужна.
Есть, конечно, исключение с Interrupt-точками, но там посылки обычно мелкие и в буфер влезают запросто.
Или зайдем с другой стороны - MSD, где надо сначала огромный кусок данных послать, а потом еще специальный пакет-подтверждение. Это для простого буфера (или что там у вас) наоборот неподъемная задача. Откуда ему знать что после передачи основного буфера надо еще дополнительный передать? То есть даже так юзеру останется немало работы.
Эх, а я уж понадеялся, что все нормально. А на какой ОС, можете сказать?
Linux, WinXP, win10.
Но в документации прямо сказано что ep0 может быть 8, 16, 32 и 64 байта. А для низкоскоростных только 8 байт, без вариантов.
[uquote="azhel12",url="/forum/viewtopic.php?p=4010029#p4010029"]Выбирал, как сделать, решил попробовать освободить юзера от необходимости разбивать самостоятельно.[/uquote]Имеет смысл сделать очередь отправки в ep0. Для остальных точек на откуп пользователя буферизация, так как даже в пределах одного класса задачи могут быть совсем разные и требуют творческого подхода.
Очередь это разбиение одного пакета на кусочки по размеру точки. Отправлять байты по своему желанию через нее нельзя, только в ответ на запросы. Ну а очередь на передачу одного пакета и у меня реализована. Даже банальный DeviceDescriptor занимает больше 8 байт, а другие могут и в 64 байта не поместиться.
В случае USB очередь из нескольких пакетов оправдана разве что для Interrupt-точек. Ну не знаю, чтобы прикинуться клавиатурой и послать последовательность символов.
COKPOWEHEU писал(а):В случае USB очередь из нескольких пакетов оправдана разве что для Interrupt-точек.
Но я и в этом случае соглашусь с вашим прошлым сообщением - пусть пользователь сам отправляет, как надо, и в этом случае как раз callback на успешную передачу будет полезен.
Нашел проблему, очень интересно для меня все оказалось.
Тыкание пальца в небо показало, что если установку адреса перенести из лямбды в обработчик CTR_TX, то все начинает работать правильно. Практически уверен, что словил следующую ситуацию: после первых 8 (или 16, отладку процесса нумерации так и не осилил) хост кинул второй сброс (что написано в "USB in a NutShell", надо быть все-таки более внимательным), но поле класса, обозначающее оставшееся количество байтов для передачи не обнулилось. Далее пришел SetAddress, на что я кинул ZLP, но и там остаток не обнулил, поэтому в обработке успешной передачи ZLP девайс отправил хосту оставшиеся 2 байта от дескриптора устройства, хост сошел с ума, дважды попытался завершить нумерацию, ничего не получилось, выдал ошибку. Сейчас в отправке ZLP обнуляю счетчик остатка и все нормально.
Спасибо за помощь.
Что-то вы всё усложняете. Там же тупой автомат "Запрос -> Ответ". По reset всё сбросить.
Размер очереди отправки задаётся только в момент формирования ответа или обнуляется по reset. Если ответ это ZLP, то и очередь автоматом обнулится. При штатном прохождении энумерации не должно быть ситуаций когда хост даёт новый запрос не дочитав ответ на старый. Но автомат должен быть к этому готов. При формировании каждого нового ответа очередь инициализируется заново. Досылать ничего от прошлого ответа уже не надо. Хотя, повторюсь, при правильном обмене такой ситуации не должно возникать.
Проверьте, что вы правильно обрабатываете следующие моменты:
1. По ресет надо сбрасывать все регистры usb-контроллера в состояние как до энумерации. Все ваши программные очереди и статусы тоже.
2. При ответе на SetAddress надо сначала отправить ZLP и только после его ухода записать полученный адрес в регистр. Я недавно открыл для себя, что самое оптимальное по коду это при каждом CTR_TX в ep0 писать в регистр адрес. Для контроллеров с OTG с этим можно не заморачиваться, у них можно устанавливать адрес сразу.
3. При запросе дескрипторов хост пишет сколько он хочет получить в ответ. Если дескриптор больше, чем просит хост, то отправить надо столько сколько попросили. Не надо пихать весь дискриптор в этом случае. Хост по заголовку увидит реальный размер дескриптора и переспросит больше, если захочет. В обратной же ситуации, когда просят больше чем есть, надо отправлять реальный размер.
4. Если размер дескриптора кратен размеру конечной точки, то в конце надо ZLP дослать. Похоже, автомат хоста не доверяет длине, написанной в поле дескриптора, а за конец ответа принимает ситуацию когда пакет меньше размера конечной точки. И только после этого начинает проверку и разбор дескриптора.
Если учесть вышеперечисленные особенности, то нештатных обрывов или недосылов не будет.
Насчёт отладки процесса энумерации - посмотрите мой проект. Там в RTT всё что может быть полезно валится. RTT вообще стоит освоить и в каждом проекте в Debug ветке использовать.
3. При запросе дескрипторов хост пишет сколько он хочет получить в ответ.
Обычно сначала запршивает 8 байт
4. Если размер дескриптора кратен размеру конечной точки, то в конце надо ZLP дослать. Похоже, автомат хоста не доверяет длине, написанной в поле дескриптора, а за конец ответа принимает ситуацию когда пакет меньше размера конечной точки.
Дело не в хосте, а в устройстве. Оно может послать данных меньше, чем хочет передать хост. А неоконченный пакет как раз и является признаком конца передачи. Даже если пакет обрывается не успев начаться.
И никто не отменял криворуких разработчиков железа (вроде меня, azhel12 или китайских бракоделов - не путать с нормальными разработчиками). Они вполне могут послать и слишком длинный ответ, и внутренне противоречивый, который невозможно корректно распарсить. И хост должен попытаться. Или хотя бы не сойти с ума.
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4010814#p4010814"]Обычно сначала запршивает 8 байТ[/uquote]Вот даже думать об этом не хочу. Сколько хостов - столько реализаций. Хоть один пусть спрашивает.
Добавлено after 58 minutes 27 seconds:
Насчёт 8 байт. Это вы моему ноуту расскажите. Лог обмена под спойлером.
Спойлер
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4010894#p4010894"]Закладываться на подобное и опасно и бесполезно: логику обработки это ни разу не упростит.[/uquote]В том же сообщении я написал, что ХОТЬ ОДИН пусть спрашивает. Вам лишь бы поспорить?
VladislavS, я смотрю важнее всего найти повод поспорить именно для вас!
Ну вот вроде бы ни слова возражения не сказал - нет, VladislavS считает своим долгом начать срач!
Просто не будьте столь категоричны в суждениях.
СпойлерНебольшая подборка с нескольких страниц этой темы.
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4005326#p4005326"]поскольку для ep0 допустим размер 8 байт, а туда не то что Configuration или HID, но даже DeviceDescriptor не влезет.[/uquote]
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4006194#p4006194"]см. выше: библиотека это скомпилированный файл.[/uquote]
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4005817#p4005817"]То-то и оно, что в заголовочниках исполняемый код не пишут.[/uquote]
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4010814#p4010814"]Обычно сначала запршивает 8 байт[/uquote]
Будьте добры расшифровать что вы хотели сказать этими цитатами. Во избежание очередного недопонимания.
Спойлер
поскольку для ep0 допустим размер 8 байт
Согласно стандарту размер ep0 может быть 8, 16, 32 или 64 байта (для низкоскоростных - только 8 байт). Размер DeviceDescriptor составляет 18 байт, то есть в минимальный размер он не помещается. Размер Configuration или HID Descriptor'ов вообще может быть любым, в том числе больше 64 байт. Значит поддержка разбиения пакета на кусочки по размеру ep0 необходима в любом случае.
см. выше: библиотека это скомпилированный файл.
То-то и оно, что в заголовочниках исполняемый код не пишут.
Это общеизвестный факт, не знаю зачем его цитировать.
Обычно сначала запршивает 8 байт
Опять-таки: И? Ну да, обычно если размер заранее неизвестен запрашивается сначала 8 байт или минимальный размер дескриптора. Какие выводы вы из этого хотите сделать?
см. выше: библиотека это скомпилированный файл.
То-то и оно, что в заголовочниках исполняемый код не пишут.
Это общеизвестный факт, не знаю зачем его цитировать.[/uquote]Вот именно об этом я и говорил. Категоричное ОБЩЕИЗВЕСТНЫЙ ФАКТ ничего общего не имеющее с действительностью. Все ошибаются, про 8 байт в ep0 вы же поправились. А вот тут не хочу на третий круг заходить.
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4010981#p4010981"]Ну да, обычно если размер заранее неизвестен запрашивается сначала 8 байт или минимальный размер дескриптора.[/uquote]Откуда вы это взяли? Вы готовы доказать, что 50% + 1 хостов так делают? Иначе категоричное ОБЫЧНО выглядит совершенно необоснованным.
Я бы в своей реализации хоста в случае неизвестного размера дескриптора просил бы выслать 256 байт ☺
А уж на компе так вообще можно килобайтный буфер выделить и сразу килобайт просить — чего уж там!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ