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

Модуль SIM800 не отвечает на команды

Только что, jcxz сказал:

А здесь видимо повисаем или чё-нить портим если вдруг в строке не оказалось кавычек или кавычка оказалась одна.

Отвечаю: вы нашли ошибку а-ля copy-paste :) это скопипащено с обработчика +CMGR, а там в кавычках приходит номер оправителя... а тут эта часть ничего хорошего не делает. Спасибо! 

Весь код не хотите осмотреть? ;)

Только что, jcxz сказал:

У автора обработка так неоптимально написана

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

1. кольцевой буфер, ловим в прерываниях '\r'

2. впоймали - посылаем сообщение о необходимости разбора строки между пойманным и предыдущим '\r' (саму строку вытаскиваем из кольца)

3. в массиве обрабатываемых сообщений ищем совпадение начала строки с шаблоном ("+CUSD", "+CBC" и т.п.), при совпадении - вызываем соответствующий обработчик. 

Разве плохо? Пока идет разбор принятой строки продолжается прием в буфер... Ничего не стопорится.

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


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

 

35 минут назад, ARV сказал:

А вот сейчас обидно было... Мне так кажется весьма элегантный алгоритм.

Я не про весь алгоритм, которого не вижу, а про приведённый кусок. Тот что после CMD_HOOK(CUSD).

Все символы строки внутри кавычек вы перебираете как минимум трижды(!): внутри strchr, внутри strlen, внутри strncpy. Зачем так громоздко? Ведь достаточно всего двух простых циклов с одним указателем для поиска '"' || '\0'? И зачем затем ещё и копировать эту строку в отдельный буфер (ещё и выделение его и освобождение потом)? Какой смысл?

Да ещё и динамическая память используется, которая тут совсем не нужна.

 

По уму надо сделать 1-й цикл: поиск '"' || '\0'. Если найдено '"' - идём дальше, иначе - выход. Дальше - 2-й цикл: поиск '"' || '\0'. Если найдено '"' - идём дальше, иначе - выход. Если всё прошли, получим длину просто вычтя указатель полученный в 1-м цикле из указателя 2-го цикла. А потом передадим указатель из 1-го цикла в sms_send() вместе с длиной строки. И не будет этой кучи ненужных операций и вызовов функций. 

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


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

4 часа назад, jcxz сказал:

Зачем так громоздко?

А зачем вообще libc существует, можно же всякий раз цикл самому писать? Да и RTOS тоже ерунда - все эти мьютексы не более чем статические переменные с атомарным доступом, есть же cli-sei, в чем проблема? Очередь - всего лишь массив с "памятью" головы/хвоста или список структур... 

 

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


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

7 минут назад, ARV сказал:

А зачем вообще libc существует, можно же всякий раз цикл самому писать?

А сейчас у вас этот самый libc за вас пишет что-ль?

И зачем тогда бейсик существует? Пишите на бейсике - что-ж его зря создавали что-ль?

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


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

Только что, jcxz сказал:

А сейчас у вас этот самый libc за вас пишет что-ль?

Нет, не пишет. Ну так strncpy и есть аналог цикла, как и strlen. Только вместо трех-пяти строк записывается в одну.

И бейсик, и Си создавались для того, чтобы меньше приходилось тратить сил на рутину. Вот я и пытаюсь меньше тратить...

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


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

1 минуту назад, ARV сказал:

Нет, не пишет. Ну так strncpy и есть аналог цикла, как и strlen. Только вместо трех-пяти строк записывается в одну.

И бейсик, и Си создавались для того, чтобы меньше приходилось тратить сил на рутину. Вот я и пытаюсь меньше тратить...

Т.е. - сознательно пишете неоптимально, а потом почему-то обижаетесь на "неоптимальный код"?

Если считать на строки, то с циклами будет примерно столько же строк. Если конечно написать то, что вы привели корректно, со всеми проверками.

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


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

Это хорошо, что вы критикуете мой код. Спасибо вам за время, потраченное на меня.

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

Например, у меня есть структура с номерами телефонов, и для отправки СМС я написал такую функцию: void sms_send(char *str, uint8_t num), где num - номер телефона в виде индекса в массиве номеров. И эта функция использует другую функцию gsm_send_cmd(char *cmd), вся роль которой сводится к добавлению перед cmd префикса "AT" и "\r" после, и все это уходит в USART. А подготовка cmd для этой функции заключается в куче strncpy или sprintf, чтобы собрать воедино номер телефона, тело сообщения и т.п.

