скрытое меню

LWIP NETCONN (c FreeRTOS)

Итак так как проект LWIP HTTP SERVER RAW c FreeRTOS как-то работает , но виснет периодически (как и полагается).

Причины этому скорее всего связаны с тем , что FreeRTOS работает с памятью через свой так сказать диспетчер памяти, а LWIP работает через свой диспетчер с памятью. В общем вопросов много, надо разбираться.

Вопрос (я бы сказал) остается столько сколько не изученного кода LWIP остается .

LWIP предлагает другой вариант интеграции во FreeRTOS - через NETCONN и использование mailbox очередей для реализации потокобезопастности.

Хочу сказать "спасибо" сложившейся ситуации с реализацией NETCONN ибо не было до этого необходимости вникнуть в управление памятью кучи досконально.

Речь вообще говоря о malloc ,memp_malloc и pvPortMalloc . Все они встречаются в примерах с NETCONN и как-то не работают они вместе никак.

[sys_arch.c]

Не надо надеятся , что код в LWIP идеален. Особенно в более поздних версиях, где уже с трудом можно разобраться кто из последователей Адама Дункельса где что дописывал (дорабатывал).
Ниже пример , который меня откровенно разочаровал.

err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
	int mboxsize = size;
	LWIP_ASSERT("mbox != NULL", mbox != NULL);
	LWIP_ASSERT("size >= 0", size >= 0);

	if (size == 0)
	{
		mboxsize = 1024;
	}
	mbox->head = mbox->tail = 0;
	mbox->sem = mbox; /* just point to something for sys_mbox_valid() */
	mbox->q_mem = (void**)malloc(sizeof(void*)*mboxsize);
	//mbox->q_mem = (void**)pvPortMalloc(sizeof(void*)*mboxsize);
	mbox->size = mboxsize;
	mbox->used = 0;

	memset(mbox->q_mem, 0, sizeof(void*)*mboxsize);
	return ERR_OK;
}

Почему здесь используется malloc? - в потоках FreeRTOS это не будет работать от слова совсем, даже если сделать потоки статическими (есть такая опция). И у нас malloc благополучно возвращает 0, то есть память не выделяется. Вот стек вызываемых функций под NETCONN для создания почтового ящика LWIP:


	sys_mbox_new() at sys_arch.c:217 0x801a8e2	
	tcpip_init() at tcpip.c:607 0x801a432	
	StartDefaultTask() at http_server.c:115 0x80252b2	
	uxListRemove() at list.c:227 0x801379c	

Дальнейшее изучение кода lwip 2.1.2 приводит к разочарованию. Я даже начала обращать внимание кто писал то или иной файл в заголовке.

Наибольшее удручение вызвал файл sys_arch.c помеченный как Copyright (c) 2017 Simon Goldschmidt .

Обратите внимание на the_waiting_fn , функцию которую вы должны якобы определить сами. По умолчанию ее нет, хотя из кода она вызывается. Но это мелочи.

Весь огород в sys_arch.c вокруг организации ожидания чего-то при получении из ehternet канала пакетов TCP (какой-то самописный семафор) . При чем у меня задача интегрировать lwip в FreeRTOS. Зачем мне какие-то еще выдуманные семафоры.

Вот злосчастная функция ожидания скидывания сефамора (не могу ее не привести):

u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
	printf("sys_arch_sem_wait\n");

	u32_t ret = 0;
	LWIP_ASSERT("sem != NULL", sem != NULL);
	LWIP_ASSERT("*sem > 0", *sem > 0);

	if (*sem == 1)
	{
		/* need to wait */
		if(!timeout)
		{
			/* wait infinite */
			LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
			// тут надо не забыть реализовать фукцию the_waiting_fn 
			// как она при этом нормально указанная ниже (но не реализованная нигде) 
                        // компилируется нормально я не понял...

			do
			{
				int expectSomething = the_waiting_fn(sem, NULL);
				LWIP_ASSERT("*sem > 0", *sem > 0);
				LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
				ret++;
				if (ret == SYS_ARCH_TIMEOUT)
				{
					ret--;
				}
			} while(*sem == 1);
		}
		else
		{
			if (the_waiting_fn)
			{
				int expectSomething = the_waiting_fn(sem, NULL);
				LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
			}

			LWIP_ASSERT("*sem > 0", *sem > 0);
			if (*sem == 1)
			{
				return SYS_ARCH_TIMEOUT;
			}
			ret = 1;
		}
	}
	LWIP_ASSERT("*sem > 0", *sem > 0);
	(*sem)--;
	LWIP_ASSERT("*sem > 0", *sem > 0);
	/* return the time we waited for the sem */
	return ret;
}

Если в функцию передавать вторым параметром (timeout) 0, то функция крутится в бесконечном цикле. И выход возможен только , если кто-то где-то установит *sem !=1.
А теперь смотрим netconn_new / netconn_new_with_proto_and_callback / netconn_apimsg / tcpip_send_msg_wait_sem / sys_arch_sem_wait (sem, 0);
То есть netconn_new крутится в бесконечном цикле while(* sem == 1) и ждет чего-то.

В двух словах : при отладке в цепочке netconn_new / netconn_bind / netconn_accept все зависает уже на netconn_new .

Я очень хотел бы ошибаться, но складывается впечатление , что NETCONN не надо использовать от слова вообще.

Есть идея взять старый добрый RAW и использовать Static FreeRTOS вариант.