Вытесняющая многозадачная ОС. Практика AVR

Обсуждаем контроллеры компании Atmel.
viiv
Грызет канифоль
Сообщения: 287
Зарегистрирован: Чт ноя 06, 2014 13:09:06

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение viiv »

[uquote="ARV",url="/forum/viewtopic.php?p=3577656#p3577656"]я уже довольно много написал о том, как сделано сейчас.
в итоге приходится каждый чих окружать всякими мьютексами, семаформаи и т.п. "блокировками", и в итоге получается, что вместо ПАРАЛЛЕЛЬНОГО исполнения код исполняется ПОСЛЕДОВАТЕЛЬНО, т.е. КООПЕРАТИВНО.[/uquote]

Я, честно, не очень представляю, как устроен протокол обмена с модемом. Только в общих чертах. Поэтому, сейчас говорю исходя из своего понимания.
Пока мне непонятны Выши проблемы. Скажем при работе по TCP/IP ровно те же проблемы. Задача (*) посылает данные по TCP сокету, эти данные должны быть подтверждены удаленной строной, когда придет подтверждение не известно. Да задача (*) посылающая данные в TCP сокет может быть заблокирована, но задача принимающая данные из IP интерфейса (и все остальные) при этом, естественно работает. Когда придет подтверждение, то и разблокируется и продожит работать задача (*).
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

viiv писал(а):Пока мне непонятны Выши проблемы.
проблема у меня только одна: код получается не красивый. не знаю, как там в TCP/IP... может, там и красиво все, но то, что получается у меня, мне не нравится. причины и описание того, что не нравится, я уже изложил ранее.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение Аlex »

Если с ресурсами МК (ОЗУ в частности) проблем нет, то описанная задача с модемом решается просто.
Один процесс парсит принятую строку (посимвольно, буфером, поллингом, ... пофиг) и, в зависимости от принятой команды "дёргает" другие процессы. Естественно, с выделением под них памяти из кучи.
И по-барабану ему, ждёт ли там тот процесс уже чего-либо, не ждёт. Принял команду "отправить СМС", запустил соответствующий процесс (повторно, потройно, почетверно, ...). Одну задачу(процесс) в вытесняющей ОС можно вызывать сколь угодно раз, если приняты все меры предосторожности, типа реентерабельности. Всё упирается в одно - ОЗУ под каждый поток.
И если с ним (ОЗУ) нет никаких проблем - то и код будет достаточно прозрачен. Соответственно, наоборот, жыдим памяти - получи "макароны".
"И конфетку съесть и на ... сесть " не всегда получается :))
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

Аlex писал(а):И если с ним (ОЗУ) нет никаких проблем - то и код будет достаточно прозрачен
в том-то и дело, что так хорошо в теории, а на практике с ОЗУ всегда есть проблемы. оттого и тоска-печаль...

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

Мой уютный бложик... заходите!
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3577762#p3577762"]главная беда в том, что нельзя заранее узнать, какого размера пришла СМС, чтобы выделить под нее памяти ровно столько, сколько надо. из-за этого приходится выделять всегда максимум[/uquote]
А кто мешает выделять память страницами фиксированного размера, связывая их в список? И фрагментацию уменьшите, и лишняя память будет всегда меньше, чем размер одной страницы.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение Аlex »

[uquote="ARV",url="/forum/viewtopic.php?p=3577762#p3577762"]главная беда в том, что нельзя заранее узнать, какого размера пришла СМС, чтобы выделить под нее памяти ровно столько, сколько надо. из-за этого приходится выделять всегда максимум, что уже для работы с двумя СМС очень накладно становится.[/uquote]
Не знаю как в других вытеснялках, не работал, но FreeRTOS есть сервисы, переключающие незамедлительно контекст из прерывания в приоритетную задачу. Это как раз тот случай, когда нужно прерывание обработать максимально быстро, но задерживаться в нём нельзя.
По этому, можно обойтись минимально коротки кольцевым буфером, за счёт использования высокого приоритета для процесса, принимающего/обрабатывающего его.
Отсюда, функция приёма символа будет выглядеть обычным ожиданием сообщения в очереди. Что-то типа :

Код: Выделить всё

char getchar(){
  char ret;
  xQueueReceive(UartQueue, &ret);
  return ret;
}
А прозрачность будет максимальной - как будто модуль сам пихает в эту функцию байтики.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

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

Добавлено after 1 minute 29 seconds:
ПростоНуб писал(а):А кто мешает выделять память страницами фиксированного размера, связывая их в список? И фрагментацию уменьшите, и лишняя память будет всегда меньше, чем размер одной страницы.
ничего не понял, о чем это вы?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение Demiurg »

