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

|
Добрый день. Есть связка MCU + удаленный девайс. Связаны по Ethernet. Требуется периодически посылать на удаленный девайс сообщение и принимать от него ответ. Использую lwIP стек. Ниже приведен работающий код. В конечном итоге callback функция ReturnPg возвращает ответ удаленного девайса. Вопрос. Как реализовать периодический опрос. main.cCODE //============================================================================== 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.cCODE #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.hCODE #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] - для короткого!!!
|
|
|
|
|
Feb 20 2014, 16:26
|
Группа: Участник
Сообщений: 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
|
|
|
|
|
Feb 20 2014, 17:02
|
Группа: Участник
Сообщений: 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
|
|
|
|
|
Feb 20 2014, 22:58
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(scifi @ Feb 20 2014, 21:44)  ...летать стало быстро-быстро. во-во, переписал lwip и фриртос, зараза, быстрый ответ(пара ms) данными от сервака МК - режится роутером. Пришлось вставлять задержку  Цитата(Александр П. @ Feb 20 2014, 21:02)  ...фокус с протоколами результата не дал это было обязательным но не необходимым условием. в самом протоколе HTTP указывается - рвётся коннекшен или нет, опсле отдачи данных. по теме: возьмите пример с FreeRTOS и не парьтесь. дышать будет. хоть сам стэк и ось желают лучшего но для "хэйлохты мир" пойдёт.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|