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

Помогите разобраться с ошибкой

37 minutes ago, cybersonner said:

это функция, которая по итогу будет вызвана

Теперь я понял о чём Вы! Это называется retargeting ли как-то так. Давно этим не занимался. Если по-русски, то это определение низкоуровневой функции вывода  в физический канал (последовательный порт, Ethernet  и т.п.).

 

1 hour ago, cybersonner said:

printf делается примерно так

Сама фраза просто смутила.

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


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

6 часов назад, haker_fox сказал:

фантастически звучит Ваш каждый пост с учётом норм русского языка.

У вас кстати тоже с русским есть проблемы:

2 часа назад, haker_fox сказал:

OsApi::MutexLocker mutex(s_mutex); // ждём мьютекс, т.к. мы ни одни используем форматированный вывод в консоль

Е одни"

:wink2:

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


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

1 minute ago, jcxz said:

У вас кстати тоже с русским есть проблемы:

Вы правы) Из психологии известно, что то, что мы видим в других, есть и в нас...

Но я немного оправдаюсь:

1. Комментарий писал быстро уже в форме редактора кода форума, т.к. такие "в лоб" комменты я не ставлю. Код самодокументируем. Согласен, это не оправдание.

2. Я автору указывал больше не на орфографию, а на стиль изложения, ибо плохо понятно, что он там вообще имеет в виду. Согласен, и это не оправдание.

Но спасибо, что поправили! Писать следует грамотно!

:blum:

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


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

И кстати - я не понял, почему у вас в функции есть вроде как захват(?) мьютекса, но нет его освобождения в конце функции?

Или освобождается он деструктором?

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


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

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;
    };

 

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


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

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

Мьютекс освобождается в деструкторе в тот момент, когда мы покидаем функцию. Происходит это автоматически. В этом и прелесть Си++)

Очень громоздко это всё. Большие накладные расходы: конструктор, захват, освобождение, деструктор. И это всё на вывод может всего одного символа...

 

К тому же негибко, если не ошибаюсь.

Например: Обычно если много задач обращаются к отладочному выводу, то они должны писать в него функционально законченные осмысленные сообщения. Хорошо, когда одно сообщение формируется полностью одним вызовом такого kprintf(). А если нужно сформировать строку (или блок строк) несколькими такими вызовами? И чтобы другой процесс не влез в его середину. Можно это сделать с помощью вашей реализации kprintf()?

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


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

9 minutes ago, jcxz said:

Очень громоздко это всё.

Признаюсь, в листинг специально для этого не глядел. А что там громоздко? Конструктор и деструктор делают то же самое, что и ручками бы пришлось делать. Может быть и есть какие-либо накладные расходы. Но меня устраивает. Для одного символа это выглядит серьёзно. Но ведь обычно выводятся строки (у меня) и из разных процессов.

З.Ы. Некоторые вещи из Си++ применяю впервые, и смотрю листинг. Так вот, порой видно, что компилятор генерирует "тупо" рабочий код без излишеств.

Недавно мне понадобилась такая штука: функция с вариативным количеством аргументов. Естественно, одного типа. И количество определяется на этапе компиляции. Посмотрел в листинг, а там просто делается всё то же самое, что я бы делал вручную. При этом удобство использования отличается напорядки.

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


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

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

Признаюсь, в листинг специально для этого не глядел. А что там громоздко? Конструктор и деструктор делают то же самое, что и ручками бы пришлось делать.

Нет. Без них там был бы просто PUSH в начале и POP - в конце (скорее даже - без POP, а просто переход на функцию). С ними будет больше (скорей всего вызовы функций).

А самое главное - см. 2-ю часть моего поста.

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


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

12 minutes ago, jcxz said:

Можно это сделать с помощью вашей реализации kprintf()?

К сожалению, нет. У Вас есть решение?)

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


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

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;
}

 

 

Результат:

Скрытый текст

