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

Плавный переход C -> C++ под МК

В 18.04.2024 в 15:44, tonyk_av сказал:

Сами выделяйте, вам же надо, а не мне.

мне не надо. я для 10 байт выделю 10. 

В 18.04.2024 в 15:44, tonyk_av сказал:

Конечно, я так не умею. Зато я умею сначала посчитать необходимую память, а уже потом подбирать решение по "железу".

Да, это просматривается.

Просто ещё бывает, что разработали контроллер для одной задачи, а потом смогли его использовать в другой. а потом в 3-ей.... а потом в 100-ой.  Обычно, при таком подходе нет издержек на разработку нового железа, нет издержек на расширение элементной базы...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Фигасе вы тут зарубу устроили. Это всё ещё насчет наложения структуры с изменяемой, так сказать, "геометрией"? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 18.04.2024 в 13:50, Arlleex сказал:
namespace nsUART {
  void init();
  
  u32  readRxFIFO (u8 dst[], u32 len);
  s32  writeTxFIFO(u8 src[], u32 len);
}

немного офтопа.... т.е. функции отправки получают указатель на void char, и размер. внутри writeTxFIFO() знать не знает о структуре пакета, ну может быть в конец src[] прикрутит u32 crc. 

Тогда смысыл вот этого...

В 17.04.2024 в 10:54, Arlleex сказал:

Потому что структуру в ее самом девственном виде проще читать и давать ее другим разработчикам, дабы понимали ее формат при поддержке протоколов общения.

Даже не смысл.... а... вот дали мне стуктуру 

struct FlexFrame {
  Header hdr;
  int length;
  u8     data[128];                        // уговорили, путь будет 128. считай что для ПЛК
  u32    crc;
};
//Передает вы её очевидно так
void main()
{
  	struct FlexFrame frame;
	writeTxFIFO( (u8*)&frame, sizeof(frame));
 }
 

Так где  "проще читать"? и " сходу въехать в порядок разложения этой порнографии на байтики в реальном проводе.". внутри writeTxFIFO() вообще фиолетого, там в провод по байтикам раскладывается тупо массив по указателю. А из "девственной" структуры видно, что сначало идет Header hdr; Смотрим описание Header - там стутура адрас, стурктура типа, структвра... в ней структура... и ещё структыра (гляньте какую нибудь стуктуру в девственном виде в ядре linux).

