sergey sva
Jan 29 2014, 08:50
Не знаю пока всех тонкостей по этой теме, проконсультируйте пожалуйста.
Как лучше использовать stek lwip с Rtos или без какие за и против, для примера контроллер lpc4337?
Я использовал без RTOS - так исторически сложилось из-за дефицита ОЗУ, а теперь добавление RTOS не сулит ничего очень уж полезного.
Плюсы RTOS обычные: код для длительных процессов может написан линейно. Минусы - расход ОЗУ на стеки задач, усложнение в части синхронизации между потоками.
Соответственно, без RTOS прикладной код сложнее, так как он должен выполняться по схеме Super Loop. То есть длительные процессы разбиваются на куски при помощи конечных автоматов, protothreads и проч. Плюсы: экономия памяти, синхронизация не требуется вообще (за исключением синхронизации с обработчиками прерываний).
sergey sva
Jan 29 2014, 11:53
Понятно, какие еще есть открытые , на данный момент нашел два lwip и fnet и uIP. Второй кто нибудь использовал ?
Еще вопрос по стеку Lwip в функции low_level_output в цикле заполняется dma и после отправляется фрейм.
Если сразу отправлять, насколько это будет правильно?
Код
for(q = p; q != NULL; q = q->next) {
заполняем dma(q->payload, q->len);
запрос на передачу()
}
Цитата(sergey sva @ Jan 29 2014, 15:53)

Еще вопрос по стеку Lwip в функции low_level_output в цикле заполняется dma и после отправляется фрейм.
Если сразу отправлять, насколько это будет правильно?
Сразу отправлять - это zero-copy transmit что ли? Я, собственно, так и делаю. Естественно, есть ограничения: данные для отправки не могут лежать в флеше, т.к. STM32 Ethernet DMA не имеет к ней доступа. Кроме того, я жду окончания отправки пакета прямо там же, так как в противном случае есть вероятность того, что буфер будет затёрт до того, как пакет будет отправлен.
Чтобы не быть голословным, вот код:
CODE
err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
int i;
uint32_t mask;
if (!netif_is_link_up(netif))
{
return ERR_OK;
}
while ((ETH_DMASR & 0x00700000) != 0x00600000)
{
/* wait until Tx DMA is suspended */
}
mask = (1u << 31) /* OWN bit */
| (1 << 28); /* first segment */
i = -1;
for (;;)
{
i++;
if (i == TX_RING_SIZE)
{
/* not enough TX descriptors */
return ERR_MEM;
}
tx_desc[i].len[0] = p->len;
tx_desc[i].ptr[0] = p->payload;
p = p->next;
if (p)
{
tx_desc[i].len[1] = p->len;
tx_desc[i].ptr[1] = p->payload;
p = p->next;
if (p)
{
tx_desc[i].status = mask;
mask = (1u << 31); /* OWN bit */
}
else
{
break;
}
}
else
{
tx_desc[i].len[1] = 0;
break;
}
}
mask |= (1 << 21) /* end of ring */
| (1 << 29); /* last segment */
tx_desc[i].status = mask;
REGBIT(ETH_DMASR, 10) = 1; /* reset ETS flag in status register */
ETH_DMATPDR = 0; /* start transmission */
while (REGBIT(ETH_DMASR, 10) == 0)
{
/* wait for data to be copied into Tx FIFO */
}
return ERR_OK;
}
sergey sva
Jan 29 2014, 13:21
Да. Смотрел пример в нем реализовано так
Код
for(q = p; q != NULL; q = q->next) {
заполняем dma(q->payload, q->len);
//вначале заполняется буфер, а после когда происходит выход из цикла ставиться бит старта передачи.А если сделать передачу в этом цикле быстрее будет работать ?
}
запрос на передачу()
kolobok0
Jan 29 2014, 16:17
Цитата(sergey sva @ Jan 29 2014, 15:53)

.. по стеку Lwip..Если сразу отправлять, насколько это будет правильно?..
можно делать следующе:
1) завести обработчик прерывания на приём и передачу.
2) выкинуть нафик все мэмкопи. подумайте - у вас DMA и ему пофигу откуда кушать ваши данные!!! То же самое приёмник.
3) Если будете юзать ось - то там (благодаря обработчику) сокращается одна нитка.
вообще то стэк основан на полинге а не на прерываниях - отсюда тормоза. Короче говоря надо доработать напильником
Golikov A.
Jan 29 2014, 17:29
Цитата(scifi @ Jan 29 2014, 16:45)

