haker_fox 61 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 37 minutes ago, cybersonner said: это функция, которая по итогу будет вызвана Теперь я понял о чём Вы! Это называется retargeting ли как-то так. Давно этим не занимался. Если по-русски, то это определение низкоуровневой функции вывода в физический канал (последовательный порт, Ethernet и т.п.). 1 hour ago, cybersonner said: printf делается примерно так Сама фраза просто смутила. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 6 часов назад, haker_fox сказал: фантастически звучит Ваш каждый пост с учётом норм русского языка. У вас кстати тоже с русским есть проблемы: 2 часа назад, haker_fox сказал: OsApi::MutexLocker mutex(s_mutex); // ждём мьютекс, т.к. мы ни одни используем форматированный вывод в консоль "нЕ одни" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 1 minute ago, jcxz said: У вас кстати тоже с русским есть проблемы: Вы правы) Из психологии известно, что то, что мы видим в других, есть и в нас... Но я немного оправдаюсь: 1. Комментарий писал быстро уже в форме редактора кода форума, т.к. такие "в лоб" комменты я не ставлю. Код самодокументируем. Согласен, это не оправдание. 2. Я автору указывал больше не на орфографию, а на стиль изложения, ибо плохо понятно, что он там вообще имеет в виду. Согласен, и это не оправдание. Но спасибо, что поправили! Писать следует грамотно! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба И кстати - я не понял, почему у вас в функции есть вроде как захват(?) мьютекса, но нет его освобождения в конце функции? Или освобождается он деструктором? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 1 minute ago, jcxz said: И кстати - я не понял, почему у вас в функции есть вроде как захват(?) мьютекса, но нет его освобождения в конце функции? И у Вас ошибка. Местоимение должно быть с большой буквы при обращении к одному лицу))) Мьютекс освобождается в деструкторе в тот момент, когда мы покидаем функцию. Происходит это автоматически. В этом и прелесть Си++) class MutexLocker { public: MutexLocker( Mutex &mt ) : m_mt(mt) {} RetVal take( size_t timeout_ms ) { return m_mt.take(timeout_ms); } ~MutexLocker() { m_mt.give(); // Вот тут мьютекс освобождается } private: Mutex m_mt; }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 8 минут назад, haker_fox сказал: Мьютекс освобождается в деструкторе в тот момент, когда мы покидаем функцию. Происходит это автоматически. В этом и прелесть Си++) Очень громоздко это всё. Большие накладные расходы: конструктор, захват, освобождение, деструктор. И это всё на вывод может всего одного символа... К тому же негибко, если не ошибаюсь. Например: Обычно если много задач обращаются к отладочному выводу, то они должны писать в него функционально законченные осмысленные сообщения. Хорошо, когда одно сообщение формируется полностью одним вызовом такого kprintf(). А если нужно сформировать строку (или блок строк) несколькими такими вызовами? И чтобы другой процесс не влез в его середину. Можно это сделать с помощью вашей реализации kprintf()? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 9 minutes ago, jcxz said: Очень громоздко это всё. Признаюсь, в листинг специально для этого не глядел. А что там громоздко? Конструктор и деструктор делают то же самое, что и ручками бы пришлось делать. Может быть и есть какие-либо накладные расходы. Но меня устраивает. Для одного символа это выглядит серьёзно. Но ведь обычно выводятся строки (у меня) и из разных процессов. З.Ы. Некоторые вещи из Си++ применяю впервые, и смотрю листинг. Так вот, порой видно, что компилятор генерирует "тупо" рабочий код без излишеств. Недавно мне понадобилась такая штука: функция с вариативным количеством аргументов. Естественно, одного типа. И количество определяется на этапе компиляции. Посмотрел в листинг, а там просто делается всё то же самое, что я бы делал вручную. При этом удобство использования отличается напорядки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 3 минуты назад, haker_fox сказал: Признаюсь, в листинг специально для этого не глядел. А что там громоздко? Конструктор и деструктор делают то же самое, что и ручками бы пришлось делать. Нет. Без них там был бы просто PUSH в начале и POP - в конце (скорее даже - без POP, а просто переход на функцию). С ними будет больше (скорей всего вызовы функций). А самое главное - см. 2-ю часть моего поста. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 12 minutes ago, jcxz said: Можно это сделать с помощью вашей реализации kprintf()? К сожалению, нет. У Вас есть решение?) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 31 минуту назад, haker_fox сказал: К сожалению, нет. У Вас есть решение?) Я напишу как делаю я. Пример функции (функция при старте ПО выводит в лог причину старта МК, декодированную из соотв.регистров МК): inline void TypResetPrint() { #ifdef LOG0 static char const tRst[] = "PORST\0" "SWD\0" "PV\0" "CPU system\0" "CPU lockup\0" "WDT\0" "unknown\0" "parity error"; LogCatchOut0(); Logs0(COL_PURPLE "Start after "); char const *s = tRst; uint i = typReset; if (!i) i = 1 << TYPRST_unknown; do { if (i & B0) Log0(COL_BLACK "%s" COL_PURPLE " %s", s, (i >> 1) ? "+ ": ""); s += strlen(s) + 1; } while (i >>= 1); LogsCR0("reset"); LogReleaseOut0(); #endif } Logs...(), LogsCR...() - вывод строки (char const *) без перевода строки в конце и с переводом (соответственно). Log...(), LogCR...() - вывод в формате printf(), но с переводом строки в версии с суффиксом CR. Цифра в конце - номер канала лога (у меня 10-канальный отладочный поток; разные службы/драйвера используют разные каналы; каналы можно разрешать/запрещать глобально в глобальном .h-файле, включая/отключая отладку от разных служб по мере необходимости с помощью средств условной компиляции (без удаления её из кода)). 0-канал - общий поток. LogCatchOut...()/LogReleaseOut...() - захват/освобождение отладочного вывода через семафор. Если мне надо вывести одну строку, то LogCatchOut...()/LogReleaseOut...() писать не нужно, просто один из вариантов Log...() и всё. Внутри все функции Log...() выполняют захват/освобождение семафора, с предварительной проверкой того, не захвачен ли он уже нашей задачей через LogCatchOut...() (точнее там ещё есть проверка - запущена ли уже ОС? (так как функция может быть вызвана ещё и на этапе до запуска ОС)). Примерно так: Скрытый текст static u8 prioOut = PRIO_TASK_n, deepOut = 0; //os.prioCur - текущая задача ОС (одно из PRIO_TASK_..., должно быть <PRIO_TASK_n) //Захват потока вывода отладки. static void PendOut() { if (OsRunning()) if (os.prioCur != prioOut) OsSemPend(&semLogOut); } //Освобождение потока вывода отладки. static void PostOut() { if (OsRunning()) if (os.prioCur != prioOut) OsSemPost(&semLogOut); } //Захват потока вывода отладки с управлением из функции пользователя. void ServiceLogCatchOut() { uint i; if (!OsRunning()) return; if (prioOut != os.prioCur) { PendOut(); if (deepOut) trap(TRAP_SERV); //превышение глубины вложенных запросов захвата LogCatchOut() prioOut = os.prioCur; i = 1; } else if ((i = deepOut + 1) >> 8) trap(TRAP_SERV); deepOut = i; } //Освобождение потока вывода отладки с управлением из функции пользователя. void ServiceLogReleaseOut() { if (!OsRunning()) return; uint i = deepOut; assert(prioOut == os.prioCur && i, TRAPR_LOG); if (!--i) prioOut = PRIO_TASK_n; deepOut = i; PostOut(); } //============================== //далее - часть кучи функций вывода //IService...() - внутренние функции вывода драйвера сервисного вывода (без блокировки) void ServiceLogChar(int c) { PendOut(); serviceHnd.Tx(c); PostOut(); } void ServiceLogEol() { PendOut(); IServiceCR(); PostOut(); } int ServiceLogs(char const *s) { PendOut(); int i = IServicePuts(s); PostOut(); return i; } int ServiceLogsCR(char const *s) { PendOut(); int i = IServicePuts(s); i += IServiceCR(); PostOut(); return i; } Результат: Скрытый текст Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба Раз уж пошел разговор не по исходной теме (кстати, может его выделить в отдельную тему?)... 29 минут назад, jcxz сказал: LogCatchOut...()/LogReleaseOut...() - захват/освобождение отладочного вывода через семафор. Ну то есть закат солнца вручную, "потому что без плюсов". А были бы плюсы и LogCatchOut()/LogReleaseOut() в конструкторе/деструкторе - было бы { Log_mutex Mutex; Log.write(.....); Log.printf(.....); ...... Log.new_line(); } Писанины меньше, головной боли меньше, результат - тот же. "Машина должна работать, а человек - думать" (принцип IBM). 1 час назад, jcxz сказал: А если нужно сформировать строку (или блок строк) несколькими такими вызовами? И чтобы другой процесс не влез в его середину У меня семафор захватывается по первому выводимому символу, освобождается по "\r\n" (но только это делается не в printf(), а в классе, реализующем собственно вывод). Внутри блока перевожу строку комбинацией "\n\r", которая выглядит так же, но семафор не освобождает. В результате сообщение от одного потока никогда не разрывается сообщением другого без всяких рукопашных CatchOut()/ReleaseOut(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 26 минут назад, Сергей Борщ сказал: Раз уж пошел разговор не по исходной теме (кстати, может его выделить в отдельную тему?)... Ну то есть закат солнца вручную, "потому что без плюсов". А были бы плюсы и LogCatchOut()/LogReleaseOut() в конструкторе/деструкторе - было бы { Log_mutex Mutex; Log.write(.....); Log.printf(.....); ...... Log.new_line(); } Писанины меньше, головной боли меньше, результат - тот же. Вообще-то не тот-же. Гибкости - в разы меньше. Как я уже писал в ответ haker_fox. Пример: void f1() { LogsCR0("Начало работы"); if (...) { OsSemPend(...); OsSemPost(...); //функция ожидает какого-то семафора например //Или здесь может быть просто тяжёлая функция, выполняющаяся долго LogCatchOut0(); LogsCR0("Начало блока данных"); LogCR0(...); } else { LogCatchOut0(); LogsCR0("Начало блока данных"); if (...) LogsCR0(...); else { LogsCR0(...); LogsCR0("Конец блока данных"); LogReleaseOut0(); OsSemPend(...); OsSemPost(...); //опять ожидание с возможным переключением задачи или долгая функция LogCatchOut0(); LogsCR0("Начало блока данных"); LogsCR0(...); } LogsCR0("Конец блока данных"); LogReleaseOut0(); OsSemPend(...); OsSemPost(...); //опять ожидание с возможным переключением задачи или долгая функция LogCatchOut0(); LogsCR0("Начало блока данных"); LogsCR0(...); } LogsCR0("Конец блока данных"); LogReleaseOut0(); OsSemPend(...); OsSemPost(...); //опять ожидание с возможным переключением задачи или долгая функция LogsCR0("Завершение работы"); } Теперь попробуйте его написать с захватом/освобождением в конструкторе/деструкторе. Там где "ожидание с возможным переключением задачи или долгая функция" - функция не должна блокировать поток вывода, так как параллельно другие процессы тоже хотят выводить в него и при этом не зависать надолго. Да и в deadlock-и бы не попасть. А ведь это просто пример накиданный на быструю руку. В реальной жизни случаи бывают обычно гораздо более заковыристые. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба 29 минут назад, jcxz сказал: Вообще-то не тот-же. Гибкости - в разы меньше. Если этот вариант не подходит для каких-то отдельных случаев - это не значит, что его не нужно применять даже в тех случаях, для которых он подходит очень хорошо. Идеальных решений не существует - ваше требует больше писанины и усидчивости (чтобы не забыть LogReleaseOut там, где он необходим). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexast 0 24 сентября, 2021 Опубликовано 24 сентября, 2021 · Жалоба Уважаемые друзья, спасибо Всем за ответы. За то чтобы быть близким к формулировкам русского языка и программирования спасибо, постараюсь придерживаться данной рекомендации. Насколько уж поличится судить Вам. Ваши рекомендации в общем полезны и интересны. Сразу же скажу я не умею программировать на С++. На С также делаю это с учётом крайне малого опыта. Однако возвратимся к началу. Постановка задачи: Я делаю учебный проект с использованием FreeRTOS, Проект компилируется и настраивается (дебажится) в среде IAR. Это сугубо тренировочный проект. Сделал без принта всё скомпилировалось и загрузилось (слинковалось). А далее в теле main решил задать некую константу и вывести её. Необходимости выводить на какой-то UART или куда-то в другой порт ввода-вывода - нет. Хотя логику, которую подсказывают - она интересна и в целом понятна. Я хотел сделать очень простую вещь: Данная константа инициализируется в программе, которая находится и работает (под управлением - интегрированно в FreeRTOS) и там же и выводится. Т.е. всё крутится внутри микроконтроллера. Но есть у меня такая вещь как среда разработки IAR, которая может помимо того что там вертится внутри микроконтроллера показать мне это во "внешнем мире". И казалось бы что может быть проще как не использовать команду printf и всё это увидеть. Действительно ли так? Это можно применить при отладке для просмотра каких-то переменных при отладке. Но вот что в реальности произошло. Компилятор отклмпилировал код. Пусть и с предупреждениями. Команда printf тоже откомпилирована. Отторжений не произошло. Запустили в микроконтроллер и получили следующий результат: Остановка произошла на выполнении команды printf . Осмелюсь сделать некоторые выводы: В таком виде команда printf не работает в среде FreeRTOS. Чтобы в явном виде посмотреть данную константу, опять же в целях исключительно тренировке придётся придумывать другие способы. Один из выдать куда-то в порт - подобрать это всё, дешифровать и сравнить с желаемым вернее с ожидаемым результатом. Ясно. Согласен. А вот просто продебажить - как-то и не очень. Странно, что в среде FreeRTOS как бы таких лобовых решений и нет. А теперь в догонку данной темы. Я предположим сактивировал USB ак виртуальный комп порт. Далее в микроконтроллере крутится FreeRTOS могу ли далее консольно подключиться допустим к FreeRTOS и посмотреть на процессы в общем получить доступ тем самым или же аналогии с QNX Linux не просматриваются и не уместны. Сразу же скажу: прочитав руководства по FreeRTOS и имея начальные "целостные" понимания данной ОС моя вышепоставленная тема как-то обойдена там молчанием. Но впрочем может быть это и очевидно и поэтому авторы обошли молчанием этот вопрос. Ну вот такие вопросы. Заранее всем спасибо С уважением Алексей. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться