реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> lwIP Client
Александр П.
сообщение Feb 20 2014, 13:18
Сообщение #1





Группа: Участник
Сообщений: 14
Регистрация: 25-12-13
Пользователь №: 79 787



Добрый день.
Есть связка MCU + удаленный девайс. Связаны по Ethernet. Требуется периодически посылать на удаленный девайс сообщение и принимать от него ответ.
Использую lwIP стек. Ниже приведен работающий код. В конечном итоге callback функция ReturnPg возвращает ответ удаленного девайса. Вопрос. Как реализовать периодический опрос.
main.c
CODE
//==============================================================================
static void ReturnPg(u8_t num, hc_errormsg msg, char *data, u16_t len)
{
// data - ответ удаленного устройства
}
//==============================================================================
int main(void)
{
struct ip_addr ipaddr, netmask, gw;
struct netif NetIf, *netif;
#if LWIP_DHCP
u8_t dhcp_state = DHCP_INIT;
#endif
// Disable watchdog
WDT_Disable( WDT );
#if defined (ddram)
MMU_Initialize((uint32_t *)0x30C000);
CP15_EnableMMU();
CP15_EnableIcache();
CP15_EnableDcache();
#endif
// Initialize system timing
sys_init_timing();
// Initialize lwIP modules
lwip_init();
// Initialize net interface for lwIP
gmacif_setmac((u8_t*)gMacAddress);

IP4_ADDR(&gw, gGateWay[0], gGateWay[1], gGateWay[2], gGateWay[3]);
IP4_ADDR(&ipaddr, gIpAddress[0], gIpAddress[1], gIpAddress[2], gIpAddress[3]);
IP4_ADDR(&netmask, gNetMask[0], gNetMask[1], gNetMask[2], gNetMask[3]);

netif = netif_add(&NetIf, &gw, &netmask, &ipaddr, NULL, gmacif_init, ip_input);
netif_set_default(netif);
netif_set_up(netif);

char page[] ="get_param1";

hc_open(ipaddr, page, 0, &ReturnPg);

while(1)
{
// Run periodic tasks
timers_update();
// Run polling tasks
gmacif_poll(netif);

}
}


webclient.c
CODE
#include <board.h>
#include <liblwip.h>
#include "lwip/opt.h"
#include "lwip/tcp.h"

#include <stdlib.h>
#include <string.h>
#include "webclient.h"
//==============================================================================
// Close a PCB(connection)
//==============================================================================
static void hc_clearpcb(struct tcp_pcb *pcb)
{
if(pcb != NULL)
{
// Close the TCP connection
tcp_close(pcb);
}
}
//==============================================================================
// Function that lwip calls for handling recv'd data
//==============================================================================
static err_t hc_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct hc_state *state = arg;
char * page = NULL;
struct pbuf * temp_p;
hc_errormsg errormsg = GEN_ERROR;
int i;

if((err == ERR_OK) && (p != NULL))
{
tcp_recved(pcb, p->tot_len);

// Add payload (p) to state
temp_p = p;
while(temp_p != NULL)
{
state->RecvData = realloc(state->RecvData, temp_p->len + state->Len + 1);

// CHECK 'OUT OF MEM'
if(state->RecvData == NULL)
{
// OUT OF MEMORY
(*state->ReturnPage)(state->Num, OUT_MEM, NULL, 0);
return(ERR_OK);
}

strncpy(state->RecvData + state->Len, temp_p->payload, temp_p->len);
state->RecvData[temp_p->len + state->Len] = '\0';
state->Len += temp_p->len;

temp_p = temp_p->next;
}

// Removing payloads

while(p != NULL)
{
temp_p = p->next;
pbuf_free(p);
p = temp_p;
}

}