Кроме того, я жду окончания отправки пакета прямо там же, так как в противном случае есть вероятность того, что буфер будет затёрт до того, как пакет будет отправлен.
Простите, я может не так понял. Вы указываете ДМА где лежат данные, а потом ждете когда он их все перепихает наружу? Какой тогда смысл ДМА, если в этот момент вы не можете делать ничего другого?
_Артём_
Jan 29 2014, 18:07
Цитата(Golikov A. @ Jan 29 2014, 19:29)

Какой тогда смысл ДМА, если в этот момент вы не можете делать ничего другого?
Видимо ДМА справляется с этой задачей быстрее, чем ядро...
Цитата(Golikov A. @ Jan 29 2014, 19:29)

вы не можете делать ничего другого?
Могут выполнятся прерывания, и если шина свободна - ДМА отправит данные на передечу, а ядро нет.
Правда выигрыш там накакой наверное будет...
Golikov A.
Jan 29 2014, 18:32
Мне кажется что memcpy быстрее скопирует данные из памяти в память,
чем дма из памяти через мак в езернет.
потому выделить память, кинуть в нее данные, и отдать их на выдачу через ДМА по времени будет не дольше, а часто и быстрее чем в функции ждать окончания посылки. Из минусов только выделение памяти, зато можно много чего другого сделать, зарядить прочие ДМА пересылать данные дальше или собирать их, например....
я в чем то не прав?
еще есть вариант сделать свой кольцевой буфер, и запускать его через ДМА, в этом случае будет серьезный выигрыш.
Цитата(Golikov A. @ Jan 29 2014, 21:29)

Простите, я может не так понял. Вы указываете ДМА где лежат данные, а потом ждете когда он их все перепихает наружу? Какой тогда смысл ДМА, если в этот момент вы не можете делать ничего другого?
Смысл в том, я что я включил режим transmit store and forward, то есть DMA сразу копирует весь пакет в FIFO перед отправкой. Это происходит очень быстро (измерял), но точную цифру сейчас не помню. Альтернатива - не ждать, но тогда нужно серьёзно допиливать стек, чтобы освобождать буферы только после отправки пакета, при этом проблем возникнет больше, чем решится.
_Артём_
Jan 29 2014, 19:24
Цитата(Golikov A. @ Jan 29 2014, 20:32)

