вызов "долгой" функции, не прерывая работы основоного цикла..
- Войдите на сайт для отправки комментариев
Чт, 29/05/2014 - 18:42
Есть долгая функция, передает данные по GPRS на комп. Работает секунд 40. Задержки реализованны глупо через delay, диалоговую реализацию сеанса писать влом. Да и не в том порос... Вопрос в том, если способ выполнять основной код программы параллельно ? Типа переключать контент на время ожидания ответа ? "Многозадачность " отсюда http://robocraft.ru/blog/981.html пробовал, не работает у меня, т.к. я вызываю функции из разных потоков, и там используются прерывания... в общем, не сохраняются регистры...
Кто что посоветует ??
Самое тупое, наверное, использовать прерывания для выдачи символа в порт. К сожалению статью Di Halta я не нашел, но смысл в следующем. Пишется обработчик прерывания для отправки одного байта в UART. Причем отправка продолжается пока в буфере есть данные. Для работы в буфер заливаются данные и выставляется флажок, после чего данные начинают выводиться в UART, пока буфер не пуст.
ээээ .... вот счас не понял :)
< Положим, будет функция, которая записывает комманду в буфер, вызывается irq , пишем в порт, возвращемся в основной код... а задержки ?? на обработку комманд модулем ?? Они же всеодно нужны...
Даже если писать диалог, он будет не сильно быстрее...
Вертиться на уме событийная модель... эвенты ... так сказать :)
Если вынести основной цикл в отдельную функцию, второстипенный цикл с долгой функцией в другой отдельный цикл... а в основном использовать диспетчеризацию прерываний.... на основе событий в тех других циклах...
Тогда ещё понадобится таймер, для задержек, тогда всё получится нормально.
Во флеш пишем строки и задержки. Устанавливаем флажок, начинается передача первой команды в прерываниях, по последнему символу в прерывания запускается таймер, в прерывании которого, формируется флажок для передачи следующей команды.
Т.е. всё в прерываниях, основная прога не замечает этого. Типа так. Какие нюансы ещё всплывут? :)
Ну да, симафоры :)
надо вообще отказаться от задержек, а процедурку все же переписать в диалоговую реализацию...
тогда ответ модуля ОК будет вызывать прерыввние и след комманду... ну или еще подумать....
Это если на каждую команду возвращается ОК, тогда одно, а если ошибку, тогда совсем другое. Очереди сообщений нет, потому ивенты.. Условные.
В общем всё делать на прерываниях и проблемы будут другими :)
Ну, на каждую команду что-то возвращается через какой то промежуток времени, вот этот промежуток надо использовать для работы основного кода, это что то писать в глобальную переменную, прерывание вызывать просто на овтет из порта, а функция прерывания уже будет разбираться со значением глобальной переменной...
Этот же механизм можно использовать для обработки команд , полученных через уарт или от тогоже GSM модуля.... и от исполняемых функций.. т.е. имеем некий соммандный процессор, который "знает" все комманды и все ответы, и рулит вызовами функций в зависимости от полученных данных...
Все управление можно осуществить на основе такой парадигмы. В основном цикле этого процессора осуществляется опрос датчиков, опрос портов, ответ интерпритируется, и в зависимости от того, что получилось, формируется , к примеру, ответ на комманду в диалоговом протоколе (например АТ комманды в GSM модуле), или директива для испольнительного устройства...
Никакие "промежутки" не нужно использовать. Основная программа крутится как обычно, а весь обмен в прерываниях. Плюс понадобится управляющая структура, которая выдает задание на передачу информации. Не нужны никакие ивенты, семафоры и т.п. Всё тупо и просто. Максимум в управляющей структуре можно разместить очередь для отправляемых сообщений. А также следить за записью данных в эту управляющую структуру (т.е. чтобы прерывания не вызывались до того, как заполнится эта структура).
А вообще, пока это всё пустой треп, потому что неясно:
1. Можно ли тупо сформировать данные, а потом включить рубильник и пусть эта вся байда катится в эфир. В главном цикле проверять, отправлено всё или нет, после отправки снова формировать следующие данные.
2. Нужно ли менять отправляемые данные в зависимости от ответа, полученного из эфира. Тогда нужна синхронизайия данных между основным циклом и отправкой данных в прерываниях.
3. Количество и команды всегда одинаковые и только некоторые параметры команд разные?
В общем я уже всё расписал, решение вполне нормальное. Прерывания, таймер и управляющая структура, плюс пара-тройка функций, для "завода" обмена и контроля окончания отправки всех данных. По мне так вполне интересная задачка, а то всё помигать светиком, да передать данные на сервер - скукота.
UPD: Можно еще спереть у Di Haltа его простенький "многозадачник", но он на ассемблере. Он его раздает вместе с Pinboard, на его форуме где то есть и тексты и описание.
Тогда в целом о задаче...
нужно опрашивать некий сет датчиков, температуры, давления, расхода воды, тока ... потом на основе их показаний выдавать команды исполняющим устройствам, кто то управляется по 0-10В, кто то просто on\off. Помимо этого, долгая процедура пишет лог на сервер через GPRS. Еще можно управлять устройствами посредством команд. т.е. либо на прямую (к примеру установить такое то значение 0-10В, или что то включить/переключить) либо путем изменения значения глобальных переменных. Команды приходят через хардверный уарт (БТ или шнурок) или софтверный - получить\послать СМС.
Собственно в прототипе все , кроме основной логики , реализовано. с Вашей помощью преодолён последний рубеж периферии - хранение данных датчиков, спасибо большое.
Счас есть функции принимающие\отправляющие СМС, опрашивающие датчики, пишущие в лог на сервер, управляющие реле и устройствами пропорционального управления, есть примитивный парсер команд, которому все равно, откуда пришла команда, СМС, консоль или еще как... осталось выбрать подход к логике работ основного цикла и описать все это...
Теперь по пунктам.
1. да, можно... передала лога это асинхронная задача с низким приоритетом
2. Нет, отправляемые данные, это просто показания датчиков и состояния аттенюаторов.
3. Да, я бы настаивал на жестком описании протокола... :) в случае с диалоговой периферией (GSM модулем) тоже строго определенный набор команд и формализованный набор ответов.
можно попробовать ассинхронную работу со всеми субъектами алгоритма.. Каждое устройство или задачу обслуживает функция, которую вызывают с передачей параметра, директивой, а ответона пишет в буфер... мы читаем буфер и реагируем на то , что там есть... т.е. некий диалоговый режим вызовов... Командный процессор запускается, выполняет первую по коду инструкцию, получает ответ, выполняет следующую... при этом, к примеру функцию передачи через GPRS мы не делаем атомарной, а каждую АТ команду и ответ обрабатываем отдельно...
наверно не буффер. а очередь... FIFO
тут как раз отсудствие многопоточности станет плюсом, а не минусом..
Создается управляющий массив структур (команда, ответ или задержка). Если таких последовательностей несколько, то несколько таких массивов.
Создается функция, которая инициализирует обмен, в неё передается управляющий массив (один из них). Далее всё катится по прерываниям, с использованием таймера для формирования задержек, если нужно, либо также, по прерываниям, получение ответа и продолжение отправки данных.
Разумеется гемора хватит, но тут я уже не помогу (разве что в деталях), слишком много нюансов, да и работа уже не совсем халявная. А идеи - запросто.
Спасибо :)
В целом. я думаю, что представляю, как это должно работать. очень упрощенно, это сейчас работает. В смысле некий парсер комманд, который получает поманды откуда угодно. Попробую нормально прикрутить основной цикл и разбить функции работы с GSM на отдельные команды. Вот тока это не решит проблем простоя, пока ждем ответ от модуля... тут же есть тока прерывания от таймеров...
Нельзя же как то программно формировать прерываение ?
Почему нет, только непонятно, что значит программно формировать прерывание?
Ну что бы основной цикл прервался на выполенени\продолжение выполнения процедуры связи с модулем, когда получен ответ...
А! Можно же и не ждать ответ, просто отправить команду и продолжить выполнение, переодически проверяя буффер обмена, на наличие сообщения. А что бы знать, к чему этот ответ относиться, можно завести три флага - GPRS, SndSMS, ResSMS. и счетчик шагов в сеансе с модулем... Но есть еще нюанс. Вызываться эти процедуры должны по расписанию, т.е. , к примеру каждые 5 минут. Значит таймер и шедулер.
Правильно заданный вопрос содержит ответ :)
В общем, долго провозившись с enum, понял, что сравнивать лейбы со строковыми константами занятие не тривиальное. Switch/case в пролете, придется использовать обычные if :)
В общем, 2 массива команд - инициализации и основного цикла, простой интерпритатор команд.
Ну это так... в виде идеи кода основного цикла....
Места тока все это много занимает....
Можно сделать не массив имен команд, а массив структур, которые содержат название команды и функцию, которая эту команду обрабаытвает. Тогда не нужно писать море вызовов типа
if
(strcmp(buf,
"I_UTL"
) == 0) {u_init();} , а достаточно написать цикл, который найдет нужное имя и вызовет соответствующую функцию. Кроме того позволяет легко добавлять/удалять новые команды.
А если еще в эту структуру флажки всякие добавить, то можно её использовать не только для поиска команды, а и еще и для других целей.
Типа так:
Это только идея, код возможно не скомпилится, для понимания only.
Э... а как вызывать то ?? Прошу прощение за тупизну..
Идея была в том, что бы 3-4 возможных инициатора команд, могли бы используя единственный стандартный способ, затребовать выполнение нструкций... т.е. "интертпритатору команд, парсеру" передается стандартная инструкция , в формате "GTEM;01", "SET01;240", кем угодно, GPRS модулем, через консоль, через вызовы основного цикла, еще как то ...
Структуры удобно, т.к. , как Вы верно заметили, можно использовать флаги состяний и менять их в процессе работы... записывать зеачения переменных, ... да мало ли...
Легко, рассмотрим на примере функции command. Исходная у Вас такая:
В модифицированном варианте будет примерно так:
MAX_STRUCTS думаю разберетесь как определить, примеры уже были. Это количество структур в массиве arr.
Посмотрел скетч из #2. Блин, зачем тут прерывания, управляющие, многозадачности (которых на 8-битном котроллере, толком небыло и не будет)?
1. Забываем о существование delay()
GSM_SendATCmd
2. Смотрим БАЗОВЫЙ пример, как можно жить без delay() - Мигаем светодиодом без delay() - пример как выполнять какое-то переодическое действия без блокировки основого скетча.
3. Укладываем все наши команды в какой-то массив строк.
4. Делаем аналогично примеру, только всместо переключения светодиода, делаем отсылку очередной (одной!) строки-команды из массива с помощью
P.S. В нашем случае "переодическое действия"=="отсылка очередной команды".
Легко, ...
В модифицированном варианте будет примерно так:
MAX_STRUCTS думаю разберетесь как определить, примеры уже были. Это количество структур в массиве arr.
Ну это я и хотел уточнить, каждый раз перебираем массив до совпадения... так элегантней, конечно :) MAX_STRUCTS определю :)
Посмотрел скетч из #2. Блин, зачем тут прерывания, управляющие, многозадачности (которых на 8-битном котроллере, толком небыло и не будет)?
1. Забываем о существование delay()
2. Смотрим БАЗОВЫЙ пример, как можно жить без delay() - Мигаем светодиодом без delay() - пример как выполнять какое-то переодическое действия без блокировки основого скетча.
3. Укладываем все наши команды в какой-то массив строк.
4. Делаем аналогично примеру, только всместо переключения светодиода, делаем отсылку очередной (одной!) строки-команды из массива с помощью
Дело не в интервалах, а в том, что
1. они не одинаковы и вообще могут тыть разными после одной и той же АТ команды
2. Нужно не интервалы ловить а ловить ответ модуля, это правильней. и обрабатывать его, ОК это или ERROR
для переодических вызовов там реет призрак leOS :) как шедулера.
>Это не многозадачность... диспетчеризации то нету :)
И не будет. Да называйте как хотите, вам шашечки или ехать?
>про delay понятно, проблема не только в нем, но и в единообразности подхода к обработке инструкций...
Ну вот так однообразоно и делайте все. Через millis() и запоминание когда последний раз выполняли какое-то дейсвие. Однообразно дробите любые задачи на маленькие "под-задачи" и выполнейти по одной "под-задачке" за одни проход Loop().
>1. они не одинаковы и вообще могут тыть разными после одной и той же АТ команды
Пример смотрели? Что мешает вам после отсылки команды, в переменную interval записывать новое значение? Устанавливать новую задержку.. Было бы желание, а его, похоже, нет.
Если бы вы попробовали, вначале хотя-бы с одним и тем же интервалом, то глядишь как сделать разные интервалы - стало было-бы очевидно.
>Нужно не интервалы ловить а ловить ответ модуля, это правильней. и обрабатывать его, ОК это или ERROR
Что мешает, при все приходящие из сериал, по одному символу складывать в какой-то буффер и смотреть что же там "насобиралось"?
Ну не по millis() будете отправлять очередную команду, а по if(strcmp(buff,expectedReponse)==0). В чем принципиальная разница по какому событию отправлять следующую комманду?
И, в конце концов, вам нужно задачу решить или вы хотите мне объяснить почему мое предложение неправильное? Да мне вообщему-то все равно. Непоходит вам мое видиние - ну и ладно.
Ну не по millis() будете отправлять очередную команду, а по if(strcmp(buff,expectedReponse)==0). В чем принципиальная разница по какому событию отправлять следующую комманду?
Собственно "абтом и речь" ... есть описание комманд, парсер команд, и структура , управляющая основным циклом, в ней описана регулярная очередность инструкций. Одна их этих инструкций, раз и есть, раз в цикл читать буфер обмена с модулем и решать как жить дальше. Так что Ваша идея вполне в конве наших, с kisoft, рассуждений.
Сечас я попробую перепереть код на новый лад, как рекомендовал kisoft, так он будет компактней и оптимальней, прикручу запуск работы с модулем по расписанию и посмотрим, что будет... Я еще не очень представляю, как лучше описать АТ комманды... каждую в отдельную функцию ? или , наверно лучше, тоже в структуру и потом просто из одного из полей брать комманду и отпралять в интерфейс модуля.
Но в обоих случаях, и в случае описания основного цикла, и в случае описания протокола с модулем, придется делать еще одну конструкцию, описывающую очередность выполнения команд, а во втором случае, нужно еще описать ветвление..
Счас попробую...
компилится...
но!
1. не получится использовать массив структур как конструкцию , определяющую очередность комманд основного цикла. Там же будут описаны все возможн ые команды. Значит массив имен останется ?? как то не очень структурно... либо же вносить езе один флаг, типа - основная инструкция или вспомогательная...
2. а как передать параметры в такой вызов ? { "GSMS", GSMS }, использовать внешнею переменную ??
Начинте кушать слона потихоньку... по кусочкам....
Вначале сделайте возмите свой изначальный пример.... из сообщения №2. Вначале хотя-бы вот это....
Где просто отсылаются комманды по очереди...
Для теста, можете вместо GSM_SendAtCmd(...) просто делать Serial.print("CMD:");Serial.println(....)
Положите все комманды в массив строк и отсылайте с какой-то задержкой. Но без delay().Вначале с одной и той же.
Потом сделаете вариальную задержку (еще один массив, только задержек). Потом переделаете два массива в один массив структур...
Потом сделаете неблокирующий прием данных от шилда в какой-то буффер.
ПОтом замените "задержку", на "в буффере оказалось правильное значение" (или прошло слишком много времени...).
Потом сделате несколько разных функций для разных состояний, введете понятие "состояния" (инициализация, отсылка sms, опрос датчиков и т.п.) и получится у вас машина состояний типичная. Вначале с помощью switch(mode), потом с помощью массива "обработчиков режимов"..... и так до бесконечности можно "фен-шуйность наводить...".
Но все то начинаются "просто отсылать строки, с некоторым интервалом, но не блокирую основной (и единственный) поток....)
В ощем логика работ потерялась напроч :)
Как то основной цикл перебора команд и собствено цикл в парсере слишком похожи...
Логика нарушилась, счас это вообще не понятно как работает , если чесно...
leshak, нормальный ход... Просто мне хочется докрутить "основное обеспечение логики" ... АТ команды и моджуль это вторичная перефирия, а хочется придумать сам механизм обработки инструкций...
Почти заработало в таком виде....
но проблемы где то в циклах... не вижу где...
вот вывод
Заработало в таком виде
Совершенно не понятно, зачем у вас for в for-ре, зачем вы ищите команду, по имени два раза...(вернее из-за цикла в цикле - фиг его знает сколько раз) зачем вы вообще ищите ее по имени... у вас имя команды, которое нужно выполнить будет приходить из Serial и вводится человеком?
Честно говоря, я могу ошибаться, но помоему оно работает "только чудом". Просто повезло.
Путаете & и && - это разные операторы.
Сравниваете с помощью оператора "==" типы char*
31 строка ошибка, не один амперсанд надо писать, а два. У Вас бинарная операция И, а надо логическую операцию И. Так то заработало - это случайность или порога с ошибками
Совершенно не понятно, зачем у вас for в for-ре, зачем вы ищите команду, по имени два раза...(вернее из-за цикла в цикле - фиг его знает сколько раз) зачем вы вообще ищите ее по имени... у вас имя команды, которое нужно выполнить будет приходить из Serial и вводится человеком?
В каждый проход цикла в первом случае перебираются команды из структуры по очереди, те, где каинд =0, т.е. команды основной очередности. Далее проверяется, не изминилась ли переменная комма, если да (в нее записана команда) то ищется эта команда и выполняется, далее снова по очереди...
Эту переменную может поменять сам процесс, кто то через консоль или через ГСМ модуль... В этом суть, в структуре описаны все команды, и их очередность... Основной цикл перебирает их по очереди, и без очереди выполняет комманду, если она записана в комму...
Да , сравниваю char через == и добавил апмперсанд...
Работает...
Я не знаю, господа, оптимально ли так... Но вроде примерно то, о чем говорил kisoft.
Вот так работает на домашней меге
Вот вывод
КАк видим, и очередность и последовательность соблюдается, внезапная команда выполняется... :)
МОжет я чего-то не улавливаю, но в чем, в итоге получилось преимущество по сравнению с
таким loop()? (ну кроме того что понять сходу что будет происходить труднее).
Сами "шаги" как были блокирующими - так и остались. Сам loop() как блокировался пока все команды не выполнятся - так и продолжает блокироваться.
А еще, попробуйте, скажем на этом скетче что-бы после "внезапной комманды", выполнилась еще одна внезапная комманда.
Если мы в TLED_H тоже установим comma="TLE2" (ну и само собой напишем для этой команды функцию и добавим ее в Instructions[] она выполнится?
А еще, чисто из любопыства запустите такой скетчик, предварительно попытавшись угадать что он выведет
сравните реальность с тем что ожидали, и представте себе что будет если у вас в с именами комманд случится такая же "обознатушка".
А еще, давайте представим, что нам нужно что-бы GSMS() выполнялся раз за разом, пока не наступит некое событие (пользователь нажмет кнопку, прийдет строка из Serial). Как это вы сделаете с таким управляющим циклом? Так что-бы при этом сам цикл loop() не блокировался (что-бы можно было продолжать следить за датчиками, другими кнопками, мигать диодом с нужной частотой и т.п.)
Ну в чистом виде этого не добиться. В принципе. Без применения диспетчеризации времени проца...
Теперь про цикл.
Команды "типа 0" и должны быть атомарными и "блокирующими". Команды типа 1 напротив, носят вспомогательный характер, могут быть разделены на шаги или фазы выполнения.
Вообще, идея в неком "командном процесоре" как я уже писал, куда команды передаются разными источникаи , включая сам код, и гарантировано выполняются одинаково.
Вообщем я уже упоминал вам про "машину состояний" (state machine/конечный автомат). Погуглите что это такое подробней... когда в голове разложится по полочкам "что же в принципе нужно", тогда и одну из реализаций ее будет легче писать.
Ну в чистом виде этого не добиться. В принципе. Без применения диспетчеризации времени проца...
Ну... так этим и нужно занятся. Програмной диспетчирезацией. Главный цикл отдает управление обработчикам, а уж обработчики должны "отработать как можно быстрее".
Помоему вы вообще начали "шарахаться" от одной хотелки к другой. Вы свой стартовый пост сами читали? Помните изначальную задачу?
Есть долгая функция, передает данные по GPRS на комп. Работает секунд 40. Задержки реализованны глупо через delay, диалоговую реализацию сеанса писать влом. Да и не в том порос... Вопрос в том, если способ выполнять основной код программы параллельно ? Типа переключать контент на время ожидания ответа ?
Эта задача решена? Почему вы поехали решать проблемы ветвления потока управления, приема внешних комманд и т.п.?
Сделать "универсально" - это общая болезнь програмеров. Даже на PC это зачастую заканчивается печально (получает "универсальный монстр", которого запыхаешься поддерживать), а уж на микроконтроллере и подавно это противопоказано.
Да вообщем-то и "универсальность" тут не получилась. Скажем реагировать на кнопки нормально - уже не получится (ну "получится", но прийдется их костылями вбивать, а так каждая добавка...).
Команды хотите "со стороны"? Ну предположим будут команды приходить из Serial. Только.... у вас же, весь цикл целиком является "блокирующим". Значит оперативно и ПОСТОЯННО смотреть что прищло в сериал - не получится. Ну разве что впихнуть прослушивание Serial в этот ваш for. То есть - костыль. Ну или вводить еще один тип комманды. Которая должна выполняться "постоянно". А потом выяснится что таких комманд требуется несколько... будет у нас третий for в for-е, который в for-e... А потом выяснится что эти "постоянные" нужно будет отключать/выключать... значит еще флаги натыкаем. if-фоф набросаем..... Упс. А ведь аттомарные-то у нас блокирующие.... следовательно расчитывать на предсказуемое (хотя-бы приблизительно) время выполнение "постоянных" и "вспомогательных" - не приходится (то есть изначальную задачу - так и не решили).
Далее... со сравнением строк разобрались? Я вам скетчик давал демонстрирующий глючность выбранного вами способа. Запускали?
Хотя.. честно говоря, я вообще нефига не понимаю нафига тут используются строки для идентификации комманд. Что-бы побольше нагрузить проц и увеличить расход памяти? Что-бы увеличить вероятность очепятки в комманде и потом биться с дебагом? (раз строка, следовательно на этапе компиляции уже ошибки не вылезует, если в comma впихнете команду которой нет. трабла вылезет уже только во время выполнения). Что-бы, не дай бог, когда потребуется поменять имя команды лазить по всему скетчу и аккуратно исправлять все "магические строки"?
Строки имееют смысл только в одном случае, когда:
Предполагает что где-то в цепочке учавствует человек (посылает комманды, пишет текстовый файлик который нужно обработать и т.п.). И то.. даже в этом случае имеет смысл разделить "коммандый процессор" и "анализ строк". Полученные от человека комманды, вначале "распознавать" (переводить их в какой-то int-представление, базирующие скажем на enum), а уж "коммандный процессор", работает только с цифрами. Если что... и хранить такие цепочки - гораздо меньше места занимает.
Это если отбросить в сторону что непонятно зачем вообще нужен поиск комманд. Причем КАЖДЫЙ РАЗ. Их список - не меняется во время выполняния. Индекс каждой - известен на момент компиляции. Почему не пользоватся индексами/enum-мами, вместо имен? Сразу понятно какую команду нужно выполнять. Ничего искать не нужно.
Непонятно зачем вы вообще перемешали (запихнули в один массив) основные и дополнительные комманды. Что-бы потом было не скучно, и постоянно нужно было в runtime их фильтровать/разделять по kind? У вас что, в процессе выполнения команда может поменять свой тип (если "да", то "это не есть good")?
У вас же, может в один момент поставиться в состояние "нужно выполнить", только одна дополнительная комманда. Нафига вам вообще их в массив запихивать?
Чем aCommand=TLED_H, хуже чем comma="TLE1"? Помоему только тем, что никаких циклов/поисков не нужно. Если я, случаной напишу aCommand=tled_h - компилятор сразу завопит. А если напишу comma="tle1" - все скомпилируется тихо, но работать не будет.
Да, привер занятный...
Давайте начнем с начала...
Этот ПАК должен выполнять ряд действий...
1. Опросить 30 датчиков, возможно сразу среагировать на выход перемтров за критические пределы
2. Основываясь на данных датчиков, изменить состояние аттенюаторов, 6 устройств 2-10 В, 8 реле
3. по расписанию, скажем каждые 5 минут отправить данные по GPRS на серевер
4.Принимать и отсылать СМС с данными и командами.
5. Принимать команды из консоли.
6. логировать директивы, полностью или частично
Как себе я это видел - организовать внутреннею жизнь на основе директив, как единицы принятия решения, Директивы универсальны, через них инкапсулируются все действия, к примеру изменить значение переменной t_LOW можно только директивой SET;t_LOW;25 , и не важно откуда директива пришла , через перефирию или ее сгенерировал исполняемый код. Изменить состояние аттенюатора (к примеру обороты на насосе с частотником) можно только директивой SET;w_PUMP1;100 (по сути опять таки изменить значение определенной переменной), и только так. Код на прямую не может изменить состояние переменных. Директивы логируются.
Значит, нам нужно описание этих директив, некий парсер команд и то, что эти команды исполняет. Кроме этого, некая структра, описывающая нормальную последовательность исполнения команд основного цикла...
1. Опросить датчики
2. сравнить состяние основных переменных и показаниями датчиков
3. записать новые значения переменных аттенюаторов
4. привести состяние аттенюаторов к этим переменным
6. записать лог
7 опросить порты и по расписанию отправить состояие основных переменных на сервер.
Что конкретно Вы предлагаете ?
>Как себе я это видел - организовать внутреннею жизнь на основе директив, как единицы принятия решения,
Еще раз говорю... почитайте про "машину состояний". Вы сейчас пытаетесь изобрести велосипед. В том числе и терминологически.
Почитайте, но не кидайтесь сразу реализовыать...
>Что конкретно Вы предлагаете ?
Я уже говорил "кушайте слона по кусочкам". Написали вы кучу пунктов. Которые ЯВНО предполагают, что ВСЯ работа должна быть не блокирующей. Вот, значит, вот этому и нужно вначале научится.
Реализуйте один пункт, потом другой... потом попытайтесь их сцепить. Причем обычный
Или switch(mode) - тоже не плохое решение. С++ в своем ситаксисе уже содержить все средства для "описывающая нормальную последовательность исполнения команд". И воротить какие-то "коммандные процессоры", нужно начинать только когда вы увидите что "без этого никак". Не нужно городить "структуры", "процессоры" только ради того что "это круто".
Вообщем начните с начала. С того чем ваша ветка и начиналась.
Без блокировки. Сделайте вначале "тупо". Пусть вначале заработает "хоть как-то". Потом уже будете смотреть как это можно сделать "более красиво", "более универсально" и т.п.
К "универсальности" вообще лучше переходить, когда уже будут работающие паралельно два/три пункта. Когда не "умозрительно", а реально будете видеть "что между ними общего". Вот это общее уже и выносить в какие-то "процессоры" и т.п.
Я знаю что такое МТ, хоть и не разработчик. Но не вижу связи, если честно. Мы явно не понимаем друг друга. Хоть как то, это работает, по крайней мере работает некая модель, в которую не внесена логика основных процессов. Я хотел бы вносить эту самую логику уже в отрыве от реализации, т.е. должна работать некая оболочка, отвечающа за переферию и основной цикл, куда уже будут добавляться конкретная реализация процессов... в виде инструкций или директив. Хорошо, попробую вернуться к "многозадачности" :)
Или switch(mode) - тоже не плохое решение. С++ в своем ситаксисе уже содержить все средства для "описывающая нормальную последовательность исполнения команд".
Вот это вообще не понятно.
В общем, не выходит пока каменный цветок.... Пробовал библиотеки четыре, protothread,mtread,arcos еще ккие то... Все не то. Проблема в том, что потоки можно тормазить тока в конце его выполнения. Protothread вроде получше, но пока не всЕ там понял...
Что он дальше делал? Бляшки точить начал. Не цветок. А невеста его, Катя-Мертвякова, когда приперло и пришлось учится каменному делу..?
Так что, "запончик надел и пошел бляшки да ручки к вилкам точить".
А цветок-то, кстати, был примером именно задачи "не по зубам". Задачи которая крышу сорвала. Решения которой пришлось брать со стороны и расплачиваться за это по цене ставящей под сомнение целесообразность этого. Решение которой, по большому счету ничего кроме горя - не принесло.
Так что "бибилиотеки" можно брать когда уже есть понимание "как самому такую библиотеку написать". Готовое берется "чисто для экономии времени". Когда оно уже не представляет собой "магический черный ящик", который делает что я хочу. Когда есть понимание как оно работает (и почему именно так), отсюда есть и понимание "как этим пользоватся", какие ограничения и расплаты...
Спасибо на добром слове :)
Но на шпагат я таки сел, все работает и не блокируется... я имею в виду долгую функцию..., теперь вернусь к основному циклу и командам:) Решил с использованием протопотоков. Хорошее примитивное решение. Чего то дружище kisoft молчит :) а сейчас как раз будет время оптимизации памяти :) , придется все команды снова запихивать во флеш...
Чето я посмотрел, как расходуется память на 328, и захотелось сразу перейти на stm32 :)
Ага и юзать какую нибудь RTOS :) Я, правда не пробовал, но Tiva C & STM32F103 время от времени мучаю.
PS Я молчу, потому что времени маловато, да и диалог вроде идет. А еще я далеко не всё понимаю и уже подзабыл, что было в начале, потому надо читать снова :) Ну а в выходные я поеду смотреть Мировую серию Рено за 140 км от нас, потому на весь день. Хорошо хоть иногда есть время форум полистать на работе.
PPS Потоки можно тормозить и не в только в конце, но это на "больших компах", в Ардуине я потоков (нитей) даже не видел еще, да и смысла особого не вижу в них.
Я сегодня приобрел stm32m4 discavery, воткнул туда clr, и буду пробовать с# на этом :) и пототом freeRTOS.
Вещь! Ну а по нашим делам, не я так не про потоки а про задачи при кооперативном шеделере, просто везде кроме протопотоков , эти задачи тормазатся в конце ... Не суть, на протопотоках все ок. Есть кооперация:)