|
Lwip: netconn TCP app |
|
|
|
Oct 27 2017, 06:09
|

Местный
  
Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978

|
В проекте используется LwIP + FreeRTOS. Поднят TCP сервер на Netconn API. Необходимо данные из входящего соединения отправлять в последовательный порт, и в обратную сторону. Проблема в том, что реализация TCP соединения подразумевает блокирующую функцию обработки принятых данных Код while (netconn_recv(ntcnn232->newc, &buf) == ERR_OK) { То есть пока не принял данные по TCP не могу отправить принятые данные по последовательному порту. Как быть в этой ситуации? Пока реализовано так: 2 задачи ОС: 1) сидит в блокирующей функции и отправляет принимаемые данные в последовательный порт 2) отправляет данные, принимаемые по последовательному порту, в TCP Но это создает кучу проблем, например работа этих задач может "сломать" соединение. Есть альтернативы как это можно реализовать?
|
|
|
|
|
 |
Ответов
(1 - 10)
|
Oct 27 2017, 16:07
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(k000858 @ Oct 27 2017, 09:09)  В проекте используется LwIP + FreeRTOS....То есть пока не принял данные по TCP не могу отправить принятые данные по последовательному порту. ...Есть альтернативы как это можно реализовать? Насколько я понимаешь - LwIP реализован согласно соответствующих RFC, в том числе и со стороны юзанья. Насколько помнишь - стандартный протокол должен обеспечивать как блокирующий так и не блокирующий режим работы. это раз. ну и второе - тот вариант что у Вас уже реализован(проглядел когда начинал писал)... Не совсем понятен Ваш термин "сломать" соединение. Если в логике нет проблем, то ищите в коде.. как то так (круглый)
Сообщение отредактировал kolobok0 - Oct 27 2017, 16:09
|
|
|
|
|
Oct 28 2017, 09:07
|
Участник

Группа: Участник
Сообщений: 36
Регистрация: 18-10-06
Из: Москва
Пользователь №: 21 459

|
Можно включить в LWIP таймауты, тогда из функции netconn_recv будет выходить через указанное время, даже если ничего не принято. #define LWIP_SO_RCVTIMEO 1 // accept, receive #define LWIP_SO_SNDTIMEO 1 // send
Если надо прервать ожидание netconn_recv из другой задачи, во FreeRTOS можно включить опцию #define INCLUDE_xTaskAbortDelay 1 и вызовом xTaskAbortDelay(hTask) разблокировать задачу.
И насколько помню в lwip/port/sys_arch.c ожидание из очереди без таймаута там зачем-то обернуто в цикл, хотя документация на FreeRTOS говорить что вызов xQueueReceive с portMAX_DELAY бесконечный. Так что если не убрать цикл, задача опять заблокируется.
И есть вариант вообще без надобности не блокировать задачу вызовом netconn_recv, для этого при создании соединение использовать netconn_new_with_proto_and_callback и назначить callback, в котором допустим взводить семафор. Сколько раз был вызван callback c NETCONN_EVT_RCVPLUS, столько раз и надо вызвать netconn_recv. Посмотрите как в LWIP реализованы сокеты, там аналогично сделано.
|
|
|
|
|
Oct 28 2017, 10:15
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 15-02-05
Пользователь №: 2 663

|
А можно, и я свой вопросик втисну? Первый раз пытаюсь использовать Lwip, вот какую проблемку пытаюсь решить: Попробовал пример с эхо - всё хорошо работает: Код while (1) { accept_err = netconn_accept(conn, &newconn); if (accept_err == ERR_OK) { while ((netconn_recv(newconn, &buf)) == ERR_OK) { do { netbuf_data(buf, &data, &len); netconn_write(newconn, data, len, NETCONN_COPY); } while (netbuf_next(buf) >= 0); netbuf_delete(buf); } netconn_close(newconn); netconn_delete(newconn); } } ( этот цикл крутится в отдельной задаче FreeRTOS) Теперь мне нужно отправить пакет через стек в в произвольный момент времени, то есть - в то время, когда выполняется netconn_recv. Как это можно сделать? С уважением, Ефанов Сергей
|
|
|
|
|
Oct 28 2017, 11:08
|
Участник

Группа: Участник
Сообщений: 36
Регистрация: 18-10-06
Из: Москва
Пользователь №: 21 459

|
Цитата Как это можно сделать?
С уважением, Ефанов Сергей А в чем проблема вызвать из другой задачи netconn_write? Функции netconn сделаны для работы в многозадачной среде.
|
|
|
|
|
Oct 28 2017, 11:59
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 15-02-05
Пользователь №: 2 663

|
Цитата(DeNi @ Oct 28 2017, 14:08)  А в чем проблема вызвать из другой задачи netconn_write? Функции netconn сделаны для работы в многозадачной среде. Не знаю ( ума не хватает). Я пытался. Неизменно получаю ошибку. Делал вот так: Код void transfer_ip( char *rep, uint16_t len ) { err = netconn_write(newconn, (const unsigned char*)rep, len, NETCONN_COPY); if( err == ERR_OK ) { printf("\rSend OK %d \r",len); } else { printf("\rSend BAD:%d\r", (int)err ); } } Ошибку всегда возвращает -6 (ERR_VAL). Очевидно, я неправильно это делаю. С уважением, Ефанов Сергей.
|
|
|
|
|
Oct 28 2017, 14:17
|
Участник

Группа: Участник
Сообщений: 36
Регистрация: 18-10-06
Из: Москва
Пользователь №: 21 459

|
Можно пройти отладчиком во внутрь функции и посмотреть где возникает ошибка и возвращается ERR_VAL.
|
|
|
|
|
Oct 31 2017, 03:31
|

Местный
  
Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978

|
Цитата(kolobok0 @ Oct 27 2017, 20:07)  Не совсем понятен Ваш термин "сломать" соединение (круглый) Если во время выполнения функции netconn_recv выполнится netconn_write в параллельной задаче, соединение ломается. можно было мьютексом асинхронизировать доступ к соединению, но netconn_recv вызывается циклом while (netconn_recv() == ERR_OK), поэтому перед и после выполнения не получится зажать мьютекс
|
|
|
|
|
Oct 31 2017, 09:08
|
Частый гость
 
Группа: Свой
Сообщений: 97
Регистрация: 27-07-10
Из: харьков
Пользователь №: 58 632

|
Цитата Если во время выполнения функции netconn_recv выполнится netconn_write в параллельной задаче, соединение ломается. Все должно работать, у меня работает, что то у вас или настроено не так или что не то с файлом sys_arch.c. Цитата Если надо прервать ожидание netconn_recv из другой задачи, во FreeRTOS можно включить опцию #define INCLUDE_xTaskAbortDelay 1 и вызовом xTaskAbortDelay(hTask) разблокировать задачу. Это самый глупый совет никогда так не делайте !!!!, в лучшем случае получите утечку памяти, так как ресурсы занятые стеком никто не освободит, в худшем вылет или зависание стека. Если нужно не зависать в netconn_recv: Настроить и включить для соединения TCP_KEEEP_ALIVE это основное. Далее в зависимости от преследуемых целей можно использовать 2 варианта. 1) Установить таймаут на прием и соответсвенно его обрабатывать. 2) Если нужно выйти по команде с другой задачи нужно воспользоваться функцией netconn_shutdown, с параметром закрытия RX, после этой команды цикл netconn_recv прервется с ошибкой ERR_CLS, но соединение по прежнему будет активно только на передачу, этой же командой можно прервать и передачу, если этой функции поставить rx = 1 и tx = 1 она закроет соединение как команда netconn_close.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|