k155la3 26 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 4 hours ago, ARV said: Мда... ужос. Еще больше убеждаюсь, что в данном контексте асинхронность - злейшее зло, поллинг наше все. Ужас происходит от избытка инф-ии. Начните с простого, выделение из потока байт пар <CR><LF> которые являются разделителями. То, что принято из потока ранее разделителя - укладывается в строковую переменную (или их массив). Если Вы сделаете такой "разборщик-парсер" вывода для одной AT-команды, то для остальных (ATкоманд) все будет намного проще (принцип один). Фактически, sscanf работает как универсальный настраиваемый парсер входного массива по правилам, указанным в строке формата. Вам универсальность не требуется, но надо для "вывода" каждой AT-команды создать свой "умный" sscanf + анализатор результата. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 2 часа назад, k155la3 сказал: Если Вы сделаете такой "разборщик-парсер" Да сделал я это... Только, подозреваю, перемудрил. Говорю же: мой парсер полностью асинхронно отрабатывает все уведомления модуля... Да только асинхронность эта для СМС приема и передачи боком выходит. // сообщение DTMF-кнопки CMD_HOOK(DTMF){ // транслировать символ в главную задачу //str = DTMF: 1 // ^ // 01234567 send_to_main(MSG_KEY, str[6]); } // ответ на запрос баланса CMD_HOOK(CUSD){ // находим первую кавычку в строке - это начало сообщения char *start = strchr(str,'"')+1; // находим последнюю кавычку - это конец сообщения char *end = strchr(start,'"'); *end = 0; if((start[0] == '0') && (start[1] == '0')){ // это UCS2-кодировка ucs2_to_text(start); // функция оставляет только латинские символы, цифры и знаки strstr(start, " .p")[3] = 0; // хак - отбросим лишний хвост debug_i(max_avail()); mem_reduce(str, strlen(str)+2); debug_i(max_avail()); } // вычисляем реальную длину полезных данных uint8_t sz = strlen(start); char *sms = mem_alloc(sz+1); // копируем данные в отдельную область strncpy(sms, start, sz); // отправлем эту СМС sms_send(cfg.mstr_phone, sms); // освобождаем память отправленной смс mem_free(sms); } Вот из примерно таких обработчиков состоит мой код. А вот так выглядит отправка СМС: void sms_send(uint8_t n, const __memx char *send_sms){ if(n == 0) return; // выделяем память под команду char *cmd = mem_alloc(TEL_LEN + 2 + COUNTRY_CODE_LEN + 26); if(!cmd) return; debug_s(send_sms); // формируем команду strcpy_P(cmd, PSTR("+CMGS=\"")); strncat(cmd, cfg.country, COUNTRY_CODE_LEN); strncat(cmd, cfg.phone[n-1], TEL_LEN); strcat(cmd,"\""); // отправляем команду gsm_at_cmd(cmd); // освобождаем память mem_free(cmd); //Task_Sleep(1000); // выводим тело сообщения while(*send_sms) gsm_send_char(*send_sms++); // завершаем сообщение Task_Sleep(10); gsm_send_char(SMS_END); } Видите - Task_Sleep в разных местах? Это борьба с асинхронностью, потоу как прием "промпта" в мою концепцию не укладывается. Хотя если постараться, можно упихать. Просто никак не могу решить: надо ли корячиться, или плюнуть на асинхронность? Просто уже очень много сделано... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 7 часов назад, rx3apf сказал: А что сложного с PDU ? Сложного - ничего, но сообщение в этом формате может быть слишком большим - много памяти надо, ведь никогда не знаешь, кто и что там пришлет, потому закладываться придется на максимальную длину... А реальной необходимости в приеме мультиязычных и мультисимвольных сообщений нет, достаточно и латиницы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 26 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба sms_send(cfg.mstr_phone, sms); Ваше void sms_send( ) Ситуации могут быть разны, от отсутствия сети до отключенного телефона у абонента и мало ли чего там еще может быть. Хотябы 2 кода - успешно выполнена операция или нет. //Task_Sleep(1000); Посмотрите в Вашей ОС (кстати какая ? "нЭ узнаЛ") наличие мьютексов и семафоров. В том месте, где Вы хотели использовать Task_Sleep() можно поставить ожидание флага MyMutex.wait(4000); В асинхронном потоке, соответственно, Вы устанавливаете-lock и сбрасываете-unlock флаг (mutex) поток В while(1) { if( parse_code != 0 ) { switch( parse_code ) { case CMD_SET_REG: . . . . break; case CMD_GET_REG: . . . . break; case CMD_SEND_SMS_A: // разбор ответа модема на фазу "А" - ждем промпт или что-то еще MyMutex.lock() // установить блокировку 1 "блокировка установлена" retc = modem_Get(); . . . . MyMutex.unlock() // снимаем блокировку, тк от модема получен (или не получен, те ошибка) блок инф-ии break; case ... case ...case ...case ... }//sw parse_code = 0; }//if else sleep(10); } //while поток A (основной алгоритм, который остановлен для ожидания выполнения операции в потоке B) retc = sendSMS("122245"); if( retc == OK ) { retc = MyMutex.wait(4000); // здесь "залипаем" на ожидание выполнения операции в потоке A - не более чем на 4000мс . . . . здесь или истек таймаут в 4000мс или операция завершилась (сбросился lock в потоке A) - см. retc . . . . } else display("error"); При залипанни на wait OS не тормозится, это такой sleep(x) c встроенным таймером и анализом условия. (Как синхронизировать асинхронность) . ps Я не претендую на "истину и правильность", нас поправят и наставят на путь истинный старшие товарисчи :) psps - TC, с каким объемом RAM имеем дело ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rx3apf 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 3 часа назад, ARV сказал: А реальной необходимости в приеме мультиязычных и мультисимвольных сообщений нет, достаточно и латиницы. А потом захочется узнать баланс, а там вдруг оператор решит, что это надо именно в PDU передать... Что же это за платформа такая, что за каждый байт RAM жаться приходится (я вообще лишнего не привлекал, есть рабочий буфер для разных нужд, им и пользуюсь). Не, дело хозяйское, конечно... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба 7 часов назад, rx3apf сказал: А потом захочется узнать баланс, а там вдруг оператор решит, что это надо именно в PDU передать... Оператор и так это решил :) но ответ на запрос баланса короткий даже в PDU, я из него тупо выдергиваю символы, которые кодируются 00ХХ, т.е. с лидирующим нулем (латиница) и все остальное отбрасываю - баланс цифрами и знаками остается :) 8 часов назад, k155la3 сказал: можно поставить ожидание флага MyMutex.wait(4000); Принципиально это ожидание от Task_Sleep отличается мало, как и от тупого delay()... и все это как-то неприятно. Что касается сути моих вопросов, то, пожалуй, я окончательно решил пока что не заниматься переделками, а оставить все, как уже работает и проверить необходимость задержек в реальном железе, т.к. велика вероятность, что их необходимость обусловлена смешением реальности с виртуальностью. 9 часов назад, k155la3 сказал: Ситуации могут быть разны, от отсутствия сети до отключенного телефона у абонента На счет отсутствия сети - об этом стоит подумать... Пока не очень понимаю, как это простыми средствами выяснить (просто по ERROR этого не поймешь, надо подробности узнавать, а это пока что представляется какими-то лишними телодвижениями). Но это не большая проблема - разберусь по документации. А выключенный телефон у абонента, как я понимаю, обнаружить при отправке СМС невозможно, да и не нужно - если СМС не дошла быстро, необходимость в ней пропадает - кому надо узнать, что на даче лопнула труба и все залито вдой спустя 3 дня? Об этом с тем же успехом можно и весной узнать по приезду :) 9 часов назад, rx3apf сказал: Что же это за платформа такая Самая что ни наиесть простейшая - atmega128. RAM 4K, RTOS - FunkOS (с небольшими собственными доделками). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 26 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба 2 hours ago, ARV said: Что касается сути моих вопросов, то, пожалуй, я окончательно решил пока что не заниматься переделками, а оставить все, как уже работает и проверить необходимость задержек в реальном железе, т.к. велика вероятность, что их необходимость обусловлена смешением реальности с виртуальностью. . . . Если сформулировать в контексте толерантности, то будет излишним настаивать в применении иных технических и мировоззренческих решений ps Не знаю, есть ли JTAG и аппаратная отладка для atmega128. Если ее (вдруг) нет - бросайте ЭТО вмести с виртуальностью и переходите на норм. современную платформу - ARM или что-то с возможностью прямой отладки софта в железе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба А абсолютно толерантен к советам, более того, я их ищу. И очень благодарен всем, кто готов их мне давать. Но любой совет я рассматриваю через призму целесообразности применения. У меня сейчас есть задержки в смешении с асинхронностью, причем асинхронность реалзована более удачно (имхо), нежели мне советовли. В частности, у меня нет цикла, в котором я зависаю при ожидании асинхронного сообщения от модуля, т.е. нет одной задачи в контексте RTOS. Все советы, данные мне, не избавялют меня ни от задержек, ни от каши из синхронно-асинхронных подходов. Поэтому я не вижу принципиальной выгоды переделывать все уже работающее. Логично? Если доведется в будущем что-то делать снова с таким модулем, возможно, уже буду изначально поступать иначе... Только что, k155la3 сказал: переходите на норм. современную платформу - ARM или что-то с возможностью прямой отладки софта в железе А вот это не тот совет, в котором я нуждаюсь. Что изменилось за последние 4-5 лет, что вдруг едва ли не один из самых крутых среди доступных МК стал никуда не годным? Лень разработчика выросла? Или USART вдруг стал 32-битным и бешено скоростным? Или мода поменялась? Не желаю идти на поводу у мнимого "прогресса". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rx3apf 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 (изменено) · Жалоба 3 часа назад, ARV сказал: Самая что ни наиесть простейшая - atmega128. RAM 4K У меня была 644 (в которой больше половины осталось). Какой-то дополнительной оперативки для PDU не потребовалось... 33 минуты назад, ARV сказал: Или USART вдруг стал 32-битным и бешено скоростным? Или мода поменялась? Но вообще-то FIFO или DMA на UART точно не повредил, несколько досадно отдавать ресурсы на обработку каждого байта, особенно если и UARTов два. Если работать только с модемом, да и на 9600 - ясное дело, что проблем не будет. На 115200 уже несколько сложнее. Да и производительность CPU невысока, если работаем от 3.6...4.2, то выше 7.3728 уже и не прыгнешь. Мне, впрочем, вполне хватало - но там был чистый asm. Очень люблю AVR, не знаю, к сожалению, ARM - но в данном случае ARM кажется предпочтительнее. Да и дешевле они, существенно. Изменено 15 февраля, 2019 пользователем rx3apf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба Только что, rx3apf сказал: Какой-то дополнительной оперативки для PDU не потребовалось... Так понимаете ли в чем дело... Я стал заложником выбранного (и по высказанным советам не факт, что верного) пути: RTOS. На каждую задачу под стек от 128 до 460 байт (подобрано минимальное значение в протеусе), на кольцевой буфер каждого USART еще по 64 байта... Еще под кучу буфер... И в итоге уже задумываешься: стоит ли статически выделять под буфер еще порядка 360 байт на PDU или не стоит... Только что, rx3apf сказал: несколько досадно отдавать ресурсы на обработку каждого байта Считаете, отдать их на Sleep или Mutex.wait менее досадно ? ;) Только что, rx3apf сказал: Если работать только с модемом, да и на 9600 - ясное дело, что проблем не будет. На это и уповаю :) МК сейчас работает на 8МГц и основную часть времени проводит в Task_Idle. А те задачи, что помимо обмена с модемом и т.п., у меня не требуют какой-то выдающейся реакции или быстродействия. Собственно, как практически все задачи, которые могут прийти в голову любителю домашней автоматики. Только что, rx3apf сказал: ARM кажется предпочтительнее Не думаю, что на эту тему стоит дискутировать вообще и в данной теме в частности. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 26 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба 17 minutes ago, ARV said: ... Я стал заложником выбранного (и по высказанным советам не факт, что верного) пути: RTOS. . . . "Заложником" можно стать, если вы изготовили партию плат с "неправильным" hardware. А так .... Вот, промежуточный вариант между "циклом" и ОС ТУТ - псевдо-ОС без отдельных стеков для задач. "Кооператив". Если Вы вернете софт на цикл, то следующим этапом можете попробовать упорядочить проект с использованием Protothreads. В прерывания вывести буферизацию USART и таймер ms. Примеры - ТУТ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба Только что, k155la3 сказал: А так .... Ну как бы порядка 3 десятков файлов с общим количеством строк больше 100 тысяч тоже жалко... Что-то, конечно, уцелеет, старался обеспечить независимость модулей, но все равно работы много. И переходить на новую парадигму вообще сложно - еще и сознание надо перестроить. В RTOS просто эйфорию испытал от возможности пользоваться готовыми очередями, хоть ничего сложного в них нет и можно всегда реализовать аналог. Кооператив вообще не хочется даже обдумывать, потоу как возможность не ограничивать себя в длительности циклов дорогого стоит. Все ж хочется сделать с минимумом усилий, и RTOS как бы дает на это надежду... Да и не пробовал RTOS до этого ни разу на МК. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 26 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба 24 minutes ago, ARV said: . . . В RTOS просто эйфорию испытал от возможности пользоваться готовыми очередями, хоть ничего сложного в них нет и можно всегда реализовать аналог. . . Попробуйте в небольшом тестовом проекте поработать с мютексами. Есть некоторая вероятность, что их использование в Вашем проекте уменьшит кол-во кода и позволит уйти от граблей с синхронизацией, в частности - с сессиями обмена с модемом. IMHO Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба 22 часа назад, ARV сказал: // находим первую кавычку в строке - это начало сообщения char *start = strchr(str,'"')+1; // находим последнюю кавычку - это конец сообщения char *end = strchr(start,'"'); *end = 0; А здесь видимо повисаем или чё-нить портим если вдруг в строке не оказалось кавычек или кавычка оказалась одна. 22 часа назад, ARV сказал: if((start[0] == '0') && (start[1] == '0')){ А здесь видимо лезем за пределы строки, если пришла пустая строка "". Очень всё коряво.... 2 часа назад, rx3apf сказал: Но вообще-то FIFO или DMA на UART точно не повредил, несколько досадно отдавать ресурсы на обработку каждого байта У автора обработка так неоптимально написана, что DMA будет мёртвому припарка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 15 февраля, 2019 Опубликовано 15 февраля, 2019 · Жалоба Только что, k155la3 сказал: Попробуйте в небольшом тестовом проекте поработать с мютексами Мьютекс мне представляется менее удачным решением. Смотрите, как сделано сейчас у меня. Главная задача-дспетчер имеет очередь сообщений. По прерываниям от GSM-модуля USART я принимаю заранее определенный набор его уведомлений, и посылаю строку с одним из этих уведомлений в главную задачу. Там происходит выбор соответствующей функции-обработчика и т.п. Помимо сообщений от GSM, в очередь поступают и другие, так что как бы отдельного "зависания в ожидании" для модема нет. Когда в очередь попадает сообщение с требованием что-то послать в модем, получается чуть хуже: послать-то я посылаю легко прямо из основной задачи, но когда требуется получить ответ (например, текст СМС), приходится перенастраивать обработку прерываний USART так, чтобы байты попадали не в кольцевой буфер (он мал - 64 байта), а в заранее выделенный большой линейный буфер, и потом ждать, пока прием не закончится (или таймер не истечет), восстанавливать работу по кольцу и т.п. О том, что прием закончился, я узнаю снова через сообщение из очереди. Только в этом моменте небольшая заковыка - и таймер ожидания задействован, и освобождение памяти не в том месте, где выделение... короче, тут некрасиво. Но работает. Хоть и не предусмотрено прибытие вместо ожидаемых данных какого-то уведомления (что, конечно, не хорошо). С мьютексами я просто сведу обработку сообщений в главной задаче в цикл ожидания мьютексов, и эта задача по сути станет заблокированной на все время, пока я жду - очередь обрабатываь она не сможет. Что не очень хорошо, как я понимаю... Только что, jcxz сказал: А здесь видимо повисаем или чё-нить портим если вдруг в строке не оказалось кавычек или кавычка оказалась одна. Я подумаю и отвечу, но не сразу, а позже. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться