|
|
|
STM32+LWIP+PPP проблемы с аутентификацией |
|
|
|
Jul 13 2018, 09:53
|
Группа: Участник
Сообщений: 5
Регистрация: 12-07-18
Из: Новосибирск
Пользователь №: 105 858
|
Доброго времени суток! Имеется sim-карта со статическим IP и модем SIM800C, который через UART соединен с STM32F0. Пытаюсь обойтись без встроенного в модем стека, чтобы обеспечить себе беззаботную жизнь, когда придет нужда менять модем, для этого в качестве внешнего стека юзаю lwip. Видел на хабре статью про это дело, которая, собственно, и являлась отправной точкой, было решено повторить подвиг, но в версии lwip 2.0.3, которой я пользуюсь, ppp немного изменился и это все хорошо описано в документации (ppp.txt, прикреплю его ниже). Следуя инструкциям из упомянутого файла, реализовал все функции, которые надо реализовать и все заработало.... почти. Когда модем начал общаться с контроллером, дальше фазы LCP дело не зашло. Как я понял из документа (ppp_connect.pdf), который оказался у меня уже-и-не-помню-откуда, после конфигурирования параметров соединения в фазе LCP контроллер должен посылать в модем пакет с заголовком PAP (C0 23), но он почему-то этого не делает... Он вообще больше ничего не делает. Я пытался проследить в отладчике весь путь запроса, что приходит от модема, но это только больше меня запутало. Собственно, прием данных у меня организован через прерывание. После ввода AT-команды " ATD*99***1#" и получения ответа " CONNECT", устанавливается флаг " ppp_enable" и при приходе байта он кладется в очередь ` xQueue_PPP_Package`. Код void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { uint8_t u8; if(huart == &huart1) {
if (ppp_enable == true) { portBASE_TYPE xHigherPriorityTaskWoken_PPP_Rx;
u8 = Sim800.UsartRxTemp;
xHigherPriorityTaskWoken_PPP_Rx = pdFALSE; xQueueSendFromISR(xQueue_PPP_Package, &u8, &xHigherPriorityTaskWoken_PPP_Rx); } else { /*Reception of AT commands*/ }
HAL_UART_Receive_IT(&huart1,&Sim800.UsartRxTemp,1); } } В задаче ` StartLwIPTask` в бесконечном цикле проверяется эта очередь и при появлении элементов, записывает их в массив ` PPPx.Data` и при фиксации второго HDLC-заголовка (0x7E), отправляет данные в lwip функцией ` pppos_input`. P.S. Переменная `PPPx.Last_Index` это размер пришедшего ppp-пакета. Код void StartLwIPTask(void const * argument) { /* USER CODE BEGIN StartLwIPTask */ /*Создаем очередь*/ xQueue_Sim800_Package = xQueueCreate(128, sizeof(uint8_t)); xQueue_PPP_Package = xQueueCreate(128, sizeof(uint8_t)); uint8_t u8=0; volatile int setup = 0;
tcpip_init( NULL, NULL ); /*Инициализация стека tcp/ip*/
/*Create a new PPPoS interface*/ ppp = pppos_create(&ppp_netif, output_cb, status_cb, 0);
// /* Auth configuration, this is pretty self-explanatory */ ppp_set_auth(ppp, PPPAUTHTYPE_PAP, "beeline", "beeline");
/* Require peer to authenticate */ ppp_set_auth_required(ppp, 1);
/*Only for PPPoS, the PPP session should be up and waiting for input.*/ ppp_set_silent(ppp, 1);
/* * Initiate PPP listener (i.e. wait for an incoming connection), can only * be called if PPP session is in the dead state (i.e. disconnected). */ ppp_listen(ppp);
/* Infinite loop */ for(;;) { if (sim800_init() == S_RESET) /*Настройка модуля Sim800*/ continue;
for (;;) {
if (pdPASS == xQueueReceive(xQueue_PPP_Package, &u8, 100/portTICK_RATE_MS)) { if (u8 == 0x7E) t++;
PPPx.Data[PPPx.Last_Index++] = u8;
if (t==2) { PPPx.Last_Index--; pppos_input(ppp, PPPx.Data, PPPx.Last_Index); t=0; memset(&PPPx, 0, sizeof(PPPx)); } } } } /* USER CODE END StartLwIPTask */ } Как я писал выше, все идет хорошо, пока идет фаза LCP, но после подтверждения контроллером запроса опций, наступает тишина. Интуиция мне говорит, что у меня какой-то косяк в настройках ppp в lwip, но неопытность в этом вопросе мешает понять, где именно и что именно я делаю не так В интернете мне удалось найти довольно мало исчерпывающей информации и примеров по связке stm32+lwip+ppp (не исключаю, что это просто я искать не умею, если поделитесь ссылками на полезные ресурсы, буду очень признателен), если кто-нибудь занимался подобным или сталкивался с похожей проблемой, буду ноги целовать очень благодарен за помощь и за пинки в нужном направлении.
|
|
|
|
|
Jul 13 2018, 11:47
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (Klapatun @ Jul 13 2018, 12:53) и при фиксации второго HDLC-заголовка (0x7E), отправляет данные в lwip функцией `pppos_input`. Это некорректно. Дело в том, что первый заголовок передается только если была большая пауза после предыдущего пакета. А на стадии установки соединения паузы маленькие и часть пакетов идет без первого заголовка. Посмотрите мое сообщение в соседней ветке, там я приводил лог установки соединения. В виденных мной реализациях (и в моей тоже) пакет передается в стек при наступлении паузы в 1-2 мс. Но ваша идея мне в целом нравится - если приняли 0x7E и в буфере больше одного байта - можно смело передавать пакет. Пожалуй, сделаю и у себя так.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 13 2018, 12:42
|
Частый гость
Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945
|
У меня тоже сделано по второму 0x7E. Не замечал пакетов без заголовка. Может ppp_set_auth_required(ppp, 1); ppp_set_silent(ppp, 1); ppp_listen(ppp); лишние? Код ppp = pppos_create(&ppp_netif, output_cb, status_cb, NULL); ppp_set_auth(ppp, PPPAUTHTYPE_PAP,user,pass); pppapi_set_default(ppp); ppp_connect(ppp, 1); while ((!PPPconnected) && (--timeout>0) && (PPPerror == PPPERR_NONE)) { osDelay(1000); }
if (timeout>0 && (PPPerror == PPPERR_NONE)) { //conected; } В status_cb: Цитата case PPPERR_NONE: { PPPconnected = 1; }
|
|
|
|
|
Jul 13 2018, 13:03
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (alex2103 @ Jul 13 2018, 15:42) У меня тоже сделано по второму 0x7E. Не замечал пакетов без заголовка. Видишь суслика? А он есть! Выше привел лог, в котром такие пакеты есть. Впрочем, я не настаиваю.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 18 2018, 08:28
|
Группа: Участник
Сообщений: 5
Регистрация: 12-07-18
Из: Новосибирск
Пользователь №: 105 858
|
Цитата(alex2103 @ Jul 13 2018, 19:42) Может ppp_set_auth_required(ppp, 1); ppp_set_silent(ppp, 1); ppp_listen(ppp); лишние? Код ppp = pppos_create(&ppp_netif, output_cb, status_cb, NULL); ppp_set_auth(ppp, PPPAUTHTYPE_PAP,user,pass); pppapi_set_default(ppp); ppp_connect(ppp, 1); while ((!PPPconnected) && (--timeout>0) && (PPPerror == PPPERR_NONE)) { osDelay(1000); }
if (timeout>0 && (PPPerror == PPPERR_NONE)) { //conected; } Попробовал ваш вариант, но у меня на функции " pppapi_set_default(ppp);" в " tcpip_api_call" застревает программа при разблокировки ядра TCPIP в " UNLOCK_TCPIP_CORE();". Согласно документации достаточно только включить #include "pppapi.h" и поставить LWIP_PPP_API 1, что я и сделал, но появившаяся проблема вводит меня в ступор и понять ее причину я не могу. Может, я как-то совсем не так настраиваю lwip и причину надо искать где-нибудь в заголовочных файлах? Так же заметил, что status_cb в принципе не вызывается. Нашел подобную проблему на stack overflow, но там не было ответов на этот вопрос ответа не было.
|
|
|
|
|
Jul 19 2018, 08:11
|
Участник
Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038
|
День добрый У меня сейчас в приборе как раз работает связка SIM800C+STM32F405+LWIP+FreeRTOS. Версия LWIP 2.0.0, но в ней вроде как нет глобальных отличий от 2.0.3 в плате PPPOS. По сравнению с вашим кодом: 1) Для передачи данных в LWIP я использую ф-цию pppos_input_tcpip() 2) После того, как я получил сообщение CONNECT от модем, я перестаю сам анализировать данные, и все данные от модема полностью передаю в LWIP на обработку Порядок включения и работы с LWIP и PPP у меня примерно следующий: Код sys_sem_new(&sem, 0); tcpip_init(TCPIPDoneCB, &sem); sys_sem_wait(sem); sys_sem_free(sem);
pppapi_pppos_create(...,PPPOSOutputCB, PPPOSStatusCB, ...)
ppp_set_usepeerdns(ctx->network.ppp, 1); // только если DNS нужен
ppp_set_auth(...., PPPAUTHTYPE_CHAP, user, password);
pppapi_set_default();
pppapi_connect();
static u32_t PPPOSOutputCB(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(ctx);
// шлем данные в UART как есть, без какого-либо разбора
return sio_write(0, data, len); }
static void PPPOSStatusCB(ppp_pcb *pcb, int err_code, void *ctx) { ...
switch (err_code) { case PPPERR_NONE: { // здесь уже есть IP у прибора } // обработка других кодов } }
// есть отдельная задача, в которой вызывается следующая функция, которая // в свою очередь забирает данные с UART и прямиком без какого-либо разбора отправляет // их в LWIP.
void GSMrocessData(struct ModemContext *ctx) { // gsmRawRxBuf - буфер для данных // GSM_RAW_RX_BUF_SIZE - максимальный размер буфера (должен быть около 1600 байт, у меня 2048) // 10 - таймут на ожидания данных в мс. // rb - количество данных полученных от модема
int rb = sio_read(gsmRawRxBuf, GSM_RAW_RX_BUF_SIZE, 10); if (rb) { pppos_input_tcpip(ppp, (u8_t *)gsmRawRxBuf, rb); } } Также не стоит забывать о настроке самой LWIP (часть для PPP) Код // PPP
#define PPP_SUPPORT 1 #define PPPOS_SUPPORT 1 #define PPP_IPV4_SUPPORT 1 #define PAP_SUPPORT 1 #define CHAP_SUPPORT 1
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|