1113542121_fwstart.thumb.png.11417a571447775ffa758fdee1c7173c.png

 

 

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


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

Раз уж пошел разговор не по исходной теме (кстати, может его выделить в отдельную тему?)...

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().

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


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

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("Завершение работы");
}

Теперь попробуйте его написать с захватом/освобождением в конструкторе/деструкторе.  :wink:

Там где "ожидание с возможным переключением задачи или долгая функция" - функция не должна блокировать поток вывода, так как параллельно другие процессы тоже хотят выводить в него и при этом не зависать надолго. Да и в deadlock-и бы не попасть.

А ведь это просто пример накиданный на быструю руку. В реальной жизни случаи бывают обычно гораздо более заковыристые.

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


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

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

Вообще-то не тот-же. Гибкости - в разы меньше.

Если этот вариант не подходит для каких-то отдельных случаев - это не значит, что  его не нужно применять даже в тех случаях, для которых он подходит очень хорошо. Идеальных решений не существует - ваше требует больше писанины и усидчивости (чтобы не забыть LogReleaseOut там, где он необходим).

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


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

Уважаемые друзья, спасибо Всем за ответы.

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

Ваши рекомендации в общем полезны и интересны. Сразу же скажу я не умею программировать на С++. На С также делаю это с учётом крайне малого опыта. Однако возвратимся к началу.

Постановка задачи:

Я делаю учебный проект с использованием FreeRTOS,

Проект компилируется и настраивается (дебажится) в среде IAR.

Это сугубо тренировочный проект.

Сделал без принта всё скомпилировалось и загрузилось (слинковалось).

А далее в теле main решил задать некую константу и вывести её. Необходимости выводить на какой-то UART или куда-то в другой порт ввода-вывода - нет.

Хотя логику, которую подсказывают - она интересна и в целом понятна.

Я хотел сделать очень простую вещь:

Данная константа инициализируется в программе, которая находится и работает (под управлением - интегрированно в FreeRTOS) и там же и выводится. Т.е. всё крутится внутри микроконтроллера. Но есть у меня такая вещь как среда разработки IAR, которая может помимо того что там вертится внутри микроконтроллера показать мне это во "внешнем мире". И казалось бы что может быть проще как не использовать команду printf и всё это увидеть. Действительно ли так?

Это можно применить при отладке для просмотра каких-то переменных при отладке.

Но вот что в реальности произошло.

Компилятор отклмпилировал код. Пусть и с предупреждениями.

Команда printf  тоже откомпилирована. Отторжений не произошло. Запустили в микроконтроллер и получили следующий результат:

Остановка произошла на выполнении команды printf .

Осмелюсь сделать некоторые выводы:

В таком виде команда printf  не работает в среде FreeRTOS.

Чтобы в явном виде посмотреть данную константу, опять же в целях исключительно тренировке придётся придумывать другие способы.

Один из выдать куда-то в порт - подобрать это всё, дешифровать и сравнить с желаемым вернее с ожидаемым результатом. Ясно. Согласен.

А вот просто продебажить - как-то и не очень.

Странно, что в среде FreeRTOS как бы таких лобовых решений и нет.

А теперь в догонку данной темы.

Я предположим сактивировал USB ак виртуальный комп порт. Далее в микроконтроллере крутится FreeRTOS могу ли далее консольно подключиться допустим к FreeRTOS и посмотреть на процессы в общем получить доступ тем самым или же аналогии с QNX Linux не просматриваются и не уместны. 

Сразу же скажу:

прочитав руководства по FreeRTOS и имея начальные "целостные" понимания данной ОС моя вышепоставленная тема как-то обойдена там молчанием. Но впрочем может быть это и очевидно и поэтому авторы обошли молчанием этот вопрос.

Ну вот такие вопросы.

Заранее всем спасибо

С уважением Алексей.

 

 

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


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

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

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

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

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

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

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

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

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

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