299 lines
9.5 KiB
C
299 lines
9.5 KiB
C
/******************************************************************************
|
|
* Copyright 2013-2014 Espressif Systems (Wuxi)
|
|
*
|
|
* FileName: espconn_udp.c
|
|
*
|
|
* Description: udp proto interface
|
|
*
|
|
* Modification history:
|
|
* 2014/3/31, v1.0 create this file.
|
|
*******************************************************************************/
|
|
|
|
#include "ets_sys.h"
|
|
#include "os_type.h"
|
|
//#include "os.h"
|
|
|
|
#include "lwip/inet.h"
|
|
#include "lwip/err.h"
|
|
#include "lwip/pbuf.h"
|
|
#include "lwip/mem.h"
|
|
#include "lwip/tcp_impl.h"
|
|
#include "lwip/udp.h"
|
|
|
|
#include "lwip/app/espconn_udp.h"
|
|
|
|
extern espconn_msg *plink_active;
|
|
|
|
static void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn *pespconn)
|
|
{
|
|
if (pespconn == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (pespconn->sent_callback != NULL) {
|
|
pespconn->sent_callback(pespconn);
|
|
}
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR espconn_data_sent(void *arg)
|
|
{
|
|
espconn_msg *psent = arg;
|
|
|
|
if (psent == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (psent->pcommon.cntr == 0) {
|
|
psent->pespconn->state = ESPCONN_CONNECT;
|
|
sys_timeout(TCP_FAST_INTERVAL, espconn_data_sentcb, psent->pespconn);
|
|
} else {
|
|
espconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_udp_sent
|
|
* Description : sent data for client or server
|
|
* Parameters : void *arg -- client or server to send
|
|
* uint8* psent -- Data to send
|
|
* uint16 length -- Length of data to send
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
void ICACHE_FLASH_ATTR
|
|
espconn_udp_sent(void *arg, uint8 *psent, uint16 length)
|
|
{
|
|
espconn_msg *pudp_sent = arg;
|
|
struct udp_pcb *upcb = pudp_sent->pcommon.pcb;
|
|
struct pbuf *p, *q;
|
|
u8_t *data = NULL;
|
|
u16_t cnt = 0;
|
|
u16_t datalen = 0;
|
|
u16_t i = 0;
|
|
err_t err;
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb));
|
|
|
|
if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {
|
|
return;
|
|
}
|
|
|
|
if (1024 < length) {
|
|
datalen = 1024;
|
|
} else {
|
|
datalen = length;
|
|
}
|
|
|
|
p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
|
|
|
|
if (p != NULL) {
|
|
q = p;
|
|
|
|
while (q != NULL) {
|
|
data = (u8_t *)q->payload;
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data));
|
|
|
|
for (i = 0; i < q->len; i++) {
|
|
data[i] = ((u8_t *) psent)[cnt++];
|
|
}
|
|
|
|
q = q->next;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port;
|
|
IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0],
|
|
pudp_sent->pespconn->proto.udp->remote_ip[1],
|
|
pudp_sent->pespconn->proto.udp->remote_ip[2],
|
|
pudp_sent->pespconn->proto.udp->remote_ip[3]);
|
|
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port));
|
|
err = udp_send(upcb, p);
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err));
|
|
|
|
if (p->ref != 0) {
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
|
|
pbuf_free(p);
|
|
pudp_sent->pcommon.ptrbuf = psent + datalen;
|
|
pudp_sent->pcommon.cntr = length - datalen;
|
|
espconn_data_sent(pudp_sent);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_udp_server_recv
|
|
* Description : This callback will be called when receiving a datagram.
|
|
* Parameters : arg -- user supplied argument
|
|
* upcb -- the udp_pcb which received data
|
|
* p -- the packet buffer that was received
|
|
* addr -- the remote IP address from which the packet was received
|
|
* port -- the remote port from which the packet was received
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
static void ICACHE_FLASH_ATTR
|
|
espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
|
struct ip_addr *addr, u16_t port)
|
|
{
|
|
espconn_msg *precv = arg;
|
|
struct pbuf *q = NULL;
|
|
u8_t *pdata = NULL;
|
|
u16_t length = 0;
|
|
struct ip_info ipconfig;
|
|
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb));
|
|
|
|
upcb->remote_port = port;
|
|
upcb->remote_ip = *addr;
|
|
|
|
precv->pcommon.remote_ip[0] = ip4_addr1_16(&upcb->remote_ip);
|
|
precv->pcommon.remote_ip[1] = ip4_addr2_16(&upcb->remote_ip);
|
|
precv->pcommon.remote_ip[2] = ip4_addr3_16(&upcb->remote_ip);
|
|
precv->pcommon.remote_ip[3] = ip4_addr4_16(&upcb->remote_ip);
|
|
os_memcpy(precv->pespconn->proto.udp->remote_ip, precv->pcommon.remote_ip, 4);
|
|
precv->pespconn->proto.udp->remote_port = port;
|
|
precv->pcommon.remote_port = port;
|
|
precv->pcommon.pcb = upcb;
|
|
|
|
if (wifi_get_opmode() != 1) {
|
|
wifi_get_ip_info(1, &ipconfig);
|
|
|
|
if (!ip_addr_netcmp((struct ip_addr *)precv->pespconn->proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {
|
|
wifi_get_ip_info(0, &ipconfig);
|
|
}
|
|
} else {
|
|
wifi_get_ip_info(0, &ipconfig);
|
|
}
|
|
upcb->local_ip = ipconfig.ip;
|
|
precv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&upcb->local_ip);
|
|
precv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&upcb->local_ip);
|
|
precv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&upcb->local_ip);
|
|
precv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&upcb->local_ip);
|
|
|
|
if (p != NULL) {
|
|
// q = p;
|
|
|
|
// while (q != NULL) {
|
|
// pdata = (u8_t *)os_zalloc(q ->len + 1);
|
|
// length = pbuf_copy_partial(q, pdata, q ->len, 0);
|
|
//
|
|
// LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %x\n", __LINE__, length));
|
|
// precv->pcommon.pcb = upcb;
|
|
//
|
|
// if (length != 0) {
|
|
// if (precv->pespconn->recv_callback != NULL) {
|
|
// precv->pespconn->recv_callback(precv->pespconn, pdata, length);
|
|
// }
|
|
// }
|
|
//
|
|
// q = q->next;
|
|
// os_free(pdata);
|
|
// }
|
|
pdata = (u8_t *)os_zalloc(p ->tot_len + 1);
|
|
length = pbuf_copy_partial(p, pdata, p ->tot_len, 0);
|
|
precv->pcommon.pcb = upcb;
|
|
pbuf_free(p);
|
|
if (length != 0) {
|
|
if (precv->pespconn->recv_callback != NULL) {
|
|
precv->pespconn->recv_callback(precv->pespconn, pdata, length);
|
|
}
|
|
}
|
|
os_free(pdata);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_udp_disconnect
|
|
* Description : A new incoming connection has been disconnected.
|
|
* Parameters : espconn -- the espconn used to disconnect with host
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
void ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg *pdiscon)
|
|
{
|
|
if (pdiscon == NULL) {
|
|
return;
|
|
}
|
|
|
|
struct udp_pcb *upcb = pdiscon->pcommon.pcb;
|
|
|
|
udp_disconnect(upcb);
|
|
|
|
udp_remove(upcb);
|
|
|
|
espconn_list_delete(&plink_active, pdiscon);
|
|
|
|
os_free(pdiscon);
|
|
pdiscon = NULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_udp_server
|
|
* Description : Initialize the server: set up a PCB and bind it to the port
|
|
* Parameters : pespconn -- the espconn used to build server
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
sint8 ICACHE_FLASH_ATTR
|
|
espconn_udp_server(struct espconn *pespconn)
|
|
{
|
|
struct udp_pcb *upcb = NULL;
|
|
espconn_msg *pserver = NULL;
|
|
upcb = udp_new();
|
|
|
|
if (upcb == NULL) {
|
|
return ESPCONN_MEM;
|
|
} else {
|
|
pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
|
|
|
|
if (pserver == NULL) {
|
|
udp_remove(upcb);
|
|
return ESPCONN_MEM;
|
|
}
|
|
|
|
pserver->pcommon.pcb = upcb;
|
|
pserver->pespconn = pespconn;
|
|
espconn_list_creat(&plink_active, pserver);
|
|
udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port);
|
|
udp_recv(upcb, espconn_udp_recv, (void *)pserver);
|
|
return ESPCONN_OK;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_igmp_leave
|
|
* Description : leave a multicast group
|
|
* Parameters : host_ip -- the ip address of udp server
|
|
* multicast_ip -- multicast ip given by user
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
sint8 ICACHE_FLASH_ATTR
|
|
espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
|
|
{
|
|
if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) {
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_leave_multigrup failed!\n"));
|
|
return -1;
|
|
};
|
|
|
|
return ESPCONN_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : espconn_igmp_join
|
|
* Description : join a multicast group
|
|
* Parameters : host_ip -- the ip address of udp server
|
|
* multicast_ip -- multicast ip given by user
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
sint8 ICACHE_FLASH_ATTR
|
|
espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
|
|
{
|
|
if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) {
|
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n"));
|
|
return -1;
|
|
};
|
|
|
|
/* join to any IP address at the port */
|
|
return ESPCONN_OK;
|
|
}
|