Из минусов только выделение памяти, зато можно много чего другого сделать, зарядить прочие ДМА пересылать данные дальше или собирать их, например....
я в чем то не прав?
Да всё может и так, но
scifi пишет:
Цитата
так исторически сложилось из-за дефицита ОЗУ
Не только дефицит ОЗУ, но и вообще не нужны мне рекорды скорости. Не вижу смысла неистово пилить стек, выжимая из него 100 мбит/с, и никогда эту возможность не использовать. Более того, если уж возникнет задача выжать 100 мбит/с, я сначала посмотрю на разные стеки и чипы.
sergey sva
Jan 30 2014, 14:11
struct pbuf->len указывает размер в байтах или словах ?
MALLOY2
Jan 30 2014, 15:54
В байтах
sergey sva
Jan 30 2014, 18:17
Понятно видимо гдето ошибся.
Добавили вывод в терминал при приеме и передачи пакетов, после подключения пакетов приходит много, а плата отправляет вначале 42байта и иногда по 64, попытался пинговать, узел не доступен. Может я не правильно указал функцию ввода ethernet_inpup? Подскажите на что обратить внимание?
Код
netif_add(netif_eth0, &my_ipaddr_data, &my_netmask_data, &my_gw_data, NULL,
ethernetif_init, ethernet_input);
sergey sva
Jan 30 2014, 20:27
Снял лог есть несколько ошибок, может у кого такие ошибки были. notebad++
Нажмите для просмотра прикрепленного файла
sergey sva
Jan 31 2014, 12:45
Думаю что не хочет работать из за этой ошибки tcp_slowtmr: no active pcbs вот часть кода:
Код
void
tcp_slowtmr(void)
{
struct tcp_pcb *pcb, *prev;
u16_t eff_wnd;
u8_t pcb_remove; /* flag if a PCB should be removed */
u8_t pcb_reset; /* flag if a RST should be sent when removing */
err_t err;
err = ERR_OK;
++tcp_ticks;
++tcp_timer_ctr;
tcp_slowtmr_start:
/* Steps through all of the active PCBs. */
prev = NULL;
pcb = tcp_active_pcbs;
if (pcb == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
}
while (pcb != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
Не разобрася до конца с этим стеком, предполагаю он не может найти интерфейс активный. После лов иннициализации нужно установить какойто бит?
Если нет системы не получиться использовать сокет, если правильно понял.
Golikov A.
Jan 31 2014, 13:32
no active pcbs
это не ошибка, это констатация факта что нет никаких данных в активной очереди.
вы быстрый таймер дергать не забываете?
sergey sva
Jan 31 2014, 14:01
Быстрый ,медленый таймер дергае tcptmr(), может еще что то нужно сбрасывать или устанавливать.
Код
void lwip_init_user(void) {
lwip_init();
IP4_ADDR(&my_ipaddr_data, 192, 168, 0, 17);
IP4_ADDR(&my_netmask_data, 255, 255, 255, 0);
IP4_ADDR(&my_gw_data, 0, 0, 0, 0);
netif_add(netif_eth0, &my_ipaddr_data, &my_netmask_data, &my_gw_data, NULL,
ethernetif_init,ethernet_input );//ip_input
netif_set_default(netif_eth0);
netif_set_up(netif_eth0);
}
while (1) // repeat forever
{
if (karusel < 10)
karusel++;
else
karusel = 0;
switch (karusel) {
case 1: {
curTicks = systick_counter;
// process packets that arrive in the interface
ethernetif_input(netif_eth0);
// functions that should call from times to times
if (curTicks - last_arp_time > ARP_TMR_INTERVAL) {
etharp_tmr();
last_arp_time = curTicks;
}
if (curTicks - last_tcp_time > TCP_TMR_INTERVAL) {
last_tcp_time = curTicks;
tcp_tmr();
}
break;
} //1
MALLOY2
Jan 31 2014, 14:03
Цитата
Если нет системы не получиться использовать сокет, если правильно понял.
Да.
Если у Вас пинга нету чего вы лезете к tcp_slowtmr ??? вам нужен только ARP, IP, ICMP. В изернете нельзя передавать пакеты меньшие 64 байт!!!,
многие МАС не умеют дополнять пакет если он меньше 64 байт это надо будет сделать вам самим. STM32 умеет это делать но п омоему надо где то битик установить.
P.S. Все по шагам.
1) Делаем функцию приема кадров изернет. Запускаем ее проверяем что она принимает правильно. Буфер расшифровываем в уме.
2) Делаем функцию передачи, создаем константный фрейм, засовываем его в функцию ловим ваершарком убеждаемся что все ок.
3) Прикручиваем эти функции к стеку.
4) Запускаем пинг. Смотрим ARP таблицу, если ваш МАС есть а девайс не пингается что с IP + ICMP, Если в таблице нету вашего МАСа копаем ARP.
5) Потом уже UDP + TCP
Я использую FreeRTOS + LwIP примерно так у меня выглядят функции драйвера (прием вынесен в отдельную задачу)
Прием:
Код
__task void EthernetDeamon(void *arg)
{
int32_t size;
struct pbuf *p,*q;
uint8_t* pkt;
struct netif *ethif = (struct netif *)arg;
for(;; )
{
size = HwEMAC::RecivePacket((void**)&pkt, 1000);
if ( size > 0 )
{
p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
if (p != NULL)
{
for (q = p; q != NULL; q = q->next)
{
memcpy((u8_t*)q->payload, pkt, q->len);
pkt += q->len;
}
HwEMAC::Recived();
if (tcpip_input(p,ethif) != ERR_OK) pbuf_free(p);
}
}
else
{
LINKSTATUS_t ls = HwPHY::LinkStatus(PHY_ADDR);
if ( ls == NOLINK )
{
netif_set_link_down(ethif);
HwEMAC::Stop();
}
else
{
if (!netif_is_link_up(ethif))
{
HwEMAC::Start(ls);
netif_set_link_up(ethif);
}
}
}
}
};
P.S. tcpip_input - используется если стек работает в режиме ОС (NO_SYS = 0), если без ос то фреймы нужно запихивать в ethernet_input
передача:
Цитата
err_t EthernetOutput(struct netif *ethif, struct pbuf *p)
{
uint8_t* pkt;
struct pbuf *q;
if (HwEMAC::GetSendBuffer((void**)&pkt,20) != 0 ) return ERR_IF;
for(q = p; q != NULL; q = q->next)
{
memcpy(pkt, q->payload, q->len);
pkt += q->len;
}
HwEMAC::Send(p->tot_len);
return ERR_OK;
}
sergey sva
Jan 31 2014, 17:12
Благодарю ,помогли . Ошибка была в копирование из дма. Сделал по вашему исходнику теперь пингуется (дальше буду смотреть). Исходник lwip взял с сайта
http://savannah.nongnu.org/projects/lwip/ Настройки не менял opt.h оставил по умолчанию, Но думаю нужно настроить размер буферов памяти... микроконтроллер lpc4337, памяти у него не очень много 136кб, но хотелось уложиться в 65кб 0x2000 0000 - 0x2000 ffff. dma emac 0x1000 0000 32кб. Может вам уже приходилось настраивать какие параметры убавить прибавить?
sergey sva
Feb 1 2014, 06:08
Вроде проясняется потихоньку). Сейчас между двумя вариантами, может еще какие есть лучше и быстрее.
Первый с копированием данных из pbuf и второй запись указателя в дескриптор на pbuf в dma, в первом скопировал стек продолжает работать. во втором передал указатель и ждем когда произойдет передача. Может еще есть варианты и какой из этих лучше?
Golikov A.
Feb 1 2014, 11:09
ну есть третий, сделать свой буфер, аналог PBUF, на него указатель передавать, и самому следить чтобы данные не перекрылись.
Получаем что и стэк продолжает работать, и лишнего копирования нет.
sergey sva
Feb 2 2014, 05:25
Понятно. Еще наверно будет проблема без ос, если потребуется управлять через веб интерфейс с нескольких компьютеров.
Хотя наверно можно обойтись, слушаем порт 80 как присоединился клиент его апи сохраняем, делаем что то, тут присоединился компьютер с другим айпи ему отправиться последняя страница которую смотрели последний раз,как это лучше реализовать.
С ос понятно каждому клиенту новый поток.
Цитата(sergey sva @ Feb 2 2014, 09:25)