// NULL packet == CONNECTION IS CLOSED(by remote host)
else if((err == ERR_OK) && (p == NULL))
{
// Simple code for checking 200 OK
for(i=0; i < state->Len; i++)
{
if(errormsg == GEN_ERROR)
{
// Check for 200 OK
if((*(state->RecvData+i) == '2') && (*(state->RecvData+ ++i) == '0') && (*(state->RecvData+ ++i) == '0')) errormsg = OK;
if(*(state->RecvData+i) == '\n') errormsg = NOT_FOUND;
}
else
{
// Remove headers
if((*(state->RecvData+i) == '\r') && (*(state->RecvData+ ++i) == '\n') && (*(state->RecvData+ ++i) == '\r') && (*(state->RecvData + ++i) == '\n'))
{
i++;
page = malloc(strlen(state->RecvData+i));
strcpy(page, state->RecvData+i);
break;
}
}
}

if(errormsg == OK)
{
// Put recv data to ---> p->ReturnPage
(*state->ReturnPage)(state->Num, OK, page, state->Len);
}
else
{
// 200 OK not found Return NOT_FOUND (WARNING: NOT_FOUND COULD ALSO BE 5xx SERVER ERROR, ...)
(*state->ReturnPage)(state->Num, errormsg, NULL, 0);
}

// Clear the PCB
hc_clearpcb(pcb);

// free the memory containing state
free(state->RecvData);
free(state);
}

return(ERR_OK);
}
//==============================================================================
// Function that lwip calls when there is an error
//==============================================================================
static void hc_error(void *arg, err_t err)
{
struct hc_state *state = arg;
// pcb already deallocated

// Call return function
// TO-DO: Check err_t err for out_mem, ...
(*state->ReturnPage)(state->Num, GEN_ERROR, NULL, 0);

free(state->RecvData);
//free(state->PostVars);
free(state->Page);
free(state);
}
//==============================================================================
// Function that lwip calls when the connection is idle
// Here we can kill connections that have stayed idle for too long
//==============================================================================
static err_t hc_poll(void *arg, struct tcp_pcb *pcb)
{
struct hc_state *state = arg;

state->ConnectionTimeout++;
if(state->ConnectionTimeout > 20)
{
// Close the connection
tcp_abort(pcb);

// Give err msg to callback function
// Call return function
(*state->ReturnPage)(state->Num, TIMEOUT, NULL, 0);
}

return(ERR_OK);
}
//==============================================================================
// lwip calls this function when the remote host has successfully received data (ack)
//==============================================================================
static err_t hc_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct hc_state *state = arg;

// Reset connection timeout
state->ConnectionTimeout = 0;

return(ERR_OK);
}
//==============================================================================
// lwip calls this function when the connection is established
//==============================================================================
char *str1;
char str2[100];
static err_t hc_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct hc_state *state = arg;
char * headers;

// error?
if(err != ERR_OK)
{
hc_clearpcb(pcb);

// Call return function
(*state->ReturnPage)(state->Num, GEN_ERROR, NULL, 0);

// Free wc state
free(state->RecvData);
free(state);

return(ERR_OK);
}

// Define Headers

// GET headers (without page)(+ \0) = 19
headers = malloc(19 + strlen(state->Page));
//usprintf(headers,"GET /%s HTTP/1.0\r\n\r\n", state->Page);
sprintf(headers,"GET /%s HTTP/1.0\r\n\r\n", state->Page);

// Check if we are nut running out of memory
if(headers == NULL)
{
hc_clearpcb(pcb);

// Call return function
(*state->ReturnPage)(state->Num, OUT_MEM, NULL, 0);

// Free wc state
free(state->RecvData);
free(state);

return(ERR_OK);
}

// Setup the TCP receive function
tcp_recv(pcb, hc_recv);

// Setup the TCP error function
tcp_err(pcb, hc_error);

// Setup the TCP polling function/interval //TCP_POLL IS NOT CORRECT DEFINED @ DOC!!!
tcp_poll(pcb, hc_poll, 10);

// Setup the TCP sent callback function
tcp_sent(pcb, hc_sent);

// Send data
strcpy(str2,headers);
tcp_write(pcb, headers, strlen(headers), 1);
tcp_output(pcb);

// remove headers
free(headers);
//free(state->PostVars); // postvars are send, so we don't need them anymore
free(state->Page); // page is requested, so we don't need it anymore

return(ERR_OK);
}
//==============================================================================
// Public function for request a webpage (REMOTEIP, ...
//==============================================================================
int hc_open(struct ip_addr remoteIP, char *Page, char *PostVars, void (* returnpage)(u8_t, hc_errormsg, char *, u16_t))
{
struct tcp_pcb *pcb = NULL;
struct hc_state *state;
static u8_t num = 0;
// local port
u16_t port= 4545;

// Get a place for a new webclient state in the memory
state = malloc(sizeof(struct hc_state));

// Create a new PCB (PROTOCOL CONTROL BLOCK)
pcb = tcp_new();
if(pcb == NULL || state == NULL)
{
//UARTprintf("hc_open: Not enough memory for pcb or state\n");
//Not enough memory
return 0;
}

// Define webclient state vars
num++;
state->Num = num;
state->RecvData = NULL;
state->ConnectionTimeout = 0;
state->Len = 0;
state->ReturnPage = returnpage;

// Make place for PostVars & Page
//if(PostVars != NULL) state->PostVars = malloc(strlen(PostVars) +1);
state->Page = malloc(strlen(Page) +1);

// Check for "out of memory"
if(state->Page == NULL)
{
free(state->Page);
//free(state->PostVars);
free(state);
tcp_close(pcb);
return 0;
}
// Place allocated copy data
strcpy(state->Page, Page);
//if(PostVars != NULL) strcpy(state->PostVars, PostVars);

// Bind to local IP & local port
while(tcp_bind(pcb, IP_ADDR_ANY, port) != ERR_OK)
{
// Local port in use, use port+1
port++;
}

// Use conn -> argument(s)
tcp_arg(pcb, state);

// Open connect (SEND SYN)
tcp_connect(pcb, &remoteIP, 8080, hc_connected);

return num;
}
//==============================================================================


webclient.h
CODE
#ifndef __WEBCLIENT_H
#define __WEBCLIENT_H

/* The unsigned data types */
typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned int u32_t;

// You can replace this enum for saving MEMORY (replace with define's)
typedef enum
{
OK,
OUT_MEM,
TIMEOUT,
NOT_FOUND,
GEN_ERROR
} hc_errormsg;

struct hc_state {
u8_t Num;
char *Page;
//char *PostVars;
char *RecvData;
u16_t Len;
u8_t ConnectionTimeout;
void (* ReturnPage)(u8_t num, hc_errormsg, char *data, u16_t len);
};

// Public function
int hc_open(struct ip_addr, char *, char *, void (*)(u8_t, hc_errormsg, char *, u16_t));

#endif // __WEBCLIENT_H


Заранее спасибо за любые советы.

Сообщение отредактировал IgorKossak - Feb 20 2014, 19:32
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
AndyBig
сообщение Feb 20 2014, 13:27
Сообщение #2


Иногдящий
****

Группа: Свой
Сообщений: 691
Регистрация: 28-02-05
Пользователь №: 2 931



По прерыванию таймера, например... В чем именно загвоздка?
Go to the top of the page
 
+Quote Post
Александр П.
сообщение Feb 20 2014, 16:26
Сообщение #3





Группа: Участник
Сообщений: 14
Регистрация: 25-12-13
Пользователь №: 79 787



Мне необходимо посылать повторный запрос сразу же после получения ответа от удаленного устройства. Если я правильно понимаю, все последующие запросы делаются анологичным образом
Код
char page[] ="get_param1";        
headers = malloc(19 + strlen(page));
sprintf(headers,"GET /%s HTTP/1.0\r\n\r\n", page);
// Send data
tcp_write(pcb, headers, strlen(headers), 1);
tcp_output(pcb);


В функции...
Код
static err_t hc_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)

...я убрал hc_clearpcb(pcb) и добавил посылку сообщения. Контроллер остается в сети. Сообщение не отправляется
Код
//hc_clearpcb(pcb);
char page[] ="get_param1";        
headers = malloc(19 + strlen(page));
sprintf(headers,"GET /%s HTTP/1.0\r\n\r\n", page);
// Send data
tcp_write(pcb, headers, strlen(headers), 1);
tcp_output(pcb);


Почему? Разве по прерыванию таймера я буду делать не тоже самое?

После выполнения первого запрос-ответа периодически вызывается (20 раз. Затем принудительный сброс соединения)
Код
static err_t hc_poll(void *arg, struct tcp_pcb *pcb)


