Jump to content

    
Sign in to follow this  
alexast

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

Recommended Posts

37 minutes ago, cybersonner said:

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

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

 

1 hour ago, cybersonner said:

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

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

Share this post


Link to post
Share on other sites
6 часов назад, haker_fox сказал:

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

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

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

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

Е одни"

:wink2:

Share this post


Link to post
Share on other sites
1 minute ago, jcxz said:

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

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

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

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

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

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

:blum:

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites
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;
    };

 

Share this post


Link to post
Share on other sites
8 минут назад, haker_fox сказал:

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

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

 

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

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

Share this post


Link to post
Share on other sites
9 minutes ago, jcxz said:

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

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

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

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

Share this post


Link to post
Share on other sites
3 минуты назад, haker_fox сказал:

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

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

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

Share this post


Link to post
Share on other sites
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

 

 

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites
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-и бы не попасть.

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

Share this post


Link to post
Share on other sites
29 минут назад, jcxz сказал:

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this