Вопросы:
Коды DTMF равнозначны кодам кнопок? Уточняю. Равнозначны, или любой первый принятый код DTMF - особый режим?
В вашем описании уже вижу недостаток. Сообщение нажатия и параметр код кнопки. Должно быть так: событие нажатия кнопок. И отдельный буфер для кодов кнопок. Размер буфера зависит от проекта. Поясняю. Проверка статичного или в очереди сообщения нажатия кнопок, после этого считываем буфер. Здесь тоже ветвление, одиночное считывание (навигация по меню, какие либо действия) либо считывание всего буфера кодов кнопок (ввод). Это определяется состоянием, по другому никак. Флаги или автомат, решать вам.
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3577798#p3577798"]ничего не понял, о чем это вы?[/uquote]
Может я Вас не правильно понял? Вы сказали, что не знаете размер SMS и вынуждены выделять память сразу по максимуму. Я так понял, что речь идет о чтении в символьной шестнадцатиричке того, что возвращает, например, M590 по команде AT+CMGR=n.
Для примера, пусть страница у нас 32 байта. Всего 255 страниц (8К-32). В каждой странице в 0-ом байте указываем номер следующей страницы, если она есть, или 255, если таковой нет. Еще 1 байт на длину данных в странице. При желании, можно еще битики на свои флаги выделить, или номера потоков.
Как только с модема мы получаем больше 30 байт, то выделяем новую страницу и номер ее записываем в заголовок старой страницы. После чего первые 30 байт уходят в обработку в другую нить, а то, что приходит из модема пишем в новую страницу. И так далее. Если обработка в параллельной нити не сложная, то, с большой вероятностью, она будет успевать освобождать нам старую страницу, как только получит очередную.
Размер страницы подбирается под задачу и под объем доступной памяти.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

Во-первых, 8К - это ровно в 2 раза больше, чем есть в atmega128
Во-вторых, вы описали один из известных алгоритмов менеджера кучи, далеко не самый оптимальный.
В-третьих, как мне это может помочь? Проблема-то в том, что СМС может занимать от примерно 30 до примерно 360 байт, и заранее я не знаю и не могу узнать, сколько байт надо для очередной СМСки. И приходится всегда выделять по 360, хотя там на самом деле может быть только два слова, и хватило бы 36 байт...

Добавлено after 4 minutes 52 seconds:
Demiurg писал(а):Коды DTMF равнозначны кодам кнопок? Уточняю. Равнозначны, или любой первый принятый код DTMF - особый режим?
С точки зрения извлечени сообщений из очереди нет никакой разницы, попало туда сообщение MSG_KEY с клавиатуры или через DTMF. То есть источник символа никакой роли не играет.
Demiurg писал(а):И отдельный буфер для кодов кнопок.
то есть вы предлагаете отказаться от общей очереди сообщений и выделить "кнопочные" сообщения в поток символов, обрабатываемых по мере надобности?

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

Мой уютный бложик... заходите!
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение Demiurg »

Я со смарта пишу, редактировать объёмный текст не получается. Разделяй и властвуй. Одно из ваших затруднений как раз в том, что у вас свалены в кучу люди, кони. Как то так:

Код: Выделить всё

if (Get_Event (EV_ID_KEY_PRESSED))
{
   switch (Get_Key_Code ())
   {
      case KEY_ESC_COD: break;
      case KEY_ENTER_COD: break;
      case KEY_PLUS_COD: break;
      case KEY_MINUS_COD: break;
   }
}
Это вариант одиночной обработки кодов. Когда требуется обработка ввода, тут уже посложнее будет.
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3577862#p3577862"]Во-первых, 8К - это ровно в 2 раза больше, чем есть в atmega128
Во-вторых, вы описали один из известных алгоритмов менеджера кучи, далеко не самый оптимальный.
В-третьих, как мне это может помочь? Проблема-то в том, что СМС может занимать от примерно 30 до примерно 360 байт, и заранее я не знаю и не могу узнать, сколько байт надо для очередной СМСки. И приходится всегда выделять по 360, хотя там на самом деле может быть только два слова, и хватило бы 36 байт...[/uquote]
Во-первых, никто Вас не заставляет выделять все 255 буферов. Выделите ровно столько, сколько Вам нужно, понимая, что если буферов не хватит, то данные будут утеряны. Для одного последовательного канала и одного парсера, обычно, достаточно 2-4 буфера.
Во-вторых, это не механизм управления пулом буферов, а вовсе не кучи. Подобным образом работает, например, буферизированный ввод-вывод. Куча работает несколько иначе, так как она должна уметь выделять произвольный объем памяти непрерывным экстентом. Если не трогать системы с виртуальной памятью, для кучи страничный подход не применим.
В-третьих, я же описал как. Принимаете первые 30 байт, отдаете фоновому парсеру на обработку. Пока парсер разбирается с этими 30 байтами, заполняете следующий буфер. Парсер же, как только завершит обработку очередного буфера, освободит его, запомнив только номер следующего буфера.
Если же парсинг тривиален, то мне Ваши проблемы вообще не понятны. Ведь тогда можно парсить текст сразу во время его приема не записывая вообще его в память.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

