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. Цитата(controller_m30 @ Mar 24 2015, 20:53) А, вот какой обработчик. Это совсем другое дело! А то я так понял, что обработчик будет ждать только один ответ (заданный из основной программы), и пропускать все остальные. Могу в качестве посильной помощи выложить скрин с логического анализатора, как выдаётся из модема ответ "+CREG: 0,1","OK". То, что отмечено как "\r" и "\n" - это непечатные символы <cr> (0x0d) и <lf>(0x0a) соответственно. Как видно, это сплошной поток данных. Сможет ли Ваш обработчик разделить строку на "+CREG: 0,1" и "OK"? Как обработчик отделяет сообщения друг от друга? По тайм-ауту, или по <cr>, <lf> вначале и конце сообщения? По концу строки <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. Цитата(Lotor @ Mar 24 2015, 19:14) А как Вы будете обрабатывать unsolicited messages? В функции обработчике буфера от модема (в прерывании) до того как отправить буфер очередью проверяются такие данные от модема: 1. OK - выставляется флаг, который ожидает задача после отправки команды модему, если за N-ое кол-во мсек после отправки команды флаг не выставился - значит модем не ответил и дальше уже по обстоятельству (перазагрузка модема и т.п) 2. > - готов отправить данные серверу. 3. SEND OK - аналогично с флагом ОК только этот флаг ожидается после отправки данных "на сервер". 4. +RECEIVE: - получили данные "с сервера" и записываем приходящие данные в прерывании не в буфер модема, а в буфер входящих сообщений. И уже если эти 4 строчки не совпали смотрим отправлять ли очередь или нет, опять же в зависимости от того на какую команду ответ мы ждем. К сообщению приложил модуль, который на текущий момент у меня получился, пока еще без подключения к серверу и без полноценного разбора ответов.
  7. Ну кроме работы с модемом нужно повешать еще и другие задачи, поэтому и использую операционку: один таск под модем, второй под работу с ГПС и т.д. каждый таск под свое устройство. Цитатаа в случае с GSM-модемом, пауза между отправкой команды и получением ответа может составлять секунды Не совсем понял, а почему может составлять секунды? Модем висит на одном ЮАРТе, другие девайсы на другом и т.п под каждый юарт свой обработчик прерывания.
  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. TNKernel & STM32

    Да, действительно очень и очень глупая ошибка...конечно же проще все делать в одном таске, чем городить новые. Спасибо за разъяснение. Но появился следующий вопрос. После того как мы подали на некоторое время сигнал на ножку девайса нам нужно его настроить и если он не отвечает то его снова перезагрузить подачей сигнала на ножку. Как я себе представляю данный код в таком случае: Код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); Но на сколько это оправданно? Заранее благодарен за ответ.