Понятно, что по *.cpp/*.h класса разложить в уме всю верёвку битов в проводе не просто, но и по структуре изучать протокол... видеть что за чем в проводе... тоже какой-то зашквар. Передавать исходный код др. разработчику для изучения протокола - так себе затея. Я предпочитаю сделать класс-фрейм. Спрятать все в методы, в приваты... в виртуальный функции... отладить и забыть. И если отдам это другому, то вместе с этим описание протокола. Не должен разработчик смотреть, что там в проводе, ползая по хидерам стурктур. Вот например, описание протокола Movilink

image.thumb.png.fd47ebddddb4a904caf3dbeaddc59e5c.png

Создал протокол, написал библиотеку для работы с ним (классы или структуры, с или с++, или вообще жава/паскаль), и выдал как библиотеку. Хоть в src, хоть скомпилеиную как lib. А чтобы было видно что в проводе - вот pdf-ка. 

Я обычно описываю достаточно подробно свои протоколы, не так конечно наглядно... но есть куда стремится. ИМХО.

 

 ps а подскажите  - это word? Или какойнить специальный редактор для вёрстки?

 

pps

В 18.04.2024 в 16:35, EdgeAligned сказал:

Фигасе вы тут зарубу устроили. Это всё ещё насчет наложения структуры с изменяемой, так сказать, "геометрией"? 

Весна!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, juvf сказал:

немного офтопа.... т.е. функции отправки получают указатель на void char, и размер. внутри writeTxFIFO() знать не знает о структуре пакета, ну может быть в конец src[] прикрутит u32 crc. 

Нет. Никаких CRC writeTxFIFO() не считает и не дописывает. Условно:

void sendTemperature() {
  ExchDesc<Temperature> t;
  t.hdr.dst = HOST_PC;
  t.temp    = getTemperature();
  t.crc     = CRC32(&t, sizeof(t) - 4);
  
  SLIP.send(&t, sizeof(t)); // вот внутри нее содержимое 't' обернется в кадр и вызовется writeTxFIFO()
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

39 minutes ago, Arlleex said:
59 minutes ago, tonyk_av said:

Прикольно. Сначала сделали "железо", а потом стали пытаться приспособить его к задаче.

Да. Так делают, например, топовые гиганты типа интел/амд/нвидиа.

Тут разные ситуации.
Я не буду высчитывать байты, а посмотрю на подобные решения. Не зря ведь у многих производителей есть линейки МК, различающиеся, например, объёмом ОЗУ. Например, я вижу, что решения, подобные моему, строятся на МК с ОЗУ от 80 до 96К ОЗУ. Взял со 128К. Не хватит- возьму со 192К или даже 256К. Учитывая, что в общей себестоимости девайса стоимость МК составляет менее 10%, то, скорей всего, оставлю всё как есть. У меня не миллионные серии, поэтому 200 рублей погоды не делают.

Подход крупняков прост: они закладывают топовое "железо", потому что их затраты на всё остальное многократно превышают его стоимость. Мощное "железо" гораздо проще приспособить к малоресурсной задаче, чем втиснуть что-то большое в бюджетное "железо".

39 minutes ago, Arlleex said:

Обычно смотрят по верхушкам - устраивает ли МК/проц по интерфейсам и их скоростям, режимам и т.д. Можно ли его купить в обозримом будущем в тех же объемах, что он продается сейчас.

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

Полностью согласен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 минут назад, juvf сказал:

ps а подскажите  - это word? Или какойнить специальный редактор для вёрстки?

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

А когда надо внутри отдела между парой-тройкой разрабов договориться - никакой писаниной заниматься времени нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

44 minutes ago, juvf said:

Просто ещё бывает, что разработали контроллер для одной задачи, а потом смогли его использовать в другой. а потом в 3-ей.... а потом в 100-ой.  Обычно, при таком подходе нет издержек на разработку нового железа, нет издержек на расширение элементной базы...

Вот именно. Когда оборудование стОит 1000000 рублей, то пофиг, сколько стоит контроллер, им управляющий, 10000 или 50000. Главное, что он есть, готовый, проверенный, всем знакомый. Зарплаты людей, применяющих этот контроллер, многократно больше разницы в стоимости, поэтому важней становится время на получение работающего результата.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, juvf сказал:
//Передает вы её очевидно так
void main()
{
  	struct FlexFrame frame;
	writeTxFIFO( (u8*)&frame, sizeof(frame));
 }

Нет не так. Структурой я описываю все содержимое кадра - хедеры, данные и т.д., в том числе CRC. Обрамление кадра - совершенно другая процедура, ее структарми не опишешь. Да и незачем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 minutes ago, Arlleex said:

Обычно в этом корень всех бед.

Почему? Число ведь берётся не от балды, а их опыта применения подобных вещей. Даже если перестанет хватать, поставлю МК с бОльшим объёмом ОЗУ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, tonyk_av сказал:

Почему? Число ведь берётся не от балды, а их опыта применения подобных вещей. Даже если перестанет хватать, поставлю МК с бОльшим объёмом ОЗУ.

Цитата

Априори не известно, сколько программист создаст запросов по Modbus и I2C. Задался разумным числом и выбрал МК с подходящим объёмом ОЗУ.

Разумное число - у всех разное, поэтому его либо заранее обговаривать в ТЗ, либо пытаться сделать так, чтобы программист вообще об этом не думал - т.е. технически победить ограничение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

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

Я структурой описываю заголовок данных, от него наследую структуры данных. При приеме привожу приемный буфер к типу generic_data (фактически - голый заголовок), по нему определяю тип пакета и тогда уже привожу к типу конкретного пакета и обрабатываю соответствующим образом. 

А обрамление кадра (при необходимости) описываю шаблоном, параметром которого является структура данных. В этом же шаблоне размещаю и CRC (чисто для визуализации). По факту при передаче CRC считаю на лету и вставляю приведением указателя в конце расчета. Или прямым запихиванием в передатчик.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Сергей Борщ сказал:

В этом же шаблоне размещаю и CRC (чисто для визуализации). По факту при передаче CRC считаю на лету и вставляю приведением указателя в конце расчета.

Вот я и хотел, чтобы визуально CRC присутствовала в структуре, чтобы и мне (спустя время) и другому человеку было понятно, что содержится в теле пакета.

В чем текущее неудобство. Пример.

К МК подцеплен езернет и CAN, и пусть это будет некий преобразователь интерфейсов. Езернет цепляется к компу.
Комп периодически поллит входящую очередь CAN-а, для чего шлет пакет-запрос READ_CAN_FIFO. МК по этому запросу формирует ответ в виде структуры

struct ReadCANAck {
  Header   hdr;
  CANFrame frame[];
};

Вопрос - где эту структуру создать в памяти. Понимаем, что нижестоящие функции отправки в сеть требуют структуру "целиком", т.е. непрерывным массивом известной длины. Значит можно запихнуть эту структуру в union

#define MAX_SEND_MESSAGE_SIZE MAX_ETH_UDP_PAYLOAD_SIZE

union SendMessage {
  ReadCANAck readCANAck;
  ...                  ; // возможно, другие "форматки" для других команд
  u8 buffer[MAX_SEND_MESSAGE_SIZE];
};

Мы заранее не знаем, сколько там в CAN-е может храниться принятых кадров, поэтому после заполнения хедера ответа, мы читаем N кадров CAN-FIFO и заполняем свободное место пэйлоада езернет-фрейма, чуть ли не вот так

static SendMessage Tx;

void sendCANRxFIFO() {
  // не насилуем стек - готовим кадр в одном месте
  Tx.readCANAck.hdr.cmd = READ_CAN_FIFO;
  
  // сколько там в CAN фреймов пришло?
  u32 const frameCnt = CAN.getFrameCnt();
  
  // запихиваем CAN-кадры из его FIFO, пока место в буфере отправки в езернет еще есть
  for(u32 i = 0; i < frameCnt; ++i) {
    if(/* места в езернет-фрейме еще хватает ? */)
      Tx.readCANAck.frame[i] = CAN.readFrame();
  }
}

