Pull to refresh
57
0
Алексей @DSarovsky

Пользователь

Send message
Ну почему же, я так это примерно вижу: составить много небольших классов, а окончательный дескриптор собирать как раз-таки с помощью variadic-ов. Делать все на макросах не хочется (собственно, присоединяюсь в этом вопросе к вашему оппоненту на radiokot-е. Вы осилили USB на чистых регистрах, с таким уровнем вникнуть в C++ с его фишками для вас будет несложно).
Это было одно из предположений (почему-то ведь не работает с constexpr), но неверное, как оказалось.
Хм, никогда не миксовал разные настройки компилятора для разных объектных файлов в одном проекте, интересное предложение, спасибо).
Сейчас покопался в F072, там удалось проблему решить путем отказа от constexpr-массива с репортом, вот так:
template<uint8_t... _Data>
struct HidReport
{
  //static constexpr uint8_t Data[sizeof...(_Data)] = {_Data...}; - было так
  static uint8_t Data[];
};
template<uint8_t... _Data>
uint8_t HidReport<_Data...>::Data[] = {_Data...};

Хотя в HEX-редакторе открыл итоговую прошивку, массив там присутствует, так что текущее решение надо признать костылём и разбираться дальше.
Думал об этом, но пока остановился на таком варианте с оглядкой на HID Descriptor tool. Сделал в этой утилите report, вставил целиком в код.
Спасибо!
Проблема еще с отладкой, потому что в отладке компилируется в Og, остается только Wireshark. Уже определил, что не прилетает только Hid-report, так что обязательно найду, в чем дело.
Каюсь, нагородил франкенштейна, хотя делов было на 2 минуты сделать лучше. Теперь инициализация выглядит так:
static void Init()
{
    memset(reinterpret_cast<void*>(BdtBase), 0x00, BdtSize);
    (InitTxAddressFieldInDescriptor<AllEndpoints>(), ...);
    (InitRxAddressFieldInDescriptor<BidirectionalAndBulkDoubleBufferedEndpoints>(), ...);
    (InitRxCountFieldInDescriptor<RxEndpoints>(), ...);
    (InitSecondRxCountFieldInDescriptor<BidirectionalAndBulkDoubleBufferedEndpoints>(), ...);
}


Каждый из методов простой, например:
template<typename Endpoint>
static void InitRxCountFieldInDescriptor()
{
    *reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<Endpoint> + 2) = CalculateRxCountValue<Endpoint>();
}
Да, и на хабре есть пост про этот репозиторий.
Спасибо за совет, согласен, так будет лучше, вынесу отдельно.
Не очень понял про память с пробелами (то есть там реально 2 байта памяти, а потом 2 байта «ничего»? А что если разыменовать, например, как 4-байтовый int, все упадёт?).
В f0 по 2 байта адресация, что тоже несколько доставило сложностей: при копировании в буфер пришлось приводить к int16 и так копировать, но еще большее неудобство при отладке — окно memory показывает только половину, пришлось создать доп.буфер, копировать каждый раз содержимое PMA в этот буфер, и уже его смотреть.
А ведь кто-то поддерживает STL…
Спасибо, упустил это в статье, это весомый аргумент, обязательно добавлю. Хотя, как я понял, есть какие-то условно-бесплатные пары для домашних проектов (хотя для домашних я бы по традиции использовал dead/beef)
А почему? Просто мне кажется, Вы выбрали не самый ужасный кусок кода:)
Про продакшн согласен наполовину: если все идет нормально, то нужды видеть это вроде особой и нет. Единственное, что нужно сделать сразу: заставить автора подробно закомментировать, что именно он имел ввиду в том или ином месте, чтобы спустя время другой программист мог что-то подправить.
UPD: в реальном проекте, если бы мне позволили такое в принципе писать, я бы раздробил длинные объявления, сделал бы так примерно это место:
using BidirectionalAndBulkDoubleBufferedEndpoints = typename Sample<IsBidirectionalOrBulkDoubleBufferedEndpoint, SortedUniqueEndpoints<Endpoints>>::type;
...
using EndpointsManager = EndpointsManagerBase<Endpoints, BidirectionalAndBulkDoubleBufferedEndpoints , ...>;

Из названий переменных должно быть понятно, что к чему.
Сложно поспорить с тем, что читать такой код нереально. При разработке дроблю на много мелких объявлений:
using X = Y;
Когда отладил и понял, что все правильно, соединяю. В основном писать шаблоны несложно (это обычно связка базовый класс + рекурсивная специализация). Напрягает только раскрытие variadic-ов, но ничего не поделать.
Касательно USB, огромные массивы дескрипторов с магическими числами читать пусть и несложно, но разобраться и тем более отредактировать ничуть не легче.
Кстати, уход от CMSIS также может сберечь некоторое количество нервных клеток. Как мне кажется, очень красочный пример: в CMSIS от F0 есть макрос
#define RCC_CFGR_PLLMUL
а в F1 это уже
#define RCC_CFGR_PLLMULL
Даже не знаю, почему у них так получилось.
То есть код, в котором в классах только статические методы (соответственно, объекты создавать смысла нет) не относится к ООП?
Возможно, Вы правы, если бы это было целесообразно, промышленность (или даже сами производители) пользовалась бы. Мне всё это дело просто интересно, помогает в более интересном виде изучать нововведения C++, который я преподаю.

Information

Rating
Does not participate
Registered
Activity