ПростоНуб писал(а):тогда можно парсить текст сразу во время его приема не записывая вообще его в память
Можете набросать пример кода, который на лету будет выбирать совпадение потока байтов с массивом строк из, предположим, 10 элементов по 5 символов каждая строка?
я стремлюсь сделать код проще и понятнее, а вы предлагаете чуть ли не ассоциативную память реализовать... боюсь, проще код от этого явно не станет.
как и в случае с предлагаемым вами разбором строки по частям.
Demiurg писал(а):Как то так
вы продолжаете вспоминать свои предыдущие менюшки... и не желаете взглянуть на мою проблему, как на свежую проблему.
голосовое меню заключается в работе такого кода:

Код: Выделить всё

m1:
   Say("Нажмите 1 для установки часов, нажмите 2 для установки календаря, нажмите 3 для запуска ракеты, нажмите # для отмены или * для повторного прослушивания меню");
   do{
      timer_start(T1, TIME_LIMIT_MENU);
      msg = get_mesage(MAIN_QUEUE);
      switch(msg){
      case MSG_KEY:
         switch(msg.key){
         case K_1: setup_time(); break;
         case K_2: setup_calender(); break;
         case K_3: start_rocket(); break;
         case K_#: return;
         case K_*: goto m1;
         } // key switch
         break;
      default:
         default_process_messages(msg);
      } // msg switch
   } while(!timer_timeout(T1));
это псевдокодом, естественно, алгоритм показан

соответственно, представьте себе, если в этом меню будет что-то типа "чтобы ввести пароль, нажмите 5", как все будет выглядеть? в моей реализации это примерно так выглядит:

Код: Выделить всё

case K_5: { 
   char tmp[8];     
   if(get_password(tmp, 7)){
      strcpy(password, tmp);    
   }
}
break;
а вот реализация get_password содержит свой цикл обработки очереди сообщений по предыдущему примеру меню - со своим таймером и дефолтной обработкой.

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

Мой уютный бложик... заходите!
Аватара пользователя
GoldenAndy
Поставщик валерьянки для Кота
Сообщения: 1925
Зарегистрирован: Чт июл 28, 2016 07:58:37
Откуда: Kyiv, UA
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение GoldenAndy »

ARV, так на лету - это было предложено как пример.
А походу, ГСМ модем отдается на скорости 9600. Или около одного символа в миллисекунду.
За миллисекунду МК у вас отмолотит 16 тысяч операций.
Неужто вы не сможете прочитать 10-15 наборов по 5 байт из прогмема и сравнить их с буфером еще в процессе считывания ? У вас на это целая миллисекунда!
(я надеюсь, прием данных от модема на прерываниях сделан ?)
ИзображениеИзображение
Изображение
 
Telegram               Лучшая благодарность ->
[+]
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3577935#p3577935"]Можете набросать пример кода, который на лету будет выбирать совпадение потока байтов с массивом строк из, предположим, 10 элементов по 5 символов каждая строка?[/uquote]
Не сейчас, сейчас мне еще по пробкам час тащиться.
Но идея следующая. Список элементов делаем отсортированным. Дубли не допускаются. Таким образом, до первого символа у нас кандидаты все элементы. После первого символа запоминаем номер первого и последнего подходящего элемента. На втором символе проверяем на равенство только вторые символы между запомненными элементами включительно и снова запоминаем номер первого и последнего подходящего элемента. И так далее.
В итоге, или у нас не совпадет символ ни с одним из элементов - значит мы не знаем такого слова. Или останется только одно слово.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