Еще наверно будет проблема без ос, если потребуется управлять через веб интерфейс с нескольких компьютеров.
Нет такой проблемы. Непонятно, откуда вы это взяли.
sergey sva
Feb 2 2014, 05:58
Например у меня несколько страниц web подключился клиент с 192,168,0,1 пришел запрос get/index отправил ему страницу index.Второй клиент зашел по ссылке например get/data парсинг get и отправили ему data.html . Точно вроде проблемы нет )
Цитата(sergey sva @ Feb 2 2014, 09:58)

Например у меня несколько страниц web подключился клиент с 192,168,0,1 пришел запрос get/index отправил ему страницу index.Второй клиент зашел по ссылке например get/data парсинг get и отправили ему data.html . Точно вроде проблемы нет )
Скажу больше: такое будет происходить даже с одним клиентом, так как современные браузеры открывают сразу несколько соединений, чтобы побыстрее вытянуть все данные.
Варианты следующие: либо разрешать только одно соединение (совсем не комильфо), либо иметь отдельный контекст для каждого соединения (как делают все здравомыслящие люди).
Golikov A.
Feb 2 2014, 18:57
ну вообще вы описываете стандартную работу сервера. Который для каждого клиента держит свою сессию и выдает интересующие его данные.
Наличие операционки ничуть не облегчает эту задачу. Ну сделаете вы для каждого клиента свой поток, и что? Следить то за действиями клиентов все равно надо. Да и от наличия 2 потоков процессоров больше не становится, потоки по очереди обрабатываются.
Такую же последовательную обработку можно сделать и без операционки.
MALLOY2
Feb 3 2014, 07:04
Цитата
Первый с копированием данных из pbuf и второй запись указателя в дескриптор на pbuf в dma, в первом скопировал стек продолжает работать. во втором передал указатель и ждем когда произойдет передача. Может еще есть варианты и какой из этих лучше?
Вам следует хорошо изучить PBUF, в pbuf пакет может лежать не одним цельным, а кусками этот код собирает из кусков 1 целый буфер.
Код
for(q = p; q != NULL; q = q->next)
{[quote][/quote]
memcpy(pkt, q->payload, q->len);
pkt += q->len;
}
Это можно конечно исправить, установив в настройках размер PBUF максимальному размеру фрейма. Но это очень большое расточительство памяти и никак не оправдывает себя. Есть маленький плюс позволяет сделать зеро копи драйвер. Но выигрыш очень мизерный. А памяти все будет жрать немерено.
У меня сделано так. Для дма драйвера выделено 2-4 буфера на передачу размером в максимальный фрейм (1512 по моему). Есть указатель на текущий буфер. Я его беру туда копирую pbuf, запускаю передачу дма, а текущему указателю присваиваю адрес следующего буфера и так по кругу. С приемом также есть от 2 - 16 (буферов дма размером в фрейм), есть указатель на текущий. Так как я использую ОС нет необходимости для приема использовать прерывания, так как дма умеет по кругу писать в буфера. Буру текущий указатель проверяю есть ли новый фрейм если есть, копирую его в новый pbuf, этот мечу свободным передвигаю указатель на следующий. И так по кругу.
У меня stm32f107 UDP - 70 Mbit/s TCP - 52 Mbit/s (4 буфера на передачу и 4 буфера на прием).
#define PBUF_POOL_SIZE 24
#define PBUF_POOL_BUFSIZE 256
Цитата
Понятно. Еще наверно будет проблема без ос, если потребуется управлять через веб интерфейс с нескольких компьютеров.
Хотя наверно можно обойтись, слушаем порт 80 как присоединился клиент его апи сохраняем, делаем что то, тут присоединился компьютер с другим айпи ему отправиться последняя страница которую смотрели последний раз,как это лучше реализовать.
С ос понятно каждому клиенту новый поток.
Проблемы нету, это можно сделать. Но именно это меня и заставило перейти на ОС. Так под ОС это реализовывается очень просто на каждое соединение свой таск. Без ОС это столько всякого гемора. Особенно если надо передавать большие фалы устройству. Когда я это сделал без ОС я понял что у меня получилась своя собственная маленькая ос в программе и зачем это ?. Почему это так я могу рассказать но много писать. Могу сказать так что стек под ОС быстрее работает (следует понимать не скорость передачи,а больше ресурсов остается основной программе), меньше расходуется памяти, да да МЕНЬШЕ. Код становится хорошо читаемым и понимаемым, вместо громадных автоматов состояний. Ну и конечно же надо хорошо понимать много поточность, и как правильно писать под ОС и наче получите что то работающее очень плохо.
sergey sva
Feb 3 2014, 12:24
Цитата
максимальный фрейм (1512 по моему).
наверно 1536 #define PBUF_POOL_SIZE 24 * #define PBUF_POOL_BUFSIZE 256 / 4
Пока тоже так сделал сейчас немного поэкспериментирую что получится.
Как различаете соединения по портам если они все приходят на порт 80 и с одного айпи?
Цитата(sergey sva @ Feb 3 2014, 16:24)

