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

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

47 минут назад, Arlleex сказал:

Потом сел, открыл дизасм и волосы дыбом.

:biggrin::biggrin::biggrin:  Точно!

Просто гуру с++ не открывают дизасм никогда.  :biggrin:

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


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

 

1 minute ago, Arlleex said:

Мне было интересно узнать, как это сделать в плюсах, чтобы не поломать ни идеологию ООП, ни пуре-Си-шное преимущество генерировать оптимальный быстрый код.

Сделать отдельный метод для ее установки: 

void xxxxx::CAN::setBitrate(Bitrate bitrate);

 

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


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

43 минуты назад, Сергей Борщ сказал:

по мере появления/развития новых проектов иногда приходится дописывать или даже радикально менять уже написанные классы в этом репозитории (с таким расчетом, чтобы не поломать совместимость со старыми проектами или хотя бы чтобы вызвать ошибку компиляции в старых проектах)

Ну да, а потом берётся старый проект, уже давно реализованный, отлаженный, состоящий из десятков тысяч строк кода, компилится, и.... начинает глючить. И хорошо если этот глюк вылезает сразу, на столе, стабильно; а не у заказчика, лишь иногда. А если он не находится, всё это кладётся в этот репозиторий, а вылезает лишь позже, через какое-то количество итераций таких изменений.  :shok:

Любое изменение кода - требует полноценной отладки, затем - опытной эксплуатации. И если проделывать такое с линейкой выпускаемых серийно устройств, потому что "сейчас я что-то новое пишу и вношу изменения в репозиторий, той библиотеки которая используется во всех этих проектах".... :shok:

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


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

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

Вы сами доказали это своим примером установки скорости CAN через callback.

Ну чисто теоретически, в моем примере компилятор, видя const у указателя на функцию, мог бы даже попробовать либо встроить вызов такой функции, либо вызвать SetBaudRateCAN1() без использования указателя. Тут да, как повезет, ИМХО.

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


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

3 minutes ago, jcxz said:

Ну да, а потом берётся старый проект, уже давно реализованный, отлаженный, состоящий из десятков тысяч строк кода, компилится, и.... начинает глючить. И хорошо если этот глюк вылезает сразу, на столе, стабильно; а не у заказчика, лишь иногда. А если он не находится, всё это кладётся в этот репозиторий, а вылезает лишь позже, через какое-то количество итераций таких изменений.  :shok:

Это не проблема языка. Это проблема управления конфигурациями ПО. Уже, кстати, решена, и не раз.

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


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

12 минут назад, Forger сказал:

void xxxxx::CAN::setBitrate(Bitrate bitrate);

Дык к SLCAN-протоколу этот метод какое отношение будет иметь? Никакого. Я хочу, чтобы, допустим пользователь моего класса SLCAN::cSlave (я), создавая объект (ну назовем его сокет, или интерфейс, без разницы), сразу понимал, чего от него еще требует этот класс. Вот не предоставил программист обработчик, который установит на нужном CAN-е нужную скорость - проект не скомпилился.

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


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

10 minutes ago, Arlleex said:

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

Ты хочешь, чтобы программа была умнее программиста. Этого не будет.

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


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

45 minutes ago, Forger said:

Статья по нему

Отлично! О! Кстати, эту статью я читал, но не осилил по пониманию. Но теперь у меня есть точные данные, что этот делегат работает. Попробую со свежими силами на досуге снова поразбираться. Спасибо!

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


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

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

Этого не будет.

В разумных пределах - еще как будет.

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

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


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

21 minutes ago, jcxz said:

компилится, и.... начинает глючить

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

22 minutes ago, jcxz said:

Любое изменение кода - требует полноценной отладки

Поскольку в случае того же git это делается принудительно (изменение кода), то программист вполне осмысленно может начать тестировать свой код. Либо оставить проект на каком-то предыдущем коммите сабмодуля.

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


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

19 минут назад, jcxz сказал:

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

Значит так он был написан...

20 минут назад, jcxz сказал:

И если проделывать такое с линейкой выпускаемых серийно устройств, потому что "сейчас я что-то новое пишу и вношу изменения в репозиторий, той библиотеки которая используется во всех этих проектах"

Для серийно выпускаемых устройств есть отдельная ветка tags, куда фиксируется именно то состояние всего репозитория и ссылки на те ревизии внешних репозиториев, которые используются на производстве. И из этой ветки всегда выкачивается одно и то же состояние исходников вне зависимости от количества последующих правок в стволе.

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


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