ПростоНуб писал(а):Но идея следующая.
и вы на самом деле считаете, что это просто?
goldenandy писал(а):За миллисекунду МК у вас отмолотит 16 тысяч операций
8000, но не суть
goldenandy писал(а):Неужто вы не сможете
ощущение, что вы не читаете, что я пишу :(
именно что я все смог. вчера обработчик принятого уведомления от модема вызывался через 105 микросекунд после того, как был принят символ '\r', являющийся завершающим строку символом. т.е. мне понадобилось 105 микросекунд на то, чтобы отправить сообщение в главную очередь, выйти из обработчика прерываний, дойти в главном цикле до очереднго опроса очереди, извлечь сообщение, проанализировать его и просканировать список строк в PROGMEM на предмет совпадения с принтой строкой, и вызвать нужный обработчик.

Код: Выделить всё

// прием по прерываниям
ISR(_VECTOR_RX){
	static char *rx_ptr = (void*)rx_buf;

	char d = _UDR;
	switch(d){
	case '\n': break; // игнорируем
	case '\r':
		if(*rx_begin) put_message(MAIN_MSG_QUEUE, MSG_GSM, 0, (uint16_t)rx_begin);
		rx_begin = (void*)rx_ptr+1;
		d = 0;
	default:
		// принятый символ сохраняем
		*rx_ptr++ = d;
		// закольцовываем указатель
		if(rx_ptr >= (rx_buf + RING_SZ)) rx_ptr = (void*)rx_buf;
	}
}
у меня нет проблемы с этой частью кода!

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

Мой уютный бложик... заходите!
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3578006#p3578006"]и вы на самом деле считаете, что это просто?[/uquote]
Все в мире относительно. Для меня функция на полэкрана всегда проста.
Вот пример для GCC на компе:

Код: Выделить всё

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

uint8_t *words[] = { "Abcd","So","Zero","R","Alpa","Breaking","Top","Unit","Boat","So","R","Abcd","Abcde","Breaking" };
uint8_t *keys[] = { "Abcd","Alpha","Boat","Breaking","R","So","Top","Unit","Zero" };

// Returns:
//   0..n - index of founded key
//   -1 - awaiting next symbol
//   -2 - key not found
short parse_symbols(uint8_t symbol)
{
  static uint8_t level = 0;
  static uint8_t from_idx = 0;
  static uint8_t to_idx = sizeof(keys)/sizeof(uint8_t *)-1;
  short found = -2;

  if ( symbol==' ' ) symbol=0;
  for (uint8_t i=from_idx;i<=to_idx;i++ ) {
    if ( keys[i][level]<symbol ) {
      from_idx++;
    } else if ( keys[i][level]>symbol ) {
      if ( found==-2 ) break;
      to_idx=i-1;
      level++;
      return(-1);
      break;
    } else {
      found=i;
      if ( symbol==0 ) break;
    }
  }
  if ( found>=0 && symbol!=0 ) {
    level++;
    return(-1);
  }
  level=from_idx=0;
  to_idx=sizeof(keys)/sizeof(uint8_t *)-1;
  return(found);
}

int main(void)
{
  uint8_t *ptr;
  short rc;

  printf("Begin test with %d words by %d elements in dictionary\n",
    sizeof(words)/sizeof(uint8_t *),sizeof(keys)/sizeof(uint8_t *));
  for (uint8_t w=0;w<sizeof(words)/sizeof(uint8_t *);w++) {
    ptr=words[w];
    do {
      rc=parse_symbols(*(ptr));
    } while ( (*ptr++)!=0 && rc==-1 );
    if (rc<0) {
      printf("Word %s not found. rc=%d\n",words[w],rc);
    } else {
      printf("Word %s found at index %d\n",words[w],rc);
    }
  }
  exit(0);
}
Просьба сильно не пинать, так как писалось слету, да еще поздно вечером после рабочего дня.
OKF
Это не хвост, это антенна
Сообщения: 1385
Зарегистрирован: Вт июн 07, 2011 08:03:18

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение OKF »

Почти всегда всё накрученное можно оформить функцией (если надо положить отдельным файлом), расписать и забыть.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ARV »

OKF писал(а):Почти всегда всё накрученное можно оформить функцией (если надо положить отдельным файлом), расписать и забыть
а мусор можно под ковёр замести... и забыть. не мой подход, хотя, чего там скрывать - приходится так делать порой...
ПростоНуб писал(а):Просьба сильно не пинать
да когда ж такое было, чтобы за попытку помочь пинали?! :shock: однако, в вашем подходе, помимо относительной сложности и некоторой загадочности, есть еще одна проблема: сортировка "образцов". это затрудняет процесс модификации списка вручную.

вот смотрите, как сделал сейчас я (не в плане критики вашего варианта, а вообще в плане поедлиться опытом).

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

а теперь - внимание! что это мне дает: в любом месте своего кода при помощи макроса я объявляю функцию-обработчик уведомления, и не забочусь ни о том, чтобы править какие-то массивы строк, контролировать размерность этих массивов и т.п. - все делается автоматически! не нужен более обработчик - удаляю его в том месте, где объявил, и снова ни о чем не переживаю.

кстати, аналогично сделал и программные таймеры. в плане удобства - просто очень шикарно, рекомендую всем! :)

