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

 
 
> 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
 
Start new topic
Ответов
Александр П.
сообщение Feb 20 2014, 17:02
Сообщение #2





Группа: Участник
Сообщений: 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
Сообщение #3


Гуру
******

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



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

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



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

 


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


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