26 минут назад, Arlleex сказал:

Ну чисто теоретически, в моем примере компилятор, видя const у указателя на функцию, мог бы даже попробовать либо встроить вызов такой функции, либо вызвать SetBaudRateCAN1() без использования указателя. Тут да, как повезет, ИМХО.

Вот именно что "как повезёт"....

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

Например с этой же установкой скорости: Люди всегда сидящие на одном МК (или семействе) не могут представить себе всего разнообразия возможных параметров, нужных для инициализации какой-то периферии. И такой человек, посмотрев, что для данного МК например для установки скорости, нужна только собственно сама скорость (в бодах), так и спроектирует функцию - принимающую только значение скорости в бодах. А потом окажется, что на каком-то новом МК, на который потребовалось перейти, этого недостаточно и нужно передавать ещё и другие параметры.

А это значит:

во-первых - переписать свою реализацию класса, изменив формат указателя и все точки его вызова (во всех проектах);

во-вторых - в старых устройствах, на старом МК (где для инита требовалась только скорость), соответственно придётся добавить неиспользуемые там аргуенты в функцию установки скорости (ну или вообще переписать полностью, передавая не саму скорость (по значению), а указатель на структуру, содержащию или только скорость или скорость + другие необходимые для инита аргументы); А значит в тех старых проектах на старых МК однозначно появится неоптимальность (лишние параметры при вызове или обращение к структуре, вместо явной передачи одной скорости).

 

Для примера приведу объявление своей функции инициализации UART для STM:

u32 UARTinit(u32 baudrate, HwRegsUART volatile *io);

и для XMC4xxx:

HwRegsUSIC::T_CH volatile * UartInit(u32 baudrate, u32 format, int usic_ch, int dxn)

а используются обе в одном и том же драйвере: потоке отладочного вывода. Но во 2-м случае не обойтись без дополнительных параметров (в хвосте usic_ch - номер канала USIC (в одном USIC - 2 UART) и dxn (трудно коротко объяснить что такое, надо читать мануал на XMC4xxx :wink:  )). И то же самое с классом Uart (используемым этим драйвером отладочного вывода) - он у меня разный, с совершенно разными членами для этих 2-х МК, так как очень сильно они различаются внутри у STM32 и XMC4xxx и если пытаться сделать единый общий класс, то он будет очень неоптимальным.

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


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

21 минуту назад, jcxz сказал:

А потом окажется, что на каком-то новом МК, на который...

В Вашем случае да, я это понимаю. Однако я чисто за SLCAN - он уже вряд ли кем-то когда-то будет меняться. В нем все довольно тривиально: прилетела строка символов вида "Sx\r" (без '/0' и где x от 0 до 8, каждой цифре соответствует строго определенная скорость: 10кбит/с, 20, 50, 100, 125, 250, 500, 800 и 1Мбит/с), извлекаем эту цифру и вызваем setBaudRate() с этой цифрой в качестве аргумента. А как конкретно будет реализован setBaudRate() - не ума класса SLCAN::cSlave дело. ИМХО, всякий контроллер должен уметь настроить скорость CAN под одну из вышеприведенных скоростей. Как - пусть конкретная функция, на которую setBaudRate в этом классе указывает, знает. Задача setBaudRate() - передать управление той реальной функции, которая установит на нужном CAN-е (их же может быть много) нужную скорость.

Опять же, в том же проклятом SLCAN есть команды, которые устанавливают всякие фишки-плюшки, присущие сугубо CAN-контроллеру SJA1000: но их реализовывать я просто не вижу смысла, т.к. там ровно то, о чем Вы говорите - регистры совершенно другие, фильтры тоже совершенно по-другому работают и настраиваются. Такие команды у меня обрабатываются в стиле "ок, схавал, но делать я, конечно же, ничего не буду", иначе какой-нибудь очередной сокет в linux, связанный с железкой по CAN-у, раком встанет. Хотя, в силу того, что одну и ту же скорость контролирует несколько параметров (TS1, TS2, SJW), приходится перекодировать формат команды установки этих значений из SJA1000 в тот, который понимает МК со своим набором регистров.

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


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

8 минут назад, haker_fox сказал:

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