Попытался здесь отправить запрос, ради интереса. Результата нет

Сообщение отредактировал Александр П. - Feb 20 2014, 16:14
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Feb 20 2014, 16:29
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



если вы очереди не очищаете, у вас память переполнится, разве нет?
а если вы не чистите входные очереди, то у вас забьется окно и тоже посылки перестанут идти
Go to the top of the page
 
+Quote Post
scifi
сообщение Feb 20 2014, 16:36
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Александр П. @ Feb 20 2014, 20:26) *
...я убрал hc_clearpcb(pcb) и добавил посылку сообщения. Контроллер остается в сети. Сообщение не отправляется

У вас указано "GET /%s HTTP/1.0". В протоколе HTTP 1.0 по умолчанию TCP соединение закрывается после одного запроса-ответа. В протоколе HTTP 1.1 - наоборот. Так что для начала надо заменить 1.0 на 1.1. Ну и делайте захват трафика при помощи Wireshark и сравнивайте с захватом заведомо рабочего трафика, чтобы понять, где у вас отклонения. Это если лень читать все эти RFC (а вам именно лень их читать, очевидно).
Go to the top of the page
 
+Quote Post
Александр П.
сообщение Feb 20 2014, 17:02
Сообщение #6





Группа: Участник
Сообщений: 14
Регистрация: 25-12-13
Пользователь №: 79 787



Цитата
если вы очереди не очищаете, у вас память переполнится, разве нет?
а если вы не чистите входные очереди, то у вас забьется окно и тоже посылки перестанут идти


Да, наверное, но у меня не проходит уже второе сообщение, что меньше размера окна. Как-то криво я делаю следующий запрос. А вот как правильно?

Цитата
У вас указано "GET /%s HTTP/1.0". В протоколе HTTP 1.0 по умолчанию TCP соединение закрывается после одного запроса-ответа. В протоколе HTTP 1.1 - наоборот. Так что для начала надо заменить 1.0 на 1.1.

Спасибо, попробую.
Цитата
Это если лень читать все эти RFC (а вам именно лень их читать, очевидно).

scifi, пожалуйста, не судите строго. Вы не представляете сколько я всего читаю каждый день. Я совсем недавно "заплыл" в embedded. Мало чего знаю, но постепенно разбираюсь.

фокус с протоколами результата не дал

Сообщение отредактировал Александр П. - Feb 20 2014, 17:01
Go to the top of the page
 
+Quote Post
scifi
сообщение Feb 20 2014, 17:44
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Александр П. @ Feb 20 2014, 21:02) *
фокус с протоколами результата не дал

Это было бы слишком просто :-) Наверное, имеет смысл для начала открывать и закрывать соединение на каждый запрос. Просто довелось самому делать веб-сервер поверх lwip на небольшом МК (сейчас, конечно, понимаю, что лучше было бы потщательнее поискать уже готовый). Эти самые "persistent connections" там реализовал - летать стало быстро-быстро.
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Feb 20 2014, 22:58
Сообщение #8


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(scifi @ Feb 20 2014, 21:44) *
...летать стало быстро-быстро.


во-во, переписал lwip и фриртос, зараза, быстрый ответ(пара ms) данными от сервака МК - режится роутером. Пришлось вставлять задержку sm.gif


Цитата(Александр П. @ Feb 20 2014, 21:02) *
...фокус с протоколами результата не дал


это было обязательным но не необходимым условием. в самом протоколе HTTP указывается - рвётся коннекшен или нет, опсле отдачи данных.


по теме:
возьмите пример с FreeRTOS и не парьтесь. дышать будет. хоть сам стэк и ось желают лучшего но для "хэйлохты мир" пойдёт.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Feb 21 2014, 04:53
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
это было обязательным но не необходимым условием

бррр... необходимым, но не достаточным условием!
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Feb 21 2014, 13:29
Сообщение #10


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Golikov A. @ Feb 21 2014, 08:53) *
необходимым, но не достаточным условием!


агась спасибо за правку sm.gif проблемы с многопроцессорностью головы. занята несколькоми проблемами параллельно - отсюда
и интерфейс человеческий пошаливает sm.gif
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 05:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01495 секунд с 7
ELECTRONIX ©2004-2016