#define PBUF_POOL_BUFSIZE 256 / 4
Во-первых, пора бы знать, что макросы пишут со скобками: (256 / 4). А во-вторых, 64 байта - это слишком мало. Буквально на днях сам на этом обжёгся. lwip ожидает, что все заголовки пакета поместятся в первый pbuf, а у некоторых пакетов TCP заголовки бывают чуть больше, чем 64 байта. Я сделал 96.
sergey sva
Feb 3 2014, 13:51
У меня вот так задается PBUF_POOL_BUFSIZE
Код
/** Calculate memory size for an aligned buffer - returns the next highest
* multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
* LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
*/
#define PBUF_POOL_SIZE 16
#define MEM_ALIGNMENT 4
#ifndef LWIP_MEM_ALIGN_SIZE
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
#endif
#define TCP_MSS 536
#define PBUF_LINK_HLEN 14
#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
В DMA у меня по 2 буфера по 1536 каждый .
Как лучше подобрать эти параметры?
Golikov A.
Feb 3 2014, 14:00
Цитата(sergey sva @ Feb 3 2014, 16:24)

Как различаете соединения по портам если они все приходят на порт 80 и с одного айпи?
Соединение может быть установлено только между двумя сокетами, и для каждой пары сокетов может существовать только одно соединение.
Сокет - это тройка параметров
1. IP
2. ПОРТ
3. Тип соединения UDP/TCP
ваша тройка параметров фиксирована
IP, ПОРТ:80, TCP
значит для создания разных соединений будут меняться тройки параметров подключаемого устройства, так как протокол и IP наверняка фиксированны, единственное что может быть изменено это - номер порта.
sergey sva
Feb 3 2014, 14:15
Может есть готовые библиотеки работы с сокетами ?
sergey sva
Feb 3 2014, 15:35
Еще один вопрос новичка по lwip, после accept как получить destination port mac ip ?
MALLOY2
Feb 3 2014, 15:46
Цитата
Буквально на днях сам на этом обжёгся. lwip ожидает ...
lwip ничего не ожидает, это ваше приложение может ожидать, можно сделать и один байт, главное что бы ваше приложение это учитывало и правильно собирало буфер.
Цитата
Как различаете соединения по портам если они все приходят на порт 80 и с одного айпи?
Как вы работаете со стеком я не знаю. Но может быть 3 варианта 1) Работа без ОС, 2) Работа с ОС через netconn интерфейс, 3) работа через сокеты (они тоже на самом деле работают через netconn просто это скрыто от пользователя что бы пользователь мог пользоваться стандартным интерфейсом сокетов)
в общем для первого варианта у вас есть функция
tcp_accept(listen_pcb, callback_accept);
которая устанавливает калбек функцию для нового соединения, у этой функции есть параметр struct tcp_pcb *pcb так вот этот pcb так вот этот pcb будет уникален для каждого соединения, следователь при записи или чтения использую эти pcb будете читать от того или другого клиента.
Для 2 и 3 случая все ток же создается уникальная структур (сокет) для каждого соединения.
Цитата(MALLOY2 @ Feb 3 2014, 19:46)