Всё равно в конце-концов придётся или обновлять или этот "сабмодуль" распадётся на 2 параллельные ветки. Потому как - сегодня мы правим проект 2 (старый проект 1 живёт на старой версии), потом занимаемся другими работами, а потом оказывается что в проект 1 нужно внести изменения в тот же самый класс, который мы правили в проекте 2 (но не обновили), и теперь вместо того чтобы просто внести эти изменения, оказывается что перед этим нужно ещё на проекте 1 отладить все изменения сделанные от той версии класса на которой он застрял, до последней!!!... А для этого нужно провести кучу испытаний (где-нить в лаборатории) :shok:  А времени как правило нет, потому как нужно просто внести мелкое дополнение.

И сразу встаёт выбор:

1) или внести это мелкое дополнение в последнюю версию и на эту последнюю версию перевести старый проект (без всех необходимых испытаний!), на свой страх и риск забив на возможные грабли;

2) или развалить этот "сабмодуль" на 2 параллельные ветки, написав где-то "когда появится время, надо будет обязательно слить эти ветки!").

Последствия понятны: в 1-м случае - получаем потенциальные баги; во-2-ом - размножение веток "сабмодуля" на множество параллельных (так как времени на слияние всегда нет).

 

8 минут назад, haker_fox сказал:

Поскольку в случае того же git это делается принудительно (изменение кода), то программист вполне осмысленно может начать тестировать свой код.

Одно дело когда только "программист должен протестировать", а когда у вас серийное изделие, работающее в ответственной сфере, то любое изменение кода должно пройти кроме "тестирования на столе у программиста", ещё тестирование в испытательной лаборатории (несколько недель), а потом ещё месяц-два опытной эксплуатации на объекте заказчика (с возможным монтажём/демонтажём и привлечением сторониих специалистов).

20 минут назад, Сергей Борщ сказал:

Значит так он был написан...

Да, согласен, есть баги. Но мой многолетний опыт говорит о простой истине: "Не бывает программ без багов, бывают только программы с ещё не найденными багами". И некоторые из них могут спать много лет, не проявляясь.

И чем сложнее ПО, тем больше в нём потенциальных багов.

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


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

Я бы сделал так (как собственно  меня и реализовано в разных проектах) - драйвер CAN, набор функционала которого зависит от ядра, но есть, конечно, базовые для всех МК методы: базовая начальная инциализация (после подачи питания) и настройка скорости.

Все остальное - в зависимости от МК.

В самих проектах в зависимости от типа МК используем разный набор этих методов.

 

Так вот общий базовый класс каждой периферии по сути изолирует код от железа, что очень помогает даже в рамках одного проекта создавать прошивку под разные МК (без #ifdef пока не получается, но и цели пока такой нет).Вот для иллюстрации пример:

 

Spoiler

 


class CommunicationLib : public Communication
{
	virtual void initialize()

	class Thread : public OS::Thread<COMMUNICATION_STACK_SIZE>
	{
		virtual void initialize() final;
		virtual void body() final;
		void irqRxFrame();

	private:
	
		Hardware::Pin<PA12>	pinCAN_TX;
		Hardware::Pin<PA11> pinCAN_RX;
	
		Hardware::CAN::Frame rxFrame;
		Hardware::CAN::Frame txFrame;

		Hardware::PortCAN1 port;
	
.....
		
	} thread;
};




void CommunicationLib::Thread::initialize()
{
	port.initialize();
	port.setPinTx(pinCAN_TX);
	port.setPinRx(pinCAN_RX);
	port.setBitrate(COMMUNICATION_DEFAULT_BITRATE);

	auto vectorRX0 = DELEGATE(&Thread::irqRxFrame, this);
	port.installVectorRX0(vectorRX0);
	port.irq.RX0.messagePending.enable();

	txFrame.isExtendedId 	= true;
....

	port.run();

.....
}

void CommunicationLib::Thread::body()
{
  	// Wait for ANY CAN frame with timeout
	if (not semaphoreFrameRx.isWaitDoneFor(kFrameTimeoutMs)) 
.....
    
}


......
  
void CommunicationLib::Thread::irqRxFrame()
{
	if (port.irq.RX0.messagePending.isPending())
	{
		port >> rxFrame;
		if (rxFrame.isExtendedId) semaphoreFrameRx.signal(); // Only 29-bit ID is supported
	
....	
	}
}

 

 

 

 

 

Следуя описанному примеру достаточно будет дать ссылку на экземпляр конкретного драйвера CAN в некую SLCAN библиотеку, где она сама вызовет нужный ей метод настройки скорости. Привязки к железу нет. Задача решена )

 

Более того, в свете дефицита МК такая схема позволяет очень просто переходить на другие МК или даже создавать разные прошивки под разные МК в рамках одного проекта (платы немного разные, ведь распиновка совпадает тока у STM и GD).

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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