вот так это выглядит в коде:

Код: Выделить всё

/// определение функции обработки команды s
#define CMD_HOOK(s)			static const __flash char s [] = "+" # s ; \
							static void CONCAT(hook_, s)(FUNC_PARAM); \
							static const tbl_item_t __attribute__((used, section(".my_table"))) CONCAT(item_, s) = {.cmd = s, .func = CONCAT(hook_, s)}; \
							static void CONCAT(hook_, s)(FUNC_PARAM)
↑ это макрос, задающий сразу строку-шаблон и функцию-обработчик ↑

Код: Выделить всё

void gsm_str_process(char *str){
	extern const int __my_tbl_start;
	extern const int __my_tbl_end;
	const __flash tbl_item_t *item = (void*)&__my_tbl_start;

	// начиная с первого зарегистрированного обработчика и до последнего
	for(; item != (void*)&__my_tbl_end; item++){
		// если зарегистрирован обработчик-пустышка - игнорируем его
		if(item->func == NULL) continue;
		// если команда найдена
		if(respcmp(item->cmd, str)){
			// вызываем обработчик и завершаем перебор
			item->func(str, item);
			return;
		}
	}
	debug_prn(PSTR("Unknown EVENT: \"%s\""), str);
}
↑ это функция поиска в полученной строке совпадения с одним из шаблонов и вызов соответствующего обработчика ↑

Код: Выделить всё

CMD_HOOK(CMTI){
	uint16_t n;
	// str = +CMTI: "SM", N
	char *begin = find_chr(str,',',1);
	if(begin){
		n = atoi(begin);
		put_message(MAIN_MSG_QUEUE, MSG_SYS, SYS_SMS, n);
	}
}
↑ а вот так выглядит один из обработчиков, конкретно этот - уведомление о приходе СМС "+CMTI" ↑

наконец, вот такой кусочек добавлен в скрипт линкера, чтобы все это заработало:

Код: Выделить всё

    /* Внедрение моих секций для таблиц */
    __my_tbl_start = . ;
    *(.my_table)
    *(.my_table*)
    KEEP (*(.my_table))
    __my_tbl_end = . ;
    KEEP (SORT(*)(.my_table))
    /* Конец моих секций для таблиц */

    /* From this point on, we don't bother about wether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
специально показал несколько строк оригинального скрипта (в конце), чтобы можно было понять, в какое место добавлял (конкретно - в секцию text).

возможно, кто-нибудь возьмёт на вооружение :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Вытесняющая многозадачная ОС. Практика AVR

Сообщение ПростоНуб »

[uquote="ARV",url="/forum/viewtopic.php?p=3578137#p3578137"]в вашем подходе, помимо относительной сложности и некоторой загадочности, есть еще одна проблема: сортировка "образцов". это затрудняет процесс модификации списка вручную.[/uquote]
О сложности и, тем более, загадочности, предлагаю вопрос замять по причине его явной субъективности. А сортировать список вручную никто не заставляет.
Вынесите список в отдельный включаемый файл

Код: Выделить всё

uint8_t *keys[] = { 
#include "keys_incl.h"
};
Указывайте в этом файле по одному ключевому слову на строку и сортируйте его при сборке проекта своей любимой утилитой сортировки. Хоть обычным sort.exe под Windows.
вот смотрите, как сделал сейчас я (не в плане критики вашего варианта, а вообще в плане поедлиться опытом).
Интересный вариант, но он как раз не для обработки "на лету". Объем кода, выполняемого между двумя полученными символами у Вас всяко больше, чем в моем примере.
Ну МК я предпочитаю частый обмен короткими сообщениями длиной 1-4 байта, но по каждому прерыванию, чем редкий обмен длинными сообщениями после накопления информации в буфере.
не забочусь ни о том, чтобы править какие-то массивы строк, контролировать размерность этих массивов
Вы лукавите. Добавлять новые ключевые слова Вам так же требуется, как и их обработчики. В моем случае, номер обработчика так же можно считать совпадающим с номером найденного ключевого слова. А размерность массивов (не строк, а указателей на строки) контролирует компилятор, а не я.

Ваш проект, как хотите, так и поступайте. Я просто ответил на вопрос и показал, как парсить строки на лету.
Ответить

Вернуться в «AVR»