EdgeAligned 81 31 мая Опубликовано 31 мая · Жалоба Вот для примера: проследите за DC Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 31 мая Опубликовано 31 мая · Жалоба 1 час назад, Arlleex сказал: Только у Вас "хитрость" - по сути все send_command имеют тип аргументов "массив" или "что-то, что можно упаковать в массив". Так и для дисплея же любая команда - поток байтов. Наша задача - объяснить компилятору, что любую команду надо трактовать как набор N байтов с некоего начального адреса. 1 час назад, Arlleex сказал: Но send_command(1, 2), например, - уже ошибка. Увы, это два int. Старшие байты будут нулями. Придумал их только как массив шестнадцатиричных кодов символов (вроде исправил в сообщении, но почему-то не сохранилось): send_command({'\x01', '\x02'}); А я все команды описываю в виде осмысленных структур и уже структуры отсылаю через template<typename T> void send_command(T const & what) { send_command(&what, sizeof(T)); } примерно так: Спойлер namespace tdf8599 { namespace core { union instruction { struct { uint8_t Mode : 1; // 0 = standby, 1 = mute/operating uint8_t Ch1_disable : 1; uint8_t : 1; uint8_t OSC_increase : 1; // 0 = Rosc - 10%, 1 = Rosc + 10% uint8_t Freq_hopping_enable : 1; uint8_t Ch1_clip_detect_disable : 1; // clip detection on CLIP pin uint8_t Ch1_offset_monitor_disable : 1; uint8_t Offset_out_disable : 1; // offset detection on DIAG pin uint8_t Mute : 1; // 0 = operating, 1 = mute uint8_t Ch2_disable : 1; uint8_t DC_load_detection : 1; uint8_t Temp_pre_warning : 1; // 0 = 140 deg.C, 1 = 120 deg.C uint8_t Thermal_pre_warning_disable : 1; // thermal pre-warning on CLIP pin uint8_t Ch2_clip_detect_disable : 1; // clip detection on CLIP pin uint8_t Ch2_offset_monitor_disable : 1; uint8_t Offset_protection_disable : 1; uint8_t Modulation : 1; // 0 = AD, 1 = BD uint8_t OSC_phase_shift : 3; // 0 = 0, 1 = 1/4pi, 2 = 1/3 pi, 3 = 1/2pi, 4 = 2/3pi, 5 = 3/4pi uint8_t AC_load_detection : 1; uint8_t : 2; uint8_t ADS_MOD_latch : 1; // 0 = latch on switching start, 1 = latch immediately }; uint8_t Raw[3]; }; .... }; bool out_amp::load(config::amplifier const volatile & settings) { Control = tdf8599::core::instruction( { settings.Mode != config::amplifier::mode::STANDBY, false, // Ch1_disable !!settings.OSC_increase, !!settings.Freq_hopping, !settings.Clip_detect_enable, !settings.Offset_monitor_enable, false, // Offset detection on DIAG pin disable settings.Mode == config::amplifier::mode::MUTE, false, // Ch2_disable !!settings.DC_load_detect, !!settings.Temp_pre_warning, !settings.Temp_pre_warn_enable, !settings.Clip_detect_enable, !settings.Offset_monitor_enable, !settings.Offset_protection_enable, !!settings.Modulation, 0, // OSC_phase_shift !!settings.AC_load_detect, true, // ADS_MOD_latch }); return Chip.setup(Control); } 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 31 мая Опубликовано 31 мая · Жалоба 21 минуту назад, Сергей Борщ сказал: А я все команды описываю в виде осмысленных структур и уже структуры отсылаю через template<typename T> void send_command(T const & what) { send_command(&what, sizeof(T)); } Вся соль в моей этой самой буферизации транзакций, о которой я на прошлой страничке в конце написал. Каждый дескриптор состоит из одного 32-битного слова. Но в зависимости от ключевого поля обработка этих дескрипторов будет вестись по-разному. Например, при желании отправить большой битмап в экран, я записываю в дескриптор адрес участка памяти (ОЗУ или Flash) и размер. Ну, еще состояние ножки DC. В этом случае (например, при отправке из ОЗУ) сам буфер нужно держать какое-то время (пока не отправится). А вот команды-коротыши целиком влезают в мой дескриптор как есть: до трех байтов (в моем экране куча таких команд - одно-двухбайтных). Я посчитал, что такие байтики я могу пихнуть в дескриптор, а при декодировании дескриптора происходит их копирование в 1 32-битное слово ОЗУ (статически выделенное слово) и уже на этот адрес натравливается DMA - посылка полетела. Так удобно не только команды отправлять, но и всякие "мелкие" кракозябры на экран - например, мигающие точки, символы и т.д. Отправка стуктурами - легко! В конце концов (вот собственно в этом и вопрос сейчас с плюсами и шаблонами) - вызовется вариант send(addr, size), он установит дескриптор в режим "SEND_FROM_FLASH" или "SEND_FROM_RAM" в зависимости от численного значения addr и заполнит size, чтобы потом DMA-контроллер считал этот адрес и размер и начал транзакцию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 31 мая Опубликовано 31 мая · Жалоба 2 hours ago, Arlleex said: Поэтому наследования от наследования от трижды абстрактных классов - нет нет нет)) если так пугают простые наследования, то шаблоны вообще должны приводить в ужос )) 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 2 июня Опубликовано 2 июня · Жалоба В общем купил себе книжечку, толстееееннную)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 81 2 июня Опубликовано 2 июня (изменено) · Жалоба Самое смешное, что через некоторое время она станет неактуальной. Нынче год какой у нас? Кажись 2024, не так ли? А в книжечке описан стандарт, максимум, с++17. Стандарт С++11 вообще уже неактуален, эту часть можно вообще пропускать. Хотя, оно конечно, для изучения всегда пользительно. Правда, я сейчас чаще прибегаю к помощи различных GPT. Например, по теме вопроса вот что ИИ ответил: Прекрасный выбор, работать с variadic шаблонами в C++17 может быть очень мощным и удобным способом обработки различного количества аргументов в шаблонных функциях и классах. Вот как можно использовать variadic шаблоны в C++17: 1. **Шаблонные функции**: #include <iostream> // Базовый случай для рекурсивной функции void processArgs() {} // Рекурсивная функция для обработки всех аргументов template<typename T, typename... Args> void processArgs(T first, Args... args) { std::cout << first << std::endl; processArgs(args...); } int main() { processArgs(1, "two", 3.0, '4'); return 0; } Распаковка параметров(pack expansion): #include <iostream> template<typename... Args> void printAll(Args... args) { ((std::cout << args << " "), ...); std::cout << std::endl; } int main() { printAll(1, "two", 3.0, '4'); return 0; } Шаблоны классов с переменным числом аргументов: #include <iostream> template<typename T, typename... Args> class Tuple { public: Tuple(T first, Args... rest) : head(first), tail(rest...) {} T head; Tuple<Args...> tail; }; template<typename T> class Tuple<T> { public: Tuple(T first) : head(first) {} T head; }; int main() { Tuple<int, std::string, double> myTuple(10, "hello", 3.14); std::cout << myTuple.head << std::endl; std::cout << myTuple.tail.head << std::endl; std::cout << myTuple.tail.tail.head << std::endl; return 0; } ну и так далее Изменено 2 июня пользователем EdgeAligned Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 3 июня Опубликовано 3 июня · Жалоба 12 часов назад, EdgeAligned сказал: Например, по теме вопроса вот что ИИ ответил: Без понимания основ тыкать чат-GPT и пытаться учиться у него довольно тупиковая стратегия) Он дергает всякого рода портянки как со стековерфлоу. Поэтому лучше как-то по старинке - книжечку листать. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 3 июня Опубликовано 3 июня · Жалоба 29 минут назад, Arlleex сказал: Без понимания основ тыкать чат-GPT и пытаться учиться у него довольно тупиковая стратегия) Он дергает всякого рода портянки как со стековерфлоу. это гугл/яндекс дергает портянки из стекоферфлоу. а гпт генерирует ответ на "знаниях", полученных из стекоферфлоу (причем со всех языков), вики, справочников, стандартов, в том числе и с книжек, подобно вашей про шаблоны. Чтоб вам получить эти знания (хотябы 1 раз прочитать, не то что получить и применить) - вам жизни не хватит. Конечно gpt3.5 "знает" всё только до 2022 и у него нет выхода в инет, gpt4o уже знает посвежее, а также может поискать за тебя в инете, если что сам не знает. Скормите в gpt4o весь свой вопрос в полный рост Цитата Хочу заиметь 2 функции: sendCommand() и sendData(). Они на 99.99% идентичны друг другу, и хотелось бы, чтобы в их телах производился вызов другой "общей" функции с правильно подсунутыми параметрами (возможно, не шаблонными). template<args> void send(int dataCommand, args) { // тут уже надо распарсить, сколько аргументов реально, какие их типы и т.д. } template<...> void sendCommand(...) { send(0, ...); } template<...> void sendData(...) { send(1, ...); } В конечном итоге хочу получить возможность вот такой записи // аргументы - простые целые числа sendCommand(0x12); // должно вызваться send(0, 0x12) sendCommand(0x12, 0x34); // должно вызваться send(0, 0x12, 0x34) sendCommand(0x12, 0x34, 0x56); // должно вызваться send(0, 0x12, 0x34, 0x56) sendData(0x12, 0x34); // должно вызваться send(1, 0x12, 0x34) // аргументы - массив или строка sendCommand("hello"); // должно вызваться send(0, const char (&)[6]) u8 buf[3]; sendData(buf); // должно вызваться send(1, u8 (&)[3]) Т.е. могу вызывать перегрузку с целыми аргументами в количестве от 1 до 3, а могу запихивать прямо массив или строку - для этого передача идет по "ссылке на массив", чтобы в send() можно было взять N или sizeof(buf). На вариативных шаблонах витиевато, не знаю - вообще возможно ли это. вы будете удивлены ответу. и если он выдаст вам std::forward<Args>, скажите ему Цитата а std::forward() здесь обязателен? Т.е. можно ли обойтись без обращения к std вовсе? И вы опять будете удивлены. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 3 июня Опубликовано 3 июня · Жалоба В 31.05.2024 в 19:41, Arlleex сказал: Т.е. можно ли обойтись без обращения к std вовсе? В 31.05.2024 в 22:15, Arlleex сказал: Было бы здорово, если можно было бы перегрузить реализации send() под 2 варианта: аргумент-массив, и аргумент-список (параметры через запятую). если без std, то не получится определить переменное кол-во аргументов. для поддержки разного числа аргументов, нужен перегруз функции sendCommand и sendData для одного, двух и трех аргументов. Если нужно больше аргументов, то добавить соответствующие перегрузки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 3 июня Опубликовано 3 июня · Жалоба 49 минут назад, juvf сказал: если без std, то не получится определить переменное кол-во аргументов. для поддержки разного числа аргументов, нужен перегруз функции sendCommand и sendData для одного, двух и трех аргументов. Если нужно больше аргументов, то добавить соответствующие перегрузки. А что такого магического над C++ делает стандартная библиотека? Насколько я понимал, что C++ и std это вещи хоть и тесно связанные, но не до уровня разрешения синтаксиса. Ведь переменное кол-во аргументов - это фишка компилятора C++, а не библиотек. Разве не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 81 3 июня Опубликовано 3 июня · Жалоба Да в том то и дело, что вариативный шаблон реализован на уровне заплаток над ядром языка. Концепция существует аж со стандарта 2011 года, но так до сих пор и не реализована в адекватном инструментарии. Ядро языка исправлять уже никто не будет, поэтому улучшение инструментария только за счет дополнительных заплаток. STD и stlкак раз представляют собой обширную коллекцию заплаток разного рода, Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 3 июня Опубликовано 3 июня · Жалоба В 03.06.2024 в 13:23, Arlleex сказал: это фишка компилятора C++, а не библиотек да самому стало интересно.... // Online IDE - Code Editor, Compiler, Interpreter #include<stdio.h> #include <iostream> template<typename... Args> void send(int firstByte, Args... args) { auto print = [](auto& arg) { std::cout << arg << " "; };//лямда, дла печати каждого аргумента std::cout << (firstByte == 0 ? "code0()" : "code1()") << std::endl; (print(args), ...); std::cout << std::endl; } // Обертка для sendCommand template<typename... Args> void sendCommand(Args... args) { send(0, args...); } // Обертка для sendData template<typename... Args> void sendData(Args... args) { send(1, args...); } int main() { // Примеры использования std::cout << "sendCommand(0x12) -> "; sendCommand(0x12); // вызовется send(0, 0x12) std::cout << "sendCommand(0x12, 0x34) -> "; sendCommand(0x12, 0x34); // вызовется send(0, 0x12, 0x34) std::cout << "sendCommand(0x12, 0x34, 0x56) -> "; sendCommand(0x12, 0x34, 0x56); // вызовется send(0, 0x12, 0x34, 0x56) std::cout << "sendData(0x12, 0x34) -> "; sendData(0x12, 0x34); // вызовется send(1, 0x12, 0x34) // Примеры с массивами и строками std::cout << "sendCommand(\"hello\") -> "; sendCommand("hello"); // вызовется send(0, "hello") unsigned char buf[3] = {0x01, 0x02, 0x03}; std::cout << "sendData(buf) -> "; sendData(buf); // вызовется send(1, buf) return 0; } Проверил тут на с++17. выхлоп Цитата sendCommand(0x12) -> code0() 18 sendCommand(0x12, 0x34) -> code0() 18 52 sendCommand(0x12, 0x34, 0x56) -> code0() 18 52 86 sendData(0x12, 0x34) -> code1() 18 52 sendCommand("hello")) -> code0() hello sendData(buf) -> code1() 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 3 июня Опубликовано 3 июня · Жалоба 47 минут назад, juvf сказал: да самому стало интересно.... Вечером буду вникать в написанное) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 3 июня Опубликовано 3 июня · Жалоба В 03.06.2024 в 15:55, juvf сказал: sendData(buf) -> code1() вот тут мне не понравилось. тут нужно докрутить. возможно нужно ещё одну send перегрузить для массивов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 3 июня Опубликовано 3 июня · Жалоба То что ничего не вывело? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться