esp8266 airkiss联网进行TCP,UDP通信服务

   esp8266是一块很火的wifi模块,本文讲的是以esp8266作为服务器,PC作为客户端通信的。esp8266是在station模式的。SDK的版本号是ESP8266_NONOS_SDK-2.2.0.
      在嵌入式的设备联网过程中,最大的痛点是联网要输入账号和密码。而大多数的嵌入式设备是没有GUI的。本文用的是airkiss通信协议。airkiss可以用在没有显示器交互的嵌入式设备联网中。联网步骤是:
       1.打开手机wifi,连接至路由器上(该路由器也是嵌入式设备需要连接的路由器).
       2.打开微信,进入乐鑫微信公众后,点击airkiss设备并点击。   

         esp8266 airkiss联网进行TCP,UDP通信服务_第1张图片
esp8266 airkiss联网进行TCP,UDP通信服务_第2张图片
    

3.出现上图,填上用户名和密码,点击连接。

下面我们进入代码讲解阶段。
    一.airkiss讲解。在设备中,我们想要实现的功能是:没有连接到wifi的情况下,需要通过airkiss联网。之后保存wifi账号和密码。在下次开机时能自动联网。在要修改wifi账号和密码时,要通过airkiss修改账号和密码。
    通过长按5s按键进入airkiss配置账号和密码。
    按键初始化代码如下:
代码中,key_init_single是定义按键的,AIRKISS_KEY_IO_NUM,是对应引脚的ID号,AIRKISS_KEY_IO_MUX为引脚名称。AIRISSS_KEY_IO_FUNC为引脚功能设为GPIO功能。而smart_long_press_callback与smart_press_callback分别为长按与短按按键后的回调函数。长按回调函数如下:

esp8266 airkiss联网进行TCP,UDP通信服务_第3张图片.
在airkiss初始化之前,需要停止airkiss,smartconfig_stop为停止airkiss.而smartconfig_set_type为设置smartconfig类型。这里设置SC_TYPE_ESPTOUCH_AIRKISS,表示esptouch与airkiss兼容。当然也可以用SC_TYPE_AIRKISS.注意,在airkiss功能中,wifi只能在station模式,所以,要把wifi设置为STATION_MODE模式。smartconfig_start,开始airkiss配置。smartconfig_done.smartconfig_done为airkiss的回调函数。smartconfig_done代码如下:
void ICACHE_FLASH_ATTR
smartconfig_done(sc_status status, void *pdata)
{
    switch(status) {
        case SC_STATUS_WAIT:
            os_printf("SC_STATUS_WAIT\n");
            break;
        case SC_STATUS_FIND_CHANNEL:  //Open the application link at this stage
            os_printf("SC_STATUS_FIND_CHANNEL\n");
            break;
        case SC_STATUS_GETTING_SSID_PSWD:
            os_printf("SC_STATUS_GETTING_SSID_PSWD\n");
			sc_type *type = pdata;
            if (*type == SC_TYPE_ESPTOUCH) {
                os_printf("SC_TYPE:SC_TYPE_ESPTOUCH\n");
            } else {
                os_printf("SC_TYPE:SC_TYPE_AIRKISS\n");
            }
            break;
        case SC_STATUS_LINK:
            os_printf("SC_STATUS_LINK\n");
            struct station_config *sta_conf = pdata;
	        wifi_station_set_config(sta_conf);
	        wifi_station_disconnect();
	        wifi_station_connect();
            break;
        case SC_STATUS_LINK_OVER:
            os_printf("SC_STATUS_LINK_OVER\n");
            if (pdata != NULL) {
				//SC_TYPE_ESPTOUCH
                uint8 phone_ip[4] = {0};

                os_memcpy(phone_ip, (uint8*)pdata, 4);
                os_printf("Phone ip: %d.%d.%d.%d\n",phone_ip[0],phone_ip[1],phone_ip[2],phone_ip[3]);
            } else {
            	//SC_TYPE_AIRKISS - support airkiss v2.0
				airkiss_start_discover();
            }
            smartconfig_stop();
            break;
    }

}

    }在代码中status = SC_STATUS_GETTING_SSID_PSWD时,参数 void *pdata为sc_type *类型的指针变量,表示此次配置是AirKiss还是ESP-TOUCH;当status=SC_STATUS_LINK时,参数void*pdata为struct station_config类型的指针变量;当status = SC_STATUS_LINK_OVER时,参数void *pdata是移动的IP地址的指针,4个字节。(仅支持在ESP-TOUCH方式下,其他方式则为NULL).当status为其他状态时,参数void*pdata为NULL.uint8 log=1,表示UART打印连接过程。否则:UART仅打印连接结果。在status= SC_STATUS_LINK,我们进行wifi参数设置。wifi_station_set_config(sta_conf)表示.之后要先断开wifi连接。再进行连接。注意:wifi_station_set_config(sta_conf)是设置并保存至flash里。也就是说wifi账号和密码已经保存至flash了。

    在主函数中,代码如下:
esp8266 airkiss联网进行TCP,UDP通信服务_第4张图片uart_reattach为初始化uart,设置uart0用户使用的,uart1表示esp8266打印接口。在此不再讲解。keys_init为刚刚的按键初始化模块。wifi_status_led_install功能为注册一个wifi状态led灯。wifi没有连接上时,一直闪烁。wifi连接上后,led灯常亮。user_wifi_station_config为初始化wifi模式。(需要判断是否有wifi账号和密码在flash里,flash里的密码为通过airkiss功能保存的)。

    
二.开机时,wifi的初始化。此时我们看一下user_wifi_station_config函数。 esp8266 airkiss联网进行TCP,UDP通信服务_第5张图片
wifi_set_opmode(STATION_MODE)为设置wifi模式。wifi_set_event_handler_cb(wifi_handle_event_cb)为注册wifi事件。后面会展开讲解。wifi_station_get_config_default(&sta_conf)此函数是读取flash里上次通过airkiss设置的wifi账号和密码。如果读取成功,返回true.否则返回false.返回false表示flash里没有wifi的参数。在返回true后,我们调用wifi_station_set_config(&sta_conf)设置wifi参数,在连接wifi之前记得先断开连接。现在我们来讲解一下注册的wifi事件wifi_handle_event_cb.代码如下:
/******************************************************************************
 * FunctionName : wifi_handle_event_cb
 * Description  : wifi event callback
 * Parameters   : evt,事件
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
wifi_handle_event_cb(System_Event_t *evt)
{
	os_printf("event %x\n", evt->event);
	switch (evt->event) {
		case EVENT_STAMODE_CONNECTED:
			os_printf("connect to ssid %s, channel %d\n",
					evt->event_info.connected.ssid,
					evt->event_info.connected.channel);
			break;
		case EVENT_STAMODE_DISCONNECTED:
			os_printf("disconnect from ssid %s, reason %d\n",
					evt->event_info.disconnected.ssid,
					evt->event_info.disconnected.reason);
			break;
		case EVENT_STAMODE_AUTHMODE_CHANGE:
			os_printf("mode: %d -> %d\n",
					evt->event_info.auth_change.old_mode,
					evt->event_info.auth_change.new_mode);
			break;
		case EVENT_STAMODE_GOT_IP:
			os_printf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR,
					IP2STR(&evt->event_info.got_ip.ip),
					IP2STR(&evt->event_info.got_ip.mask),
					IP2STR(&evt->event_info.got_ip.gw));
			os_printf("\n");
			user_udp_init();
			os_printf("\r\nUDP start\r\n");
			user_tcpserver_init(SERVER_LOCAL_PORT);
			break;
		case EVENT_SOFTAPMODE_STACONNECTED:
			os_printf("station: " MACSTR "join, AID = %d\n",
					MAC2STR(evt->event_info.sta_connected.mac),
					evt->event_info.sta_connected.aid);
			break;
		case EVENT_SOFTAPMODE_STADISCONNECTED:
			os_printf("station: " MACSTR "leave, AID = %d\n",
					MAC2STR(evt->event_info.sta_disconnected.mac),
					evt->event_info.sta_disconnected.aid);
			break;
		default:
			break;
	}
}

这个函数是由事件驱动的,非常有用。比其它用定时器定时器扫描wifi的状态好太用了EVENT_STAMODE_CONNECTED,表示wifi已经连接上了路由器,并打印出路由器的ssid,channel.EVENT_STAMODE_DISCONNECTED,wifi断开时事件类型。而EVENT_STAMODE_AUTHMODE_CHANGE,表示wifi切换信道的了,并打印出新旧信道,EVENT_STAMODE_GOT_IP,在wifi连接至路由器后回调的。可以知道路由器的ip,mask,gw.这个非常有用。因为所有的业务都必须在wifi连接上后才能开始。我们的TCP服务器和UDP绑定端口就是在此调用的。在后文详细讲解。
    三.UDP端口绑定和组播绑定。在wifi回调事件中,我们在状态EVENT_STAMODE_GOT_IP中,调用了UDP初始化.如下代码片段。
	case EVENT_STAMODE_GOT_IP:
			os_printf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR,
					IP2STR(&evt->event_info.got_ip.ip),
					IP2STR(&evt->event_info.got_ip.mask),
					IP2STR(&evt->event_info.got_ip.gw));
			os_printf("\n");
			user_udp_init();
			os_printf("\r\nUDP start\r\n");
			user_tcpserver_init(SERVER_LOCAL_PORT);
			break;
我们来看看user_udp_init函数吧。代码如下:
/******************************************************************************
 * FunctionName : user_devicefind_init
 * Description  : create a udp listening
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_udp_init(void)
{
	sint8 ret = 0;
	ip_addr_t multicast_ip;
	struct ip_info host_info;
	multicast_ip.addr = ipaddr_addr(Multicast_Ip);
	os_printf("\r\nmulticast_ip:%d\r\n",multicast_ip.addr);
	wifi_get_ip_info(STATION_IF,&host_info);
	os_printf("host_ip:%d.%d.%d.%d\r\n",ip4_addr1(&(host_info.ip)),
			ip4_addr2(&(host_info.ip)),ip4_addr3(&(host_info.ip)),ip4_addr4(&(host_info.ip)));
	wifi_set_broadcast_if(STATION_MODE);
	espconn_igmp_join(&(host_info.ip),&multicast_ip);
	udpespconn.type = ESPCONN_UDP;//UDP
	udpespconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); //return memory space
	udpespconn.proto.udp->local_port = UDP_LOCAL_PORT;//local port
	espconn_regist_recvcb(&udpespconn,user_udp_recv_cb);//Resigister a callback function that it will be callback when udp receives datas from network
	ret = espconn_create(&udpespconn);
	os_printf("\r\nret=%d\r\n",ret);
}
在调用该函数之前,wifi已经连接至路由器了,所以本wifi station的IP地址是可以知道的。调用wifi_get_ip_info函数可以返回本模块被分配的IP地址。组播的地址是由自己定义。关于组播,大家可以百度搜。再经过ip的格式转换后,就可以绑定组播了。之后通过wifi_set_broadcast_if(STATION_MODE)绑定广播。之后建立UDP结构体块,绑定本地端口号,并注册udp接受回调函数。espconn_create,创建UDP连接。为什么要创建UDP,并绑定主播与广播呢?做这些工作是为了下面的TCP连接。在应用场景中,端设备是不知道服务器地址的。而没有服务器的IP就无法连接到服务器。所以可以通过组播。在服务器端,通过发送组播(内外网)或者广播(内网).而加入组播或者广播的设备可以收到服务器发送的组播或者广播。接受到组播或者广播命令时,也就可以知道服务器的IP地址等信息,也可以通过特定命令下发其他有用的信息。这样就可以通过IP地址连接至TCP服务器了。user_udp_recv_cb接受回调函数如下:
/******************************************************************************
 * FunctionName : user_udp_recv_cb
 * Description  : Processing the received udp packet
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_udp_recv_cb(void *arg,char *pusrdata,unsigned short length)
{
	os_printf("recv udp data:%s\n",pusrdata);
	struct espconn *pesp_conn = arg;

	remot_info *premot = NULL;
	sint8 value = ESPCONN_OK;
	if(espconn_get_connection_info(pesp_conn,&premot,0) == ESPCONN_OK){
		pesp_conn->proto.udp->remote_port = premot->remote_port;
		pesp_conn->proto.udp->remote_ip[0] = premot->remote_ip[0];
		pesp_conn->proto.udp->remote_ip[1] = premot->remote_ip[1];
		pesp_conn->proto.udp->remote_ip[2] = premot->remote_ip[2];
		pesp_conn->proto.udp->remote_ip[3] = premot->remote_ip[3];
		os_printf("remote_ip:%d.%d.%d.%d\r\n",pesp_conn->proto.udp->remote_ip[0],
				pesp_conn->proto.udp->remote_ip[1],pesp_conn->proto.udp->remote_ip[2],pesp_conn->proto.udp->remote_ip[3]);
		espconn_sendto(pesp_conn,pusrdata,os_strlen(pusrdata));
	}
}

请注意,回调函数中的espconn_get_connection_info函数的作用就是获取该UDP是哪个源IP,源端口发送的。这个非常有用。在接收信息后回复该设备命令场景很有用。切记不可用参量arg里面的remote_ip和remote_port.它指的是我们udp创建时绑定的远程ip和远程端口。而不是当前命令的远程ip和远程端口。如果创建UDP块时没有绑定远程ip和远程端口,则arg里的remote_ip和remote_port应该是0.
    三.TCP服务器创建。终于将到了TCP服务器了。直接上代码吧。
/****************************************************************************** * FunctionName : user_tcpserver_init * Description : parameter initialize as a TCP server * Parameters : port --server port * Returns : none*******************************************************************************/void ICACHE_FLASH_ATTRuser_tcpserver_init(uint32 port){esp_conn.type = ESPCONN_TCP;//TCPesp_conn.state = ESPCONN_NONE;esp_conn.proto.tcp = &esptcp;esp_conn.proto.tcp->local_port = port;espconn_regist_connectcb(&esp_conn,tcp_server_listen);sint8 ret = espconn_accept(&esp_conn);os_printf("espconn_accept [%d]!!!\r\n",ret);
}TCP服务器初始化时,也只是绑定了本地端口。

注意,最好是UDP与TCP的端口后要不一样。respconn_regist_connectcb为注册监听回调函数tcp_server_listen.在此函数中,又注册了几个回调函数。如下:
/******************************************************************************
 * FunctionName : tcp_server_listen
 * Description  : TCP server listened a connection successfully
 * Parameters   : arg -- Addritional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
tcp_server_listen(void *arg)
{
	struct espconn *pesp_conn = arg;
	os_printf("tcp_server_listen!!!\r\n");

	espconn_regist_recvcb(pesp_conn,tcp_server_recv_cb);//Register a callback function that successfully receives network data
	espconn_regist_reconcb(pesp_conn,tcp_server_recon_cb);//Regiser callback function when TCP connections are abnormally disconnected
	espconn_regist_disconcb(pesp_conn,tcp_server_discon_cb);//Register the callback function when the TCP connections are normally disconnected
	espconn_regist_sentcb(pesp_conn,tcp_server_sent_cb);//Register the callback function when the network receives datas sucessfully
}

当服务器接受到tcp数据时,回掉tcp_server_recv_cb;当tcp异常掉线时,回掉tcp_server_reconn_cb函数;当tcp正常断开时回调tcp_server_discon_cb;当tcp发生数据成功后回调tcp_server_sent_cb.
    总结:本文的功能是:通过按键长按出发airkiss配置wifi连接密码,并保持在flash里。在以后的每次上电都可以自动连接至路由器。为了可以根据人性后的连接tcp服务器,先建立了UDP并绑定了广播和组播。这样,服务器可以在不知道esp8266模块的ip地址的情况下发送组播(外网)或者广播(内网),与esp8266通信。在esp8266模块接受到组播或者广播后,分析接受到的数据可以知道服务器的ip和端口号,续而发起tcp连接。这样,esp8266就可以上次数据至服务器了。

    最后,公布一下详细代码如下:
void ICACHE_FLASH_ATTR
keys_init(void)
{
	singlekey[0] = (struct single_key_param *)airkissfun_key();			//airkissfun key
	singlekey[1] = (struct single_key_param *)start_test_key();			//start test key
	key.key_num = PLUG_KEY_NUM;
	key.single_key = singlekey;
	key_init(&key);
}
void ICACHE_FLASH_ATTR
user_init(void)
{
	uart_reattach();//uart initialize
	keys_init(); // keys initialize
	wifi_status_led_install(HUMITURE_WIFI_LED_IO_NUM, HUMITURE_WIFI_LED_IO_MUX, HUMITURE_WIFI_LED_IO_FUNC);//wifi led initialize
	user_wifi_station_config();//config wifi station and connect wifi to AP
}
/*
 * airkissfun.c
 *
 *  Created on: 2018年5月25日
 *      Author: admin
 */
