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

Arlleex

Свой
  • Постов

    5 803
  • Зарегистрирован

  • Посещение

  • Победитель дней

    14

Arlleex стал победителем дня 6 апреля

Arlleex имел наиболее популярный контент!

Репутация

131 Очень хороший

2 Подписчика

Информация о Arlleex

Контакты

  • ICQ
    Array

Посетители профиля

17 687 просмотров профиля
  1. Да. Так делают, например, топовые гиганты типа интел/амд/нвидиа. И да, я не видел ни одной фирмы, где прям по серьезке садились бы считать байты ОЗУ, которые потребуются для задачи, ибо хотя бы найти челвоека, который это умеет и потом будет в случае чего отвечать - та еще задача. Обычно смотрят по верхушкам - устраивает ли МК/проц по интерфейсам и их скоростям, режимам и т.д. Можно ли его купить в обозримом будущем в тех же объемах, что он продается сейчас. У инженера обычно в комплекте где-то в районе пятой точки есть чуйка, которая подсказывает ему, хватит ли ему ресурсов или будет маловато. Чуйка обучается опытом а потом подтверждается расчетами.
  2. ... или стартап-файл не под свой контроллер налутал))
  3. Есть, конечно)) Но эта ошибка из разряда "вернуть адрес локальной переменной из функции" - т.е. бывалым разработчиком не допустится🙂 Операции с DMA либо блокирующие (костыль, не делаю так никогда), либо функция отправки пишет в буфер, из которого DMA спокойно будет отправлять, а из той функции можно смело выходить. Я стремлюсь всегда разделять уровни кода, поэтому все очень просто становится читать и поддерживать. Вот так выглядит интерфейс чтения/записи в UART #ifndef _UART_HPP_ #define _UART_HPP_ #include "macros.h" namespace nsUART { void init(); u32 readRxFIFO (u8 dst[], u32 len); s32 writeTxFIFO(u8 src[], u32 len); } #endif И совершенно не важно, что передача и прием реализованы как кольцевой буфер с задействованным DMA как на прием, так и на передачу. Задача (или цикл) парсера вызывает readRxFIFO() и разгребает входящий поток байтов: если нащупала что-то осмысленное - вызывает функцию разбора пакетов. Если хотим отправить данные - вызываем соотв. функцию и передаем ей эти данные, она их кодирует, обрамляет как надо и вызывает writeTxFIFO().
  4. Отключать то зачем? Скорее, просто следить за когерентностью данных и вовремя их флушить/инвалидировать. Я тоже могу представить контекст, в котором эти сентенции уместны. Но они точно не уместны при тезисном описании в википедиях и тем более не применимы в технических дискуссиях за свод нерушимых правил, преклоняясь перед авторитетом дяди в очках с задней обложки книжки. На всякий случай, повторюсь🙂 Я цифру 1024 написал от балды, это лишь для примера было. На самом деле у меня отправляемые пакеты создаются по мере необходимости к отправке, т.е. на стеке. А вот под принимаемые пакеты как раз статически выделяется буфер-агрегатор (в виде Си-шного union) под самый длинный возможный пакет. Т.е. если максимально возможный принимаемый пакет будет, например, 1000 байт - будет создан буфер на 1000 байт или чуть больше для локальных требований к выравниванию и т.д. В особых случаях, когда памяти почти нет (ОЗУ), а линия связи позволяет отправлять данные порционно - то можно так и делать. Например, тот же SLIP по UART-у можно не кодировать предварительно, а кодировать по мере отправки очередного символа. С тем же езернетом так не получится - внутри одного езернет-кадра будь добр подготовить все нужные данные сразу.
  5. Именно. Профессоры обычно только и печатали книжки, не имея ни малейшего представления о реальном коде. Туда же книжки Макконела и Мартина - т.е. в жопито😉 Посмотрел цитаты великого цитируемого (с моими скромными комментами): За любым столом после 3-й рюмки уже обычно начинаются пространные рассуждения о смысле жизни и трехэтажная философия. Здесь из этого же разряда - просто потому, что "классики" больше никакой нет. За неимением цитируют вот таких вот деятелей. P.S. И кстати, а причем тут щас вообще оптимизация? Я вроде о ней даже не говорил. Нет, ну я конечно стараюсь сразу более менее вменяемо подходить к написанию кода - т.е. там, где можно сразу сделать хорошо - делаю. Другой подход мне уже не приживется, ибо это, как и любовь к говнокодингу - либо навсегда, либо никогда. Сегодня вот на моем смартфоне при открытии камеры вываливалось сообщение "Невозможно подключиться к камере". Б%ять! И никакая перезагрузка не помогает. Калькулятор весит 100 мегов - скоро, видимо, и считать правильно перестанет. И так со всем программным, что меня окружает в нынешнем мире. Вот такая философия с преждевременной оптимизацией и породила покрасчиков кнопок, которым похрен на юзеров, которым для моргания лымпочкой нужна ардуина на распбери пай, не меньше.
  6. Прошу прощения, не обратил внимания, что указатель. Вы правы. Однако да, мой компайлер обозвал меня представителем европейского модного движения за VLA внутри структуры А так - это почти то, что я хотел🙂 А разница? В одном проекте - по прерываниям делал, в текущем - DMA принимает. Как это влияет на разбор байтового потока? Зачем его знать? DMA настраивается в кольцевой режим. Задача, обслуживающая канал приема, читает эти байты и отдает его фреймеру SLIP-а, а тот уже на выходе выдает пакеты данных. Потому что структуру в ее самом девственном виде проще читать и давать ее другим разработчикам, дабы понимали ее формат при поддержке протоколов общения. Когда передается 100500 разных классов, начиненных еще каким-то функционалом - становится вообще-то затруднительно сходу въехать в порядок разложения этой порнографии на байтики в реальном проводе. Структура весьма самодокументируема - сразу понятно, что за чем идет. В классе, в котором помимо данных набито еще 100 строк всяких методов и перегрузок, разобраться тяжелее сходу.
  7. Это будет подтягивать динамическое выделение памяти, такое меня уже не устроит. Ух тут сколько всего написали (это хорошо, дискуссия жива🙂) - однако я внесу немножко понятностей. Не важно, что за протокол, важно то, что он пакетный: длина пакета выкорчевывается внеполосной сигнализацией на уровне проводов или (для примитивных байтовых интерфейсов) промежуточный канальный фреймер разбирает поток байтов на кадры/пакеты. Короче говоря, я всегда знаю, сколько данных мне прилетело в пакете. Пакет, как обычно, уже содержит заголовок со всякими типами содержимого для идентификации этого пакета и т.д. Шмалять в сеть пакеты фиксированной длины здесь очень избыточно - это точно красный флаг. Так вот. У меня девайс состоит из множества плат, каскадно соединенных друг с другом порой сильно разными интерфейсами. Пакет данных со входа до самой дальней платы может пройти пару-тройку интерфейсных мостов со своими протокольно-зависимыми особенностями. Каждая "промежуточная" плата имеет механизм проброса "не своих" пакетов данных туда дальше в "паровозик". Чтобы облегчить ПО каждой платы, она детально даже не разбирает "не свои" пакеты, а как есть его пересылает дальше. Где-то закладывать CRC не имело бы смысла, а где-то, из-за этого "прозрачного режима", CRC пакету нужен. Например: девайс состоит из двух плат (1) и (2), между ними прокинут UART. С платы (1) наружу девайса торчит Ethernet, воткнутый в комп. С компа шлю данные плате (2) - и, казалось бы, езернет уже гарантирует целостность своего фрейма, т.е. можно не вносить контрольную сумму для данных, но данные ведь предназначены плате (2), а чтобы туда попасть, данные должны преобразоваться в UART платой (1) и транслироваться на плату (2). Этот UART - байтовый, поэтому поверх него работает SLIP. Но для контроля целостности данных на приеме платой (2) пакет нужно долполнить контрольной суммой. Что и делает сразу отправляющая сторона перед засовыванием в езернет. Насчет положения CRC в структуре: да, можно в хедер ее пихнуть. Однако это маааленький такой костыль с тасованием расположения, который конкретно в данном случае вполне поможет (за счет наличия в Си и (с позволения компиляторов) C++ FAM в структурах). Да, удобно, если КС в конце - сверил - и результат будет 0. Оданко по затратам на вычисление это будет почти один-в-один с пробегом по хедеру и по данным и последующим сравнением полученной КС с той, что в хедере лежит (в случае размещения КС в хедере). Исторически у меня так завелось, что хедеры могут быть разных размеров, и поэтому КС размещалась строго в конце, несмотря на то, что размер кадра плавающий. Меня полностью устраивает этот вариант и поныне. И я хотел, чтобы несколько "костыльно" выглядящее определение структуры с гибким массивом в конце наконец обрело лаконичный вид в C++. Мне не нужна динамическая память - мне нужно как-то сказать компайлеру, чтобы на статически выделенном куске создавал структуру, в которой после гибкого массива расположен еще какой-то элемент. Условно, чтобы это выглядело примерно так (как я это вижу): struct FlexFrame { Header hdr; u8 data[]; // <- гибкий массив, а значит дальше можно ставить только элементы с атрибутом "гибкого положения" u32 crc __attribute__((flexible)); // положение этого члена "гибкое", в зависимости от объема поля data при создании структуры }; ... static u8 RxPacketMemory[1024]; // статически выделенная память для создания "гибких" структур // вызвали с len == 10 void sendPacket(u32 len) { // тут нужен был бы синтаксис объявления структуры, например FlexFrame frame __attribute__((RxPacketMemory, len)); // компилятор думает, что frame имеет data[10], размещая frame в памяти RxPacketMemory frame.crc = ...; // компилятор для доступа к полю crc использует соответствующее смещение, полученное на основе аргумента функции }
  8. Работает все прекрасно и у меня. И 15 лет назад тоже все работало. Меня интересовало, додумалось ли C++ сообщество до чего-то более удобоваримого в этом плане. P.S. Какие указатели в протоколе передачи данных??? Вы о чем? Вроде понятно, что данные снабжаются КС и уже улетают в провод. В дизасм смотреть или даже не пытаться?🙂 P.S. Я с МК тоже отправляю, так что способ ищу легковесный. Если нет - мне проще (как всегда, собственно) написать свой небольшой класс.
  9. Я от того и спрашиваю, что задача тривиальная, а решалась всегда "криво"🙂 Но, видимо, нужно создать класс-оболочку над неким массивом известной длины (достаточной, чтобы вместить нужное количество данных) и с ним уже работать. Длину не нужно передавать, т.к. сам протокол умеет детектировать ее по механизму кадрирования нижних уровней. ИМХО, ужасное решение🙂 Потому что у меня десятки разных управляющих структур бегают, с разным содержимым и длиной. Контрольную сумму логично располагать где-то в одном конкретном месте для всех структур: и это либо начало кадра, либо самый его хвост. Иначе, чтобы определить положение КС, нам надо "узнать", что это за структура, а лезть в ее поля, не проверив КС - нельзя. У меня "узаконен" формат с CRC в хвосте. Алгоритм приема и отбраковки битых кадров становится универсальным.
  10. Можно ли в C++ как-то красиво описать структуру с гибким положением последнего элемента? Допустим, есть структура struct TxRS485 { Header hdr; u8 byte[N]; u32 crc; } N должно будет стать известно в рантайме, поэтому шаблоны тут вряд ли помогут. Задача простая (и применяемая ну совсем повсюду): из поля ввода юзер-данных считать строчку, запихнуть ее в структуру с определенным паттерном (снабдив заголовками и т.д.), последним элементом должен "приклеиться" CRC-чек. Вроде все просто, однако как будто нет решения, кроме как по старинке "клеить" вручную хедер с данными, а потом к этому всему дописывать контрольную сумму.
  11. У китайцев чуть более прогнозируемая ситуация: если купить становится затруднительно у основного поставщика, то по инерции можно еще полгода точно ехать с помощью других продаванов, в это время подготавливая почву для внедрения новой аппаратной платформы. Другое дело - например, евреи - i.MX6 (по крайней мере, нужные нам SoM) пропали за месяц от слова "навсегда".
  12. У манагеров всегда все просто. Это вечно недовольным инженерам вечно то конденсаторов не хватает, то дорожки не лезут.
  13. К этому и сводится большая часть программирования, несмотря на рядом стоящую помойку под названием стандартная библиотека.
×
×
  • Создать...