lwip ничего не ожидает, это ваше приложение может ожидать, можно сделать и один байт, главное что бы ваше приложение это учитывало и правильно собирало буфер.
Вы бы для начала заглянули в исходники lwip, вместо того чтобы нести всякую пургу.
sergey sva
Feb 3 2014, 16:08
Понятно. У меня первый вариант без ос. Вот еще какой момент для каждого соединения создаю структуру свою, в функции accept буду выделять память mem_malloc под эту структуру, а как ее найти и освободить после разрыва соединения. Где это проверять?
Golikov A.
Feb 3 2014, 17:33
почитайте викизнание по LwIP
он сам сделает структуру для вас, и даст на нее указатель, надо его сохранить.
А когда соединение закроется, структура пометиться как мертвая, и функцией которая вызывается при медленном таймере уничтожится.
вообще при работе с lwip, он хорошо следить за своей памятью, и если в процесс ручками не залезть, и ничего не напортить. И следовать стандартному алгоритму вызовов, с отметками освобождения буферов, все будет хорошо.
kolobok0
Feb 3 2014, 18:21
Цитата(scifi @ Feb 3 2014, 17:00)

...у некоторых пакетов TCP заголовки бывают чуть больше, чем 64 байта. Я сделал 96.
там ышо могут быть оп-байты... не обязательный хвост в первом сегменте после заголовка IP. Так что первый кусочек может быть больше чем 96

так что уменьшать сильно не стоит... тем более, что практически каждую сессию броузеры корректируют этими опциональными
полями (см. любой снифер трафика).
sergey sva
Feb 3 2014, 19:09
Документация только здесь
http://lwip.wikia.com/wiki/LwIP_Wiki ,может еще есть какие источники?
Как отправить много данных. В функции calback_receve когда приходит пакет делаю парсинг, нахожу что просят. И отправляю tcp_write иногда пакет больше TCP_SND_QUEUELEN. Пакет можно разбит на пакеты длиной TCP_SND_QUEUELEN, первый пакет отправлю сразу, когда и в какой функции отправлять остаток ?
Цитата(kolobok0 @ Feb 3 2014, 22:21)

