Есть связка 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);
}
}
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;
}
//==============================================================================
#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
#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
Заранее спасибо за любые советы.