Jump to content

    

hound

Участник
  • Content Count

    12
  • Joined

  • Last visited

Community Reputation

0 Обычный
  1. В общем, думаю сделать следующее: при получении в прерывании сигнала о "другом режиме" выставлять флаг и в начале цикла этот флаг проверять, если он выставлен - выполнить нужное действие и дальше вернуться в "стандартный" режим. Обмен идет только синхронный, отправили команду устройству - ждем от него ответа, ответ получен отправляем следующую команду и так до бесконечности. А, например, как лучше поступить с такой задачей: есть 2 таска, первый таск отправляет через очередь сообщение второму таску, во втором таске это сообщение обрабатывается и ответ отправляется обратно первому таску. Городить 2 очереди? В первой исходящее сообщение, а во второй ждем ответа?
  2. Переход в другую задачу еще не совсем вариант, потому что это в этом "другом режиме работы" нужно девайсу отправить буквально одну команду. Идеальным вариантом было бы при получении в прерывании уведомления о этом режиме, например, выставлять флаг и запускать сразу следующую итерацию цикла. Перезапуск основной задачи тоже не вариант, т.к в начале этой задачи идет инициализация этого устройства и его первая перезагрузка, что в "разгаре" работы нельзя делать.
  3. Bulya, вариант да, но не охота создавать еще другие таски, стараюсь придерживаться принципа: 1-девайс подключенный к МК - 1 таск для него.
  4. Добрый день, есть таск для работы с некоторым внешним устройством. Устройство общается с МК по юарту, данные в прерывании складываются в буфер и очередьми отправляется в этот таск. В таксе есть основной бесконечный цикл, в котором по очереди выполняются разные функции. Т.е, грубо говоря: while (1) { func_1(); func_2(); func_3(); func_4(); func_5(); } Время выполнения каждой функции разное, примерно от 100мс до 1 сек. Но само устройство может перейти в другой режим работы, для которого нужно будет выполнять уже другие функции. И устройство может перейти в этот режим в любой момент. Когда устройство переходит в другой режим оно отправляет определенное сообщение МК. Это сообщение отлавливается в прерывании и дальше уже нужно заставить таск выйти из этого цикла и перейти в другой. Каким способ лучше подобное реализовать? Проверка на наличии сообщения о переходе в другой режим при проверки очереди в каждой функции не вариант, т.к функций в основном цикле может быть намного больше и каждый раз делать проверку кажется лишним.
  5. По концу строки <0xOD><0xOA> В прерывании: if (ch == 0x0D) return; if (ch == 0x0A) { modem_line_buffer.data[modem_line_buffer.pos] = 0x00; modem_line_buffer.pos = 0; modem_process_buffer(); return; } Дальше уже в функции modem_process_buffer() идет обработка сообщения void modem_process_buffer(void) { if (strlen(modem_line_buffer.data) < 1) return; if (strncmp(modem_line_buffer.data, "OK", 2) == 0) { tn_event_iset(&modem_event, MODEM_SAY_OK); return; } if (strncmp(modem_line_buffer.data, "SEND OK", 7) == 0) { tn_event_iset(&modem_event, MODEM_SEND_OK); return; } if (strncmp(modem_line_buffer.data, "+RECEIVE", 7) == 0) { uint16_t length; length = get_modem_token_int(modem_line_buffer.data, 1); modem_status.read_flag = TRUE; modem_receive_buffer_reset(&modem_receive_buffer, length); return; } if (strncmp(modem_line_buffer.data, wait_queue.data, wait_queue.length) == 0) { modem_send_queue(); } } Где, wait_queue.data, wait_queue.lengt это строка и ее длина для анализа ответа от модема, т.е отправили мы команду AT+CREG? и от нее нам нужно получить ответ вида +CREG: 2 Вот значение "+CREG" мы и записывает wait_queue.data. И уже кроме этого ответа ничего в очередь не попадает, а если что-то пришло от сервера, то в прерывании мы схватим сообщение "+RECEIVE", которое в очередь не попадет уж точно. Как-то так.
  6. В функции обработчике буфера от модема (в прерывании) до того как отправить буфер очередью проверяются такие данные от модема: 1. OK - выставляется флаг, который ожидает задача после отправки команды модему, если за N-ое кол-во мсек после отправки команды флаг не выставился - значит модем не ответил и дальше уже по обстоятельству (перазагрузка модема и т.п) 2. > - готов отправить данные серверу. 3. SEND OK - аналогично с флагом ОК только этот флаг ожидается после отправки данных "на сервер". 4. +RECEIVE: - получили данные "с сервера" и записываем приходящие данные в прерывании не в буфер модема, а в буфер входящих сообщений. И уже если эти 4 строчки не совпали смотрим отправлять ли очередь или нет, опять же в зависимости от того на какую команду ответ мы ждем. К сообщению приложил модуль, который на текущий момент у меня получился, пока еще без подключения к серверу и без полноценного разбора ответов. modem.rar
  7. Ну кроме работы с модемом нужно повешать еще и другие задачи, поэтому и использую операционку: один таск под модем, второй под работу с ГПС и т.д. каждый таск под свое устройство. Не совсем понял, а почему может составлять секунды? Модем висит на одном ЮАРТе, другие девайсы на другом и т.п под каждый юарт свой обработчик прерывания.
  8. А если сделать так: перед отправкой команды модему в глобальную перемену заносим начало ответа на команду, в случае с командой AT+CREG? это будет "+CREG", а в прерывании, вернее в функции обработчике буфера в прерывании будем сравнивать полученный ответ от модема с этой переменной. Тогда не нужно будет прочесывать каждый раз таблицу...
  9. Откопал же тему)) надеюсь тут еще кто-то есть и увидит мое сообщение) Ковыряю модем - Quectel m66, но особой роли не играет, главное те же самые АТ команды. Использую операционку TNKernel, но тоже особой роли не играет, разве что в этой системе в очереди передается указатель на данные, а не сами данные как, например, во FreeRTOS. К этому чуть позже вернемся) 1. Сделал отдельный таск под работу с модемом. 2. Линейный буфер, куда складываются все приходящие данные с модема, которые потом из прерывания передаются в функцию обработчик (modem_process_buffer). В функции обработчике (modem_process_buffer) проверяется строка от модема со следующими условиями: если пришел ответ OK, то выставляется определенный флаг, который в последствии мы будем ждать в функции отправке команды. Если пришел что-то другое, то копируем эти данные в массив буферов и номер в этом массиве отправляем уже очередью. Пример команды AT: uint8_t modem_check_at(void) { uint32_t flag, rc; uart3_ex_send_string("AT\r\n"); rc = tn_event_wait(&modem_event, MODEM_SAY_OK, TN_EVENT_WCOND_OR, &flag, 300); if (rc != TERR_NO_ERR) { dbg_send("AT fail\r\n"); return ACTION_FAIL; } dbg_send("AT ok\r\n"); tn_event_clear(&modem_event, ~(MODEM_SAY_OK)); return ACTION_OK; } Тут все просто, нужно только дождаться чтобы флаг ОК был выставлен. Сложности начинаются с командами в которых нужно парсить ответ от модема. Например, команда AT+CREG? На нее модем отвечает следующим образом: +CREG: 0, 1 OK Нужно дождаться именно этого ответа. Сделал следующим образом: Перед отправкой команды помещаю в некоторые переменные условия по которым мы должны отправлять очередь: uint8_t modem_creg(void) { uint32_t rc, flag, number_queue; // Используется в прерывании для определения условия отправки очереди strcpy(wait_data, "+CREG"); wait_length = 5; uart3_ex_send_string("AT+CREG?\r\n"); // Ждем ответ ОК от модема, если ОК пришло значит команда успешно выполнена rc = tn_event_wait(&modem_event, MODEM_SAY_OK, TN_EVENT_WCOND_OR, &flag, 300); if (rc != TERR_NO_ERR) { dbg_send("CREG fail\r\n"); return ACTION_FAIL; } tn_event_clear(&modem_event, ~(MODEM_SAY_OK)); // В очереди получаем порядковый номер в массиве для нашего сообщения tn_queue_receive_polling(&queue_modem_buffer, (void**)&number_queue); dbg_send("Answer CREG - "); dbg_send(modem_queue_buffer[number_queue]); dbg_send_rn(); return ACTION_OK; } И в свою очередь в функции modem_process_buffer (в прерывании): if (strncmp(modem_line_buffer, wait_data, wait_length) == 0) { modem_send_queue(); } Либо отправлять в очередь все что пришло и потом уже в функции отправки команды перебирать очереди пока не нашли нужный нам ответ, но так кажется более затратно... И стоит ли в подобных командах CREG, где нужно разбирать ответ от модема дожидаться именно приходящего ОК сообщения? Или можно просто дождаться уже ответа от модема +CREG и его разбирать, а после флаг ОК просто сбросить... Ах да, и вот сам таск для модема: void modem_queue_func(void *par) { dbg_send("Task modem start\r\n"); while (1) { modem_reset(); if (modem_check_at() == ACTION_FAIL) continue; if (modem_qimux() == ACTION_FAIL) continue; while (1) { if (modem_check_at() == ACTION_FAIL) break; if (modem_qistate() == ACTION_FAIL) break; if (modem_cgatt() == ACTION_FAIL) break; if (modem_creg() == ACTION_FAIL) break; } } } Пока без подключений к серверу, отправки данных и т.п главное пока разобраться с правильностью разбора команды и сообщений от модема.
  10. Добрый день. Есть GSM модем, управление, которого производится AT командами. Общий вид "общения" с модемом: 1. Отправляется команда 2. Ответ модема на команду (может отсутствовать) 3. Строка "OK", что мол команда выполнена. Соответственно есть команды, которые возвращают значение состояния модема, например: AT+CREG? +CREG: 0, 1 OK А есть, которые просто выдают строчку ОК, что команда принята и все, например: AT OK Собственно и нужно отслеживать каждый ответ модема и разбирать его, сейчас я сделал что-то подобное. Функция отправки простой AT команды модему: uint8_t modem_check_at(void) { uint32_t flag, rc; uart3_ex_send_string("AT\r\n"); rc = tn_event_wait(&modem_event, MODEM_SAY_OK, TN_EVENT_WCOND_OR, &flag, 300); if (rc != TERR_NO_ERR) { dbg_send("AT fail\r\n"); return ACTION_FAIL; } dbg_send("AT ok\r\n"); tn_event_clear(&modem_event, ~(MODEM_SAY_OK)); return ACTION_OK; } А в самом прерывании, если от модема пришла строка содержащее слово ОК, то выставляется флаг MODEM_SAY_OK: if (strncmp(modem_buffer, "OK", 2) == 0) { tn_event_iset(&modem_event, MODEM_SAY_OK); return; } С простыми командами так проходит, но сложность возникает с теми командами, в которых нужно разбирать ответ модема. Например команда: AT+CREG? После отправки модему она возвращает строку с определенными параметрами и после уже слово ОК, что команда выполнена. Поэтому простой проверкой на слово ОК не обойтись, нужно разбирать, то что ответил модем. Сделал таким образом: все строчки, которые пришли от модема складываются в очередь, которую уже должна обработать функция, которая отправляла данную команду модему, опять же пример: uint8_t modem_creg(void) { uint32_t rc, flag, number_queue; uart3_ex_send_string("AT+CREG?\r\n"); rc = tn_queue_receive(&queue_modem_buffer, (void**)&number_queue, 300); if (rc != TERR_NO_ERR) { dbg_send("CREG fail!\r\n"); return ACTION_FAIL; } dbg_send("Answer CREG - "); dbg_send(modem_queue_buffer[number_queue]); dbg_send_rn(); } Да момент такой еще, есть один линейный буфер, в который пишутся приходящие символы в прерывании, в том случае когда эту строчку нужно отправить через очередь, содержимое этого линейного буфера копируется в другой буфер, который представляем из себя "массив буферов" и собственно позицию в этом массиве и передается через очередь. Но в таком случае в очередь может отправится ЭХО модема и вместо ответа "+CREG: 0,2" в функции увидим "AT+CREG?", как вариант прогонять очередь до тех пор пока не попадется нужный нам ответ: do { rc = tn_queue_receive_polling(&queue_modem_buffer, (void**)&number_queue); if (strncmp(modem_queue_buffer[number_queue], "+CREG", 5) == 0) { return number_queue; } } while (rc == TERR_NO_ERR); Но это кажется сильно натянутым решением... Эхо от модема отключать не желательно,хотя это отчасти и решило бы проблему, но опять же не полностью. И кроме однострочных команд, модем может выдать много строчные команды. В общем, у кого-нибудь был опыт работы с АТ командами, кто как реализовал? Заранее благодарен за любой совет/пинок в нужную/правильную сторону.
  11. Да, действительно очень и очень глупая ошибка...конечно же проще все делать в одном таске, чем городить новые. Спасибо за разъяснение. Но появился следующий вопрос. После того как мы подали на некоторое время сигнал на ножку девайса нам нужно его настроить и если он не отвечает то его снова перезагрузить подачей сигнала на ножку. Как я себе представляю данный код в таком случае: void task_device(void *par) { while (1) { dbg_send("Reboot device\r\n"); GPIOB->BSRR=GPIO_Pin_1; tn_task_sleep(3000); GPIOB->BRR=GPIO_Pin_1; tn_task_sleep(2000); if (check_device() == ACTION_FAIL) continue; if (change_setting() == ACTION_FAIL) continue; while (1) { rc = tn_queue_receive_polling(&queue_modem_send_data, (void **)&pos); if (rc == TERR_NO_ERR) { device_send_message(); } if (check_device() == ACTION_FAIL) break; tn_task_sleep(1000); } } } Если девайс нам не отвечает на команды, то мы просто перезапускаем цикл. А уже во внутреннем цикле идет дальнейшая работа с девайсом, проверяем есть ли сообщения в очереди, если нет, то проверяем не подвис ли девайс, если подвис, то выходит из внутреннего цикла, а во внешнем цикле все по новой - перезагрузка, настройка и т.п И задача засыпает на 1000 тиков (в данном случае на 1 сек.) чтобы другие задачи могли выполняться. Использовать очередь с блокировкой задачи не совсем вариант, т.к нам нужно время от времени проверять состояние устройства. Или же можно реорганизовать работу данного таска?
  12. Добрый вечер, начал работать с TNKernel использую версию 2.7. Есть один вопрос: нужно определенную функцию выполнять через некоторое время системных тиков, сейчас реализовал через задачи подобным образом: #define REBOOT_START 0x00 #define REBOOT_UP 0x01 #define REBOOT_END 0x02 void func_reset(void *par) { uint8_t status = REBOOT_START; uart-send_string("Start activate modem"); while (1) { switch(status_reboot) { case REBOOT_START: GPIOB->BSRR=GPIO_Pin_1; status = REBOOT_UP; tn_task_sleep(3000); break; case REBOOT_UP: GPIOB->BRR=GPIO_Pin_1; status = REBOOT_END; tn_task_sleep(1000); break; case REBOOT_END: send_cmd_device(POWER_UP); tn_task_exit(TN_EXIT_TASK); break; } } } Т.е. создаю задачу без ее запуска при создании, а потом уже в коде программы, там где нужно запустить/перезагрузить девайс я запускаю эту задачу tn_task_activate(&task_reset); Но на сколько это оправданно? Заранее благодарен за ответ.