там ышо могут быть оп-байты... не обязательный хвост в первом сегменте после заголовка IP. Так что первый кусочек может быть больше чем 96

Дык вроде бы размер опций ограничен 40 байтами. Так что всё нормально должно быть.
sergey sva
Feb 4 2014, 12:39
После того как сервер получает запрос Get tcp должен послать ACK ,а потом http 200 или 302 ответ.
Смотрю ваершарком запрос с пк уходит на плату приходит вывожу в терминал все правильно, но tcp ACk не отправляет может нужно еще что то запускать,или перезапустить?
Нажмите для просмотра прикрепленного файла
sergey sva
Feb 4 2014, 15:18
Собрал по примерам исходников функцию которая должна показывать страницу.
Принцип такой: как поступают данные в receive делаю парсинг и вызываю эту функцию:
Код
err_t ShowPage(void* arg,struct tcp_pcb *tpcb) {
struct userstr *us = (struct userstr*) arg;
char resp[150];
u16_t lenresp = 0;
memset(resp,0,150);
err_t err = ERR_OK;
u16_t len = us->SizePage;
lenresp = sprintf(resp, "HTTP/1.1 200 OK\r\nServer: Mutniiserver/2014-02-04\r\nContent-Type: text/html\r\nContent-Length: %i\r\nConnection: close\r\n\r\n",us->SizePage);
tcp_write(tpcb, resp, lenresp, 0);
UART_printf("send ... (%s) (%i)\n\r", resp,err);
do {
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len));
err = tcp_write(tpcb, us->PtrPageShow, len, 0);
if (err == ERR_MEM) {
if ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) {
/* no need to try smaller sizes */
len = 1;
} else {
len /= 2;
}LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed, trying less (%d bytes)\n", len));
}
} while ((err == ERR_MEM) && (len > 1));
UART_printf("post send ... (%i)\n\r",err);
if (err == ERR_OK) {
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len));
} else {
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err)));
}
us->lenght = len;
return err;
} //
Но пока не хочет работать(
Хотите написать свой веб сервер? Бросайте это гиблое дело: с вашим нынешним уровнем подготовки рано за такое браться. Тем более, что у lwip давно есть
свой.
sergey sva
Feb 4 2014, 17:50
Сейчас посмотрю. Откуда же ей взяться если буду все бросать

С помощью профи как на этом форуме все получиться.
В этом много того что мне не нужно , нужен простой по такому принципу поступил запрос отправили 200 и страницу. Так то все работает запрос приходит функции разбора запроса уже есть, проблема я что то не так или не втой последовательности делаю.
Сейчас так: как запускается callback_receive в нем разбираю запрос, и туже отправляю tcp_write. Смотрю что происходит ваиршарком запрос с пк уходит. В плату приходит, но после запроса должен быть ACK и 200 потом страница. но вместо этого ваиршарк показывает ethernet 2 вместо tcp или http. Может нужно еще что то делать в callback_send /pool/err сейчас они пустые?
sergey sva
Feb 9 2014, 09:36
Не выходит никак ничего )). В чем может быть дело, нужно отправить 10кб, пытаюсь отправить в цикле tcp_write() перед этим смотрю tcp_sndbuf(pcb); при первом проходе получаю размер 2500 этот пакет уходит а при втором проходе цикла tcp_sndbuf(pcb); возвращает 0 .
sergey sva
Feb 9 2014, 14:01
Все заработало причина была в этом флаге TCP_WRITE_FLAG_MORE.
sergey sva
Feb 10 2014, 07:46
Как ускорить процесс, сейчас в tcp_pool (foo,4) в функции foo отправляю ответ но это происходит 1 раз в 4 секунды если ответ разбит на несколько отправлений то страница может загружаться 10 секунд? Если снизить с4 до 1с то это тоже долго.
sergey sva
Feb 10 2014, 18:23
Если увеличить скорость быстрого и медленного таймера?
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.