#include "ets_sys.h"
#include "osapi.h"
#include "ip_addr.h"
#include "espconn.h"
#include "mem.h"

#include "user_interface.h"
#include "smartconfig.h"
#include "airkiss.h"
#include "driver/uart.h"
#include "driver/key.h"
#include "driver/airkissfun.h"

#define DEVICE_TYPE 		"gh_9e2cff3dfa51" //wechat public number
#define DEVICE_ID 			"122475" 		  //model ID

#define DEFAULT_LAN_PORT 	12476

#define AIRKISS_KEY_IO_MUX PERIPHS_IO_MUX_GPIO5_U   // airkiss key gpio's name
#define AIRKISS_KEY_IO_NUM GPIO_ID_PIN(5)		   //airkiss key gpio's id
#define AIRKISS_KEY_IO_FUNC FUNC_GPIO5			   //airkiss key gpio's func



LOCAL esp_udp ssdp_udp;
LOCAL struct espconn pssdpudpconn;
LOCAL os_timer_t ssdp_time_serv;

uint8_t  lan_buf[200];
uint16_t lan_buf_len;
uint8 	 udp_sent_cnt = 0;

const airkiss_config_t akconf =
{
	(airkiss_memset_fn)&memset,
	(airkiss_memcpy_fn)&memcpy,
	(airkiss_memcmp_fn)&memcmp,
	0,
};

