天天看點

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通信服務

esp8266 airkiss聯網進行TCP,UDP通信服務

。     

3.出現上圖,填上使用者名和密碼,點選連接配接。

下面我們進入代碼講解階段。     一.airkiss講解。在裝置中,我們想要實作的功能是:沒有連接配接到wifi的情況下,需要通過airkiss聯網。之後儲存wifi賬号和密碼。在下次開機時能自動聯網。在要修改wifi賬号和密碼時,要通過airkiss修改賬号和密碼。     通過長按5s按鍵進入airkiss配置賬号和密碼。     按鍵初始化代碼如下:

esp8266 airkiss聯網進行TCP,UDP通信服務

代碼中,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通信服務

. 在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通信服務

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通信服務

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伺服器了。直接上代碼吧。

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<lan_buf_len; i++)
			os_printf("%c",lan_buf[i]);
		os_printf("\r\n\r\n");

		packret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
		if (packret != 0) {
			os_printf("LAN UDP Send err!");
		}

		break;
	default:
		os_printf("Pack is not ssdq req!%d\r\n",ret);
		break;
	}
}

void ICACHE_FLASH_ATTR
airkiss_start_discover(void)
{
	ssdp_udp.local_port = DEFAULT_LAN_PORT;
	pssdpudpconn.type = ESPCONN_UDP;
	pssdpudpconn.proto.udp = &(ssdp_udp);
	espconn_regist_recvcb(&pssdpudpconn, airkiss_wifilan_recv_callbk);
	espconn_create(&pssdpudpconn);

	os_timer_disarm(&ssdp_time_serv);
	os_timer_setfn(&ssdp_time_serv, (os_timer_func_t *)airkiss_wifilan_time_callback, NULL);
	os_timer_arm(&ssdp_time_serv, 1000, 1);//1s
}


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;
    }

}

/******************************************************************************
 * FunctionName : long_press_callback
 * Description  : When pressing the button frequently,clear the stored wifi information
 * 				  and enter the airkiss function
 * Parameters   : NONE
 * Returns      : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
smart_long_press_callback(void)
{
	 //system_restore();	//restore data to spi
	 //system_restart();	//restart machine
	smartconfig_stop();
	smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS); //SC_TYPE_ESPTOUCH,SC_TYPE_AIRKISS,SC_TYPE_ESPTOUCH_AIRKISS
	wifi_set_opmode(STATION_MODE);
	smartconfig_start(smartconfig_done);
}


LOCAL void ICACHE_FLASH_ATTR
smart_short_press_callback(void)
{

}
/******************************************************************************
 * FunctionName : keyofconnect_init
 * Description  : Initializes the airkiss connection function module
 * Parameters   : NONE
 * Returns      : NONE
*******************************************************************************/

struct single_key_param *ICACHE_FLASH_ATTR
airkissfun_key(void)
{
	struct single_key_param *smart_connect_key = key_init_single(AIRKISS_KEY_IO_NUM,AIRKISS_KEY_IO_MUX,\
			AIRKISS_KEY_IO_FUNC,smart_long_press_callback,smart_short_press_callback);
	return smart_connect_key;
}

           
/*
 * 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);
}
           

繼續閱讀