После вашей критики я понял, что слишком глупо сделал: для чего копировать номер телефона в строку, чтобы потом эту строку выдать в USART, если номер сразу можно выдавать в USART прямо из массива, где он и хранится?! и так далее - слишко много манипуляций со строками у меня, которые никакой пользы не несут. Так что польза несомненна... как и неизбежность значительных передлок.

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

а потом почему-то обижаетесь на "неоптимальный код"?

Вы же видели, что неоптимальность я отнес на счет обработки "верхнего уровня", а не "нижнего". Алгоритм "верхнего" я описал в трех пунктах, а до этого рассказывал о нем дважды или трижды словесно. И мне кажется, алгоритм весьма оптимален. Хотя, чем больше читаю ваши ответы, тем сильнее сомневаюсь в этом...

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


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

Кстати, на счет разыменования NULL я был не прав: у меня в коде все правильно. Я об этом:

CMD_HOOK(CUSD){
	// находим первую кавычку в строке - это начало сообщения
	char *start = strchr(str,'"')+1; // TODO это вообще что такое?! зачем оно здесь?
	// находим последнюю кавычку - это конец сообщения
	char *end = strchr(start,'"');
	*end = 0;
	if((start[0] == '0') && (start[1] == '0')){
		// это UCS2-кодировка

Здесь идет обработка уведомления, которое ВСЕГДа имеет такой формат +CUSD=1,"сообщение", поэтому поиск кавычек вполне корректен, как и последующий анализ 0-го и 1-го байта полученной строки. Варианта, когда кавычек нет или между ними нет строки - не существует. Я поспешил, когда признал тут проблему.

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


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

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

которое ВСЕГДа имеет такой формат +CUSD=1,"сообщение",

Вот ещё из моей коллекции артефактов:

(x0D)(x0A)+CUSD: 2, "Vasha SIM aktiviruyetsya. Chtoby uznat' balans, povtorite komandu *102# cherez 5 min", 15(x0D)(x0A)

(Здесь (x0D)(x0A) - это от парсера вывод в лог.) И коль кодировка=15, надо опасаться того, что оператор может включить в текст в том числе и кавычку двойную.

Что делать? Разбор с конца строки. DCS, затем закрывающую " - так найдём конец сообщения.

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


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

10 часов назад, ARV сказал:

Здесь идет обработка уведомления, которое ВСЕГДа имеет такой формат +CUSD=1,"сообщение", поэтому поиск кавычек вполне корректен, как и последующий анализ 0-го и 1-го байта полученной строки. Варианта, когда кавычек нет или между ними нет строки - не существует.

Из чего это следует? Где то раньше в коде есть проверка этого условия?

Если такой проверки нет, то на входе устройства (на RXD UART) может быть всё что угодно. Корректно написанное ПО всегда должно предполагать, что по внешним интерфейсам связи ему может поступить всё что угодно, вне зависимости от того что там подключено или не подключено и какой заявлен протокол обмена. Подключенное устройство может глюкануть из-за помехи, может проявиться баг в его прошивке (при некотором условии), может пересброситься во время передачи, может произойти помеха на линии, может выйти новая прошивка этого устройства, где поменяют формат протокола обмена - да всё что угодно! Если Ваше ПО не рассчитано на такое, и при каждом таком чихе тупо виснет, то ваше ПО - КРИВОЕ.

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


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

11 часов назад, ARV сказал:

И мне кажется, алгоритм весьма оптимален. Хотя, чем больше читаю ваши ответы, тем сильнее сомневаюсь в этом...

Если Вы заметили - про неоптимальность я написал в ответ на советы по поводу DMA. Но если сам код обработки построен так неэффективно, то прежде чем думать о DMA, надо сперва улучшить код там, где это даст в разы больший эффект, при в разы меньших усилиях. И только когда обработка вся будет сделана эффективно, только тогда следует думать о дальнейшей оптимизации при помощи DMA. Оптимизацию всегда нужно начинать с мест, где будет наибольший выигрыш.

А если, как Вы говорите, вас и так по скорости всё устраивает, то и о DMA и прочих крохах улучшения говорить - нет смысла. Я же не говорю, что надо обязательно оптимизировать. Если эффект от выигрыша в скорости несущественнен для вас - ну и ладно. Хотя в то же самое время вы ранее говорили о нехватке памяти в МК, а уже в этом участке кода так бессмысленно её расходуете, то это очень странно. У меня сейчас проект на МК с ОЗУ ==352КБ и с кучей кода и задач. И то я при этом нигде ни разу не использую дин.память - не нужно это и вредно и бессмысленная трата памяти.

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


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

1 час назад, jcxz сказал:

МК с ОЗУ ==352КБ и с кучей кода и задач. И то я при этом нигде ни разу не использую дин.память - не нужно это и вредно и бессмысленная трата памяти

Когда памяти достаточно, её можно и не экономить. А когда ее не хватает, надо искать способ, как одну и ту же область памяти разделить на разные задачи, и тут динамическое распределение - единственный выход. Например, как можно отправить строку из одной задачи в другую, если память под строку не выделять динамически? Задача А, допустим, имеет статическую область (массив), сформировала там текст и отправила этот массив в задачу Б через сообщение. Пока задача Б не закончит работу со строкой, задача А не может задействовать этот массив для отправки сообщения задаче С. В итоге мы имеем тупик. При динамическом выделении тупик возникнет только в случае исчерпания кучи, что при должном её размере не должно возникать. Я так думаю...

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

Корректно написанное ПО всегда должно предполагать, что по внешним интерфейсам связи ему может поступить всё что угодно, вне зависимости от того что там подключено или не подключено и какой заявлен протокол обмена.

Теория именно так и говорит, согласен. А практика убеждает, что корректно написанного ПО не существует в природе. Бесконечное стремление к совершенству - пустая трата времени. Мой оператор ничего другого не передает, и, если верить оператору-информатору, не планирует ничего менять. Нужно ли мне закладывать в ПО моего устройства алгоритмы, рассчитанные на все варианты, которые МОГУТ быть? Не уверен...

10 часов назад, Vladivolt сказал:

Вот ещё из моей коллекции артефактов:

Угу, именно артефактов - явлений, исключительных, редких и необъяснимых. Вставлять в устройство еще неактивированную симку, закладывать в алгоритм вариант, когда она будет самоактивироваться... тогда еще и PIN надо автоматически "снимать" - на некоторых симках же он установлен, и не на всех обязан быть 0000, не так ли? У вас в ПО это учтено? Не проще ли ограничить число вариантов простым требованием устанавливать в устройство активированную симку со снятым запросом PIN и с уже ненулевым балансом?

Производители автомобилей не закладывают в возможности авто варианты, когда пользователь вместо бензина нальет в бак дизель или вообще жидкость для омывания стеол, а ведь такое возможно В ТЕОРИИ... Производитель на лючке бака пишет "только А92 или выше" и ограничивается этим.

ИМХО, разумный компромисс - это намного лучше, чем параноидальное стремление к идеалу надежности...

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


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

17 минут назад, ARV сказал:

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

Распространённое заблуждение. С чего бы это "единственный"? Что мешает передать через обычный статический буфер? А если нужно разделить для использования разными задачами, то для этого есть union и семафоры ОС.

И с чего бы это динамическая память "позволяет экономить"? Памяти как раз тратиться намного больше (служебные области/заголовки блоков, фрагментирование), так что это наоборот - растранжиривание, и можно использовать только там, где памяти вагон.

Цитата

Теория именно так и говорит, согласен. А практика убеждает, что корректно написанного ПО не существует в природе. Бесконечное стремление к совершенству - пустая трата времени.

И тогда следует писать заведомо кривое ПО? Странная логика....  :russian_ru:

Если скажем Вы слушаете человека и вдруг он на полуслове прерывает фразу и уходит, Вы же при этом не повисаете? И не забываете своё имя? А ведь он не закрыл кавычки закончил фразу! А почему тогда ваше ПО повисает или рушит память в аналогичной ситуации?

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


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

1 час назад, jcxz сказал:

Что мешает передать через обычный статический буфер? А если нужно разделить для использования разными задачами, то для этого есть union и семафоры ОС.

Послушайте, разве то, что вы сказали, не то же самое, что сказал я?

1 час назад, ARV сказал:

В итоге мы имеем тупик.

Какая разница, торчим мы в тупике по семафору, ожидая освобождения статического буфера, или по иной причине? При динамическом выделении мы в тупике вообще не торчим. Разве это не стоит того?

1 час назад, jcxz сказал:

И с чего бы это динамическая память "позволяет экономить"?

По причине того, что static-буфер в одном модуле для одной задачи не "виден" другой задаче в другом модуле, соответственно, 10 буферов для 10 задач по 100 байт - это килобайт памяти. В то самое время кода вероятность того, что все 10 задач захотят занять каждая свой буфер одновременно, как правило, мала (особенно, если эти буферы служат для обмена сообщениями), и принципиально можно обойтись и динамически разделяемым буфером в 500 байт, а может и в 200. На моем собственном примере я убедился, что при статическом выделении буферов под обмен строками (учтем неоптимальность моего кода) при 4 задачах у меня остается свободными менее 800 байт ОЗУ, а с динамическим буфером в 640 байт уже 1200 байт свободно. Вот так и происходит экономия, и это с учетом расходов на служебные области...

1 час назад, jcxz сказал:

Если скажем Вы слушаете человека и вдруг он на полуслове прерывает фразу и уходит, Вы же при этом не повисаете? И не забываете своё имя?

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

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

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

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


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

21 минуту назад, ARV сказал:

При динамическом выделении мы в тупике вообще не торчим.

Почему это? Вы думаете динамическая память это такая магическая область, которая всегда обязана выдать вам память, вне зависимости от того имеется свободные блоки или нет?

Кстати в вашем коде ещё один косяк - нет проверки того, что mem_alloc() может вернуть NULL.

21 минуту назад, ARV сказал:

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

Опять "вероятность мала". Странный у вас подход к программированию. Если вероятность события мала, то забъём на него. Пускай устройство будет иногда глючить и виснуть и терять данные - это ведь редко происходит.

Если алгоритм написан так, что в какой-то момент времени все 10 задач могут затребовать одновременно память, то ПО должно быть рассчитано на это. И должно предоставить эту память. Или обеспечить блокировку задач (ожидание на семафоре) до момента освобождения памяти. Либо иначе алгоритм должно быть написан так, чтобы требовал одновременно блоков памяти не более чем имеется.

Всё остальное - кривое ПО, и годно лишь на помойку.

Если Вы с этим не согласны, и по вашему иногда глючащее ПО - это допустимая норма, тогда мне больше не о чем с вами разговаривать. Но и программистом вас считать тогда нельзя. Только былокодером. Уж извините.

21 минуту назад, ARV сказал:

Вот так и происходит экономия, и это с учетом расходов на служебные области...

Если все 10 задач могут в любой момент времени затребовать каждая по одному буферу в N байт, то (в случае статического распределения памяти), можно сделать 10 статических буферов по N байт. При этом потребуется 10*N байт памяти. Можно сэкономить сделав один буфер в N байт и распределяя его между задачами, блокируя задачи на семафоре до его освобождения. Можно сделать больше таких буферов, уменьшая вероятность блокировки задач (увеличивая доступность памяти), но в ущерб памяти.

С динамической памятью картина точно такая же: хотим чтобы все 10 задач независимо получали память - значит нужно иметь 10*(N+K) байт свободной памяти в куче в виде единого блока. Где K - размер заголовка блока менеджера памяти (K > 0). Если выделяемые задачам блоки могут иметь разный размер, то со временем будет происходить фрагментация кучи и уменьшение доступного объёма памяти. А значит к условию выше нужно прибавить ещё некий объём на случай наихудшей фрагментации. Т.е. - получаем что при тех же требованиях задач к памяти как и со статическим распределением памяти, при динамическом распределении может требоваться существенно больше памяти в системе. Если располагать объёмом памяти, меньше чем необходимо 10 задачам одновременно запрашивающим память, то как и в случае со статическими буферами, можно использовать семафоры для блокировки задач. Но неэффективность динамического распределения по сравнению со статическим от этого не пропадёт, просто потери памяти будут немного меньше.

Так что статическое распределение ВСЕГДА эффективнее по использованию памяти. По определению. Но конечно требует большего задействования мозга программистов.

21 минуту назад, ARV сказал:

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

У вас там может происходить разрушение памяти. Что будет в этом случае - никому неизвестно. И WDT предназначен не для костыленья кривого кода. А для борьбы с аппаратными помехами. Если код кривой - никакой WDT не поможет.

21 минуту назад, ARV сказал:

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

Да. Абсолютно всегда. Если делитель может быть ==0, то обязательно проверяю и обхожу. Если какие-то аргументы могут принимать недопустимые значения - обязательно проверяю это и обхожу. И никогда не рассчитываю на авось или какие-то вероятности.

21 минуту назад, ARV сказал:

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

Так и появляется быдлокод....

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


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

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

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

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

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

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

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

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

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

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