LOCAL void ICACHE_FLASH_ATTR
airkiss_wifilan_time_callback(void)
{
	uint16 i;
	airkiss_lan_ret_t ret;

	if ((udp_sent_cnt++) >30) {
		udp_sent_cnt = 0;
		os_timer_disarm(&ssdp_time_serv);//s
		//return;
	}

	ssdp_udp.remote_port = DEFAULT_LAN_PORT;
	ssdp_udp.remote_ip[0] = 255;
	ssdp_udp.remote_ip[1] = 255;
	ssdp_udp.remote_ip[2] = 255;
	ssdp_udp.remote_ip[3] = 255;
	lan_buf_len = sizeof(lan_buf);
	ret = airkiss_lan_pack(AIRKISS_LAN_SSDP_NOTIFY_CMD,
		DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);
	if (ret != AIRKISS_LAN_PAKE_READY) {
		os_printf("Pack lan packet error!");
		return;
	}

	ret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
	if (ret != 0) {
		os_printf("UDP send error!");
	}
	os_printf("Finish send notify!\n");
}

LOCAL void ICACHE_FLASH_ATTR
airkiss_wifilan_recv_callbk(void *arg, char *pdata, unsigned short len)
{
	uint16 i;
	remot_info* pcon_info = NULL;

	airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf);
	airkiss_lan_ret_t packret;

	switch (ret){
	case AIRKISS_LAN_SSDP_REQ:
		espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0);
		os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1],
			                                    pcon_info->remote_ip[2],pcon_info->remote_ip[3]);
		os_printf("remote port: %d \r\n",pcon_info->remote_port);

        pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port;
		os_memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4);
		ssdp_udp.remote_port = DEFAULT_LAN_PORT;

		lan_buf_len = sizeof(lan_buf);
		packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD,
			DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);

		if (packret != AIRKISS_LAN_PAKE_READY) {
			os_printf("Pack lan packet error!");
			return;
		}

		os_printf("\r\n\r\n");
		for (i=0; i
/*
 * tcp_msg.c
 *
 *  Created on: 2018年5月28日
 *      Author: admin
 */

#include "ets_sys.h"
#include "osapi.h"
#include "ip_addr.h"
#include "espconn.h"
#include "mem.h"

#include "user_interface.h"
#include "driver/tcp_msg.h"
#include "driver/udp_msg.h"

#define LINK_LED_IO_MUX     PERIPHS_IO_MUX_MTDI_U
#define LINK_LED_IO_NUM     12
#define LINK_LED_IO_FUNC    FUNC_GPIO12

#define SERVER_LOCAL_PORT   9909

LOCAL os_timer_t link_led_timer; //link led timer
LOCAL uint8 link_led_level = 0;	 //link led current level
LOCAL struct espconn esp_conn;  //esp_conn parameter
LOCAL esp_tcp esptcp; //tcp struct parameter

/******************************************************************************
 * FunctionName : link_led_init
 * Description  : link led init
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
link_led_init(void)
{
	PIN_FUNC_SELECT(LINK_LED_IO_MUX, LINK_LED_IO_FUNC);
}

/******************************************************************************
 * FunctionName : link_led_output
 * Description  : output the link led
 * Parameters   : level=1,high level;level=0,low level
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
link_led_output(uint8 level)
{
    GPIO_OUTPUT_SET(GPIO_ID_PIN(LINK_LED_IO_NUM), level);
}

/******************************************************************************
 * FunctionName : link_led_timer_cb
 * Description  : the callback function of the link_led_timer
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
link_led_timer_cb(void)
{
	link_led_level = (~link_led_level & 0x01);
	GPIO_OUTPUT_SET(GPIO_ID_PIN(LINK_LED_IO_NUM),link_led_level);
}

/******************************************************************************
 * FunctionName : link_led_timer_init
 * Description  : The timer of link led is initalized
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
link_led_timer_init(void)
{
	os_timer_disarm(&link_led_timer);
	os_timer_setfn(&link_led_timer,(os_timer_func_t *)link_led_timer_cb,NULL);
	os_timer_arm(&link_led_timer,50,1);
}

/******************************************************************************
 * FunctionName : link_led_timer_done
 * Description  : close the link led timer and link led
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
link_led_timer_done(void)
{
    os_timer_disarm(&link_led_timer);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(LINK_LED_IO_NUM), 0);
}

LOCAL void ICACHE_FLASH_ATTR
tcp_server_sent_cb(void *arg)
{
	//data sent successfully
	os_printf("tcp sent successed  \r\n");
}

/******************************************************************************
 * FunctionName : tcp_server_recv_cb
 * Description  : receive callback.
 * Parameters   : arg -- Addritional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
tcp_server_recv_cb(void *arg,char *pusrdata,unsigned short length)
{
	//received some data from tcp connection
	struct espconn *pespconn = arg;
	espconn_send(pespconn,pusrdata,length);
}

/******************************************************************************
 * FunctionName : tcp_server_discon_cb
 * Description  : disconnect callback
 * Parameters   : arg -- Addritional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
tcp_server_discon_cb(void *arg)
{
	//tcp disconnect sucesssfully
	os_printf("tcp disconnect successed!!!\r\n");
}

/******************************************************************************
 * FunctionName : tcp_server_recon_cb
 * Description  : reconnect callback,error occured in TCP connection
 * Parameters   : arg -- Addritional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
tcp_server_recon_cb(void *arg,sint8 err)
{
	//error occured,tcp connection broke.
	os_printf("reconnect callback,error code %d!!! \r\n",err);
}

/******************************************************************************
 * FunctionName : tcp_server_listen
 * Description  : TCP server listened a connection successfully
 * Parameters   : arg -- Addritional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
tcp_server_listen(void *arg)
{
	struct espconn *pesp_conn = arg;
	os_printf("tcp_server_listen!!!\r\n");

	espconn_regist_recvcb(pesp_conn,tcp_server_recv_cb);//Register a callback function that successfully receives network data
	espconn_regist_reconcb(pesp_conn,tcp_server_recon_cb);//Regiser callback function when TCP connections are abnormally disconnected
	espconn_regist_disconcb(pesp_conn,tcp_server_discon_cb);//Register the callback function when the TCP connections are normally disconnected
	espconn_regist_sentcb(pesp_conn,tcp_server_sent_cb);//Register the callback function when the network receives datas sucessfully
}

/******************************************************************************
 * FunctionName : user_tcpserver_init
 * Description  : parameter initialize as a TCP server
 * Parameters   : port --server port
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_tcpserver_init(uint32 port)
{
	esp_conn.type = ESPCONN_TCP;//TCP
	esp_conn.state = ESPCONN_NONE;
	esp_conn.proto.tcp = &esptcp;
	esp_conn.proto.tcp->local_port = port;
	espconn_regist_connectcb(&esp_conn,tcp_server_listen);
	sint8 ret = espconn_accept(&esp_conn);
	os_printf("espconn_accept [%d]!!!\r\n",ret);
}

/******************************************************************************
 * FunctionName : wifi_handle_event_cb
 * Description  : wifi event callback
 * Parameters   : evt,事件
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
wifi_handle_event_cb(System_Event_t *evt)
{
	os_printf("event %x\n", evt->event);
	switch (evt->event) {
		case EVENT_STAMODE_CONNECTED:
			os_printf("connect to ssid %s, channel %d\n",
					evt->event_info.connected.ssid,
					evt->event_info.connected.channel);
			break;
		case EVENT_STAMODE_DISCONNECTED:
			os_printf("disconnect from ssid %s, reason %d\n",
					evt->event_info.disconnected.ssid,
					evt->event_info.disconnected.reason);
			break;
		case EVENT_STAMODE_AUTHMODE_CHANGE:
			os_printf("mode: %d -> %d\n",
					evt->event_info.auth_change.old_mode,
					evt->event_info.auth_change.new_mode);
			break;
		case EVENT_STAMODE_GOT_IP:
			os_printf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR,
					IP2STR(&evt->event_info.got_ip.ip),
					IP2STR(&evt->event_info.got_ip.mask),
					IP2STR(&evt->event_info.got_ip.gw));
			os_printf("\n");
			user_udp_init();
			os_printf("\r\nUDP start\r\n");
			user_tcpserver_init(SERVER_LOCAL_PORT);
			break;
		case EVENT_SOFTAPMODE_STACONNECTED:
			os_printf("station: " MACSTR "join, AID = %d\n",
					MAC2STR(evt->event_info.sta_connected.mac),
					evt->event_info.sta_connected.aid);
			break;
		case EVENT_SOFTAPMODE_STADISCONNECTED:
			os_printf("station: " MACSTR "leave, AID = %d\n",
					MAC2STR(evt->event_info.sta_disconnected.mac),
					evt->event_info.sta_disconnected.aid);
			break;
		default:
			break;
	}
}

/******************************************************************************
 * FunctionName : user_wifi_station_config
 * Description  : wifi station config
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_wifi_station_config(void)
{
	struct station_config sta_conf,sta[5];
	bool result = false;
	wifi_set_opmode(STATION_MODE);//Set the wifi mode as station mode
	wifi_set_event_handler_cb(wifi_handle_event_cb);//when wifi is connected,will callback wifi_handle_event_cb
	result = wifi_station_get_config_default(&sta_conf);//get the wifi station paramter from flash
	if(result){
		os_printf("get wifi station parameter sucessed!\r\n");
		wifi_station_set_config(&sta_conf);
		wifi_station_disconnect();
		wifi_station_connect();
	}else{
		os_printf("get wifi station parameter failed!\r\n");
	}
}

/*
 * udp_msg.c
 *
 *  Created on: 2018年5月30日
 *      Author: admin
 */

#include "ets_sys.h"
#include "osapi.h"
#include "ip_addr.h"
#include "espconn.h"
#include "mem.h"

#include "user_interface.h"
#include "driver/udp_msg.h"

#define UDP_LOCAL_PORT 	9666
#define MULTICAST_IP	"224.0.1.99"

LOCAL struct espconn udpespconn; //udp struct parameter

const char *Multicast_Ip = MULTICAST_IP;


/******************************************************************************
 * FunctionName : user_udp_recv_cb
 * Description  : Processing the received udp packet
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_udp_recv_cb(void *arg,char *pusrdata,unsigned short length)
{
	os_printf("recv udp data:%s\n",pusrdata);
	struct espconn *pesp_conn = arg;

	remot_info *premot = NULL;
	sint8 value = ESPCONN_OK;
	if(espconn_get_connection_info(pesp_conn,&premot,0) == ESPCONN_OK){
		pesp_conn->proto.udp->remote_port = premot->remote_port;
		pesp_conn->proto.udp->remote_ip[0] = premot->remote_ip[0];
		pesp_conn->proto.udp->remote_ip[1] = premot->remote_ip[1];
		pesp_conn->proto.udp->remote_ip[2] = premot->remote_ip[2];
		pesp_conn->proto.udp->remote_ip[3] = premot->remote_ip[3];
		os_printf("remote_ip:%d.%d.%d.%d\r\n",pesp_conn->proto.udp->remote_ip[0],
				pesp_conn->proto.udp->remote_ip[1],pesp_conn->proto.udp->remote_ip[2],pesp_conn->proto.udp->remote_ip[3]);
		espconn_sendto(pesp_conn,pusrdata,os_strlen(pusrdata));
	}
}
/******************************************************************************
 * FunctionName : user_devicefind_init
 * Description  : create a udp listening
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_udp_init(void)
{
	sint8 ret = 0;
	ip_addr_t multicast_ip;
	struct ip_info host_info;
	multicast_ip.addr = ipaddr_addr(Multicast_Ip);
	os_printf("\r\nmulticast_ip:%d\r\n",multicast_ip.addr);
	wifi_get_ip_info(STATION_IF,&host_info);
	os_printf("host_ip:%d.%d.%d.%d\r\n",ip4_addr1(&(host_info.ip)),
			ip4_addr2(&(host_info.ip)),ip4_addr3(&(host_info.ip)),ip4_addr4(&(host_info.ip)));
	wifi_set_broadcast_if(STATION_MODE);
	espconn_igmp_join(&(host_info.ip),&multicast_ip);
	udpespconn.type = ESPCONN_UDP;//UDP
	udpespconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); //return memory space
	udpespconn.proto.udp->local_port = UDP_LOCAL_PORT;//local port
	espconn_regist_recvcb(&udpespconn,user_udp_recv_cb);//Resigister a callback function that it will be callback when udp receives datas from network
	ret = espconn_create(&udpespconn);
	os_printf("\r\nret=%d\r\n",ret);
}

 
  


你可能感兴趣的:(esp8266)