Jump to content

    

Lwip: netconn TCP app

В проекте используется LwIP + FreeRTOS. Поднят TCP сервер на Netconn API.

Необходимо данные из входящего соединения отправлять в последовательный порт, и в обратную сторону.

Проблема в том, что реализация TCP соединения подразумевает блокирующую функцию обработки принятых данных

 

            while (netconn_recv(ntcnn232->newc, &buf) == ERR_OK)
            {

 

То есть пока не принял данные по TCP не могу отправить принятые данные по последовательному порту.

 

Как быть в этой ситуации?

 

Пока реализовано так: 2 задачи ОС:

1) сидит в блокирующей функции и отправляет принимаемые данные в последовательный порт

2) отправляет данные, принимаемые по последовательному порту, в TCP

 

Но это создает кучу проблем, например работа этих задач может "сломать" соединение.

 

Есть альтернативы как это можно реализовать?

Share this post


Link to post
Share on other sites
В проекте используется LwIP + FreeRTOS....То есть пока не принял данные по TCP не могу отправить принятые данные по последовательному порту. ...Есть альтернативы как это можно реализовать?

 

Насколько я понимаешь - LwIP реализован согласно соответствующих RFC, в том числе и со стороны юзанья.

Насколько помнишь - стандартный протокол должен обеспечивать как блокирующий так и не блокирующий режим работы.

 

это раз.

ну и второе - тот вариант что у Вас уже реализован(проглядел когда начинал писал)...

Не совсем понятен Ваш термин "сломать" соединение. Если в логике нет проблем, то ищите в коде..

 

как то так

(круглый)

Edited by kolobok0

Share this post


Link to post
Share on other sites

Можно включить в 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 реализованы сокеты, там аналогично сделано.

Share this post


Link to post
Share on other sites

А можно, и я свой вопросик втисну?

Первый раз пытаюсь использовать 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.

 

Как это можно сделать?

 

С уважением, Ефанов Сергей

Share this post


Link to post
Share on other sites
Как это можно сделать?

 

С уважением, Ефанов Сергей

А в чем проблема вызвать из другой задачи netconn_write? Функции netconn сделаны для работы в многозадачной среде.

Share this post


Link to post
Share on other sites
А в чем проблема вызвать из другой задачи 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).

Очевидно, я неправильно это делаю.

 

С уважением, Ефанов Сергей.

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

ошибся. приношу извинения...

Edited by kolobok0

Share this post


Link to post
Share on other sites
Не совсем понятен Ваш термин "сломать" соединение

(круглый)

Если во время выполнения функции netconn_recv выполнится netconn_write в параллельной задаче, соединение ломается.

можно было мьютексом асинхронизировать доступ к соединению, но netconn_recv вызывается циклом while (netconn_recv() == ERR_OK), поэтому перед и после выполнения не получится зажать мьютекс

Share this post


Link to post
Share on other sites
Если во время выполнения функции 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.

Share this post


Link to post
Share on other sites
И есть вариант вообще без надобности не блокировать задачу вызовом netconn_recv,

для этого при создании соединение использовать netconn_new_with_proto_and_callback и назначить callback,

в котором допустим взводить семафор. Сколько раз был вызван callback c NETCONN_EVT_RCVPLUS, столько раз

и надо вызвать netconn_recv. Посмотрите как в LWIP реализованы сокеты, там аналогично сделано.

Такой вариант бы хорошо подошел. можете привести пример кода, особенно интересует часть с закрытием соединения (мы сервер, подключен клиент, клиент закрывает соединение - в калбэке NETCONN_EVT_RCVPLUS 0 длинны) ??? у меня с этим какой то затык.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this