и вот теперь: беда. Мы договорились, что в протоколе обмена все кадры имеют CRC последним членом. Тут (примера ради) его не было показано. Но этот CRC подразумевался. В структуре ReadCANAck его нельзя после frame[] поставить.

И это порождает 2 проблемы:
1) визуально нет поля CRC в пакете - т.е. или я, или сторонний разраб, которому я дам эту структуру, может "забыть", что там еще CRC считать надо и заполнять (а еще и место в памяти выделять!);
2) после заполнения основных указанных полей, в силу "отсутствия" явного описания CRC в структуре отправки - мы должны костыльными приведениями типов и адресацией залезть за последний записанный frame и вставить туда CRC. Это может (и будет!) выглядеть плохо! Так как сходу не будет понятно, с какого лешего мы пишем "за пределы структуры" какую-то там CRC:

void sendCANRxFIFO() {
  ...
  u32 i;
  
  // запихиваем CAN-кадры из его FIFO, пока место в буфере отправки в езернет еще есть
  for(i = 0; i < frameCnt; ++i) {
    if(/* места в езернет-фрейме еще хватает ? */)
      Tx.readCANAck.frame[i] = CAN.readFrame();
  }
  
  *(u32 *)&Tx.readCANAck.frame[i] = calcCRC32(&Tx, /* правильно посчитать len */); // <- через пару месяцев: WTFFFFFFFFFFFF???
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, Arlleex said:

Разумное число - у всех разное

Оно потому и разумное, что выбирается из соображений каких-либо физических ограничений, когда иное не прописано в ТЗ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Из крайнего проекта (извернулся трюком с union, но это все равно громоздко и муторно):

// это с компа надо отправить в железку, а та отправит в свой RS-485 len байт
struct sTxMsgRS485SendCmd {
  sMsgHdr hdr;
  eMsgUID uid;
  u32     ifNum;
  u32     len;

  union {
	u8  byte[MAX_RS485_TX_SIZE + sizeof(u32)];                // - эта добавка sizeof() как раз для CRC-поля
	u32 crc[(MAX_RS485_TX_SIZE + sizeof(u32)) / sizeof(u32)]; // а это чтоб представить весь буфер как набор u32 crc[]
  };
};

...

void send() {
  sTxMsgRS485SendCmd tx;
  
  tx.hdr.srcAddr = HOST_ADDR;
  tx.hdr.dstAddr = MBC_ADDR;
  tx.uid         = WORK_REQ_MBC_SEND_RS485;
  tx.ifNum       = 0;
  
  u32 const len = /* считал с окошка программы */;
  u32       i   = 0;
  
  while(i < len && i < MAX_RS485_TX_SIZE)
    tx.byte[i] = /* чтение с окошка ввода */()[i++];
  
  tx.len = i;
  
  if(i > 0) {
    i = (i + 3) / 4; // ровняю по u32

    u32 const size = sizeof(tx) - (MAX_RS485_TX_SIZE - i * 4); // началось в деревне лето... считаю общий размер кадра

    tx.crc[i] = crc_Calc(&tx, size / 4 - 1); // фокус с union <- вот он
    
    /* ethernet_send() */(&tx);
  }
}


Ну вот визуально - полная шляпа выходит)) А хотелось копеечка к копеечке - все заполнили и отправили, без хитрых представлений и закулисных допущений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...