下面代码的一部分是从乐鑫提供的iot_demo中提取并由自己修改来的:
#include "osapi.h"
#include "ets_sys.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "c_types.h"
//详细格式描述可以参考我写的一篇文章:【】
#define get "GET %s HTTP/1.1\r\nHost:%s\r\nAccept-Language:zh-cn\r\nConnection:keep-alive\r\n\r\n"
/***************************函数声明********************************/
LOCAL void user_esp_platform_check_ip(void);
/****************************END***********************************/
/******************************tcp结构体及定时器声明****************************/
LOCAL struct espconn user_conn;
LOCAL struct _esp_tcp user_tcp;
LOCAL os_timer_t client_timer;
ip_addr_t esp_server_ip;
/****************************END***********************************/
/**************************重连的回调函数***********************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_reconnect(struct espconn *pespconn)//重连定时器的回调函数
{
os_printf("user_esp_platform_reconnect\r\n");
user_esp_platform_check_ip();
}
/******************************************************************************
* FunctionName : array_cmp
* Description : 两个数组之间的比较。
* Parameters : a-- 数组1
* b--数组2
* length--数组长度
* Returns : 两个数组相同返回1,否则返回0
*******************************************************************************/
LOCAL uint8 array_cmp(uint8 *a, uint8 *b, uint8 length)
{
uint8 i;
for(i = 0; i < length; i ++)
if(a[i]!=b[i]) return 0;//出现不相等元素,返回0.
return 1;//完全相等,返回1。
}
/******************************************************************************
* FunctionName : user_esp_platform_recon_cb
* Description : 连接有一个错误,并且已经被解除分配。
* Parameters : arg -- 传递给回调函数的附加参数
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_recon_cb(void *arg, sint8 err)//失败重连的回调函数
{
struct espconn *pespconn = (struct espconn *)arg;
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
os_printf("user_esp_platform_recon_cb\r\n");
os_timer_disarm(&client_timer);
os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn);//开启重连定时器
os_timer_arm(&client_timer, 1000, 0);
}
else return;
}
/****************************************************************************/
/******************************************************************************
* FunctionName : user_esp_platform_sent_cb
* Description : 数据已成功发送并被远程主机确认。
* Parameters : arg-传递给回调函数的附加参数
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_sent_cb(void *arg)成功发送网络数据的回调函数
{
struct espconn *pespconn = arg;
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
os_printf("user_esp_platform_sent_cb\r\n");
}
else return;
}
/******************************************************************************
* FunctionName : user_esp_platform_sent
* Description : 处理应用程序数据并将其发送到主机
* Parameters : pespconn -- 用于与主机连接的espconn。
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_sent(struct espconn *pespconn)
{
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
char buffer[1024];
memset(buffer,0,1024);
os_sprintf(buffer,get,"/v3/weather/now.json?language=en&key=smtq3n0ixdggurox&location=lingao&unit=c","api.seniverse.com");
os_printf("user_esp_platform_connect_cb\r\n");
espconn_send(pespconn,buffer,os_strlen(buffer));//发送get请求数据包
}
else return;
}
/******************************************************************************
* FunctionName : user_esp_platform_recv_cb
* Description : 处理从服务器接收的数据
* Parameters : arg -- 传递给回调函数的附加参数
* pusrdata -- 接收到的数据(或连接已关闭时为NULL)!
* length -- 接收数据的长度
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_recv_cb(void *arg,char *pdata,unsigned short len){//成功接收网络数据的回调函数
struct espconn *pespconn = arg;
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
if(pdata==NULL)
os_printf("Connection has been closed!\r\n");
else
os_printf("Data received:\r\n%s\r\n",pdata);//打印输出从服务器接收的数据
}
else return;
}
/******************************************************************************
* FunctionName : user_esp_platform_discon_cb
* Description : 成功断开与主机的连接
* Parameters : arg -- 传递给回调函数的附加参数
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_discon_cb(void *arg)// TCP 连接正常断开成功的回调函数
{
//该指针为 SDK 内部维护的指针,不同回调传入的指针地址可能不⼀样,请勿依此判断网络连接。可根据 espconn 结构体中的
//remote_ip、 remote_port 判断多连接中的不同网络传输
struct espconn *pespconn = arg;
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
os_printf("user_esp_platform_discon_cb\r\n");
}
else return;
}
/******************************************************************************
* FunctionName : user_esp_platform_connect_cb
* Description : 一个新的传入连接已被连接。
* Parameters : arg -- 传递给回调函数的附加参数
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_connect_cb(void *arg)//连接服务器成功的回调函数
{
//该指针为 SDK 内部维护的指针,不同回调传入的指针地址可能不⼀样,请勿依此判断网络连接。可根据 espconn 结构体中的
//remote_ip、 remote_port 判断多连接中的不同网络传输
struct espconn *pespconn = arg;
uint8 server_ip[4]={116,62,81,138};//远程ip地址
if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
espconn_regist_recvcb(pespconn, user_esp_platform_recv_cb);
espconn_regist_sentcb(pespconn, user_esp_platform_sent_cb);
espconn_regist_disconcb(pespconn, user_esp_platform_discon_cb);注册断开连接成功的回调函数
user_esp_platform_sent(pespconn);
}
else return;
}
/******************************************************************************
* FunctionName : user_esp_platform_connect
* Description : 作为与主机的连接而提供的函数。
* Parameters : espconn -- 用于连接的espconn
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_connect(struct espconn *pespconn)//tcp连接服务器的函数
{
os_printf("user_esp_platform_connect\r\n");
espconn_connect(pespconn);
}
/******************************************************************************
* FunctionName : user_esp_platform_dns_found
* Description : dns找到回调
* Parameters : name -- 指向查找的名称的指针
* ipaddr -- 指向包含主机名的IP地址的IP_addr_t的指针,如果找不到名称(或任何其他错误),则为NULL。
* callback_arg -- 用户指定的回调参数传递给dns_gethostbyname
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)//dns回调函数
{
struct espconn *pespconn = (struct espconn *)arg;
char str_buffer[40];
os_memset(str_buffer,'\0',40);
//解析成功才关闭client_timer定时器
if (ipaddr == NULL) {//如果解析失败,退出
os_printf("user_esp_platform_dns_found NULL\r\n");
return;
}
if (esp_server_ip.addr == 0 && ipaddr->addr != 0) {//解析成功
os_timer_disarm(&client_timer);//关闭dns_check定时器
//格式化字符串
os_sprintf(str_buffer,"[%s]parse_URL->%d.%d.%d.%d",name,*((uint8 *)&ipaddr->addr),
*((uint8 *)&ipaddr->addr+1),
*((uint8 *)&ipaddr->addr+2),
*((uint8 *)&ipaddr->addr+3));
os_printf("%s\n",str_buffer);//打印输出解析域名获得的ip地址
//初始化剩下的espconn参数
esp_server_ip.addr = ipaddr->addr;
os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr,4);//拷贝远程ip地址
pespconn->proto.tcp->local_port = espconn_port();//获取可用端口
pespconn->proto.tcp->remote_port = 80;//http默认的端口
//注册连接成功的回调函数
espconn_regist_connectcb(pespconn, user_esp_platform_connect_cb);
//注册 TCP连接发生异常断开时的回调函数,可以在回调函数中进行重连。
espconn_regist_reconcb(pespconn, user_esp_platform_recon_cb);
//tcp连接
user_esp_platform_connect(pespconn);
}
}
/******************************************************************************
* FunctionName : user_esp_platform_dns_check_cb
* Description : 1s检查dns找到的回调时间
* Parameters : arg -- 传递给回调函数的附加参数
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_dns_check_cb(void *arg)
{
struct espconn *pespconn = arg;
os_printf("user_esp_platform_dns_check_cb\n");
espconn_gethostbyname(pespconn,"api.seniverse.com", &esp_server_ip, user_esp_platform_dns_found);
os_timer_arm(&client_timer, 1000, 0);
}
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_start_dns(struct espconn *pespconn)
{
esp_server_ip.addr = 0;//全局变量
espconn_gethostbyname(pespconn,"api.seniverse.com", &esp_server_ip, user_esp_platform_dns_found);
os_timer_disarm(&client_timer);//开启client_timer定时器
os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_dns_check_cb, pespconn);
os_timer_arm(&client_timer, 1000, 0);
}
/******************************************************************************
* FunctionName : user_esp_platform_check_ip
* Description : 当获得ip地址后,初始化espconn结构体参数
* Parameters : none
* Returns : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_check_ip(void)
{
struct ip_info ipconfig;
os_timer_disarm(&client_timer);//关闭定时器
wifi_get_ip_info(STATION_IF, &ipconfig);//查询station接口所获取的ip地址
//已连接上路由器且station接口获取到了ip地址
if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) {
//初始化部分espconn参数
user_conn.proto.tcp = &user_tcp;
user_conn.type = ESPCONN_TCP;
user_conn.state = ESPCONN_NONE;
os_memcpy(user_conn.proto.tcp->local_ip, &ipconfig.ip.addr,4);//拷贝本地ip地址
user_esp_platform_start_dns(&user_conn);//dns开始解析
}
else {//重开定时器
os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL);
os_timer_arm(&client_timer, 100, 0);
}
}
LOCAL void ICACHE_FLASH_ATTR
user_set_station_config(void)//station接口配置
{
char ssid[32]="wifi名称";//接入网络的wifi名
char password[64]="wifi密码";//接入网络的密码
struct station_config stationConf;
stationConf.bssid_set=0;//无需检查AP的mac地址
os_memcpy(&stationConf.ssid,ssid,32);
os_memcpy(&stationConf.password,password,64);
wifi_station_set_config(&stationConf);
}
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_init(void){
os_timer_disarm(&client_timer);
os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL);
os_timer_arm(&client_timer, 100, 0);
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
//uart_init(115200,115200);
wifi_set_opmode (STATION_MODE);//station模式
user_set_station_config();//如果 wifi_station_set_config在 user_init中调用,则 ESP8266 Station接口会在系统初
//始化完成后,自动连接 AP(路由),无需再调用 wifi_station_connect
user_esp_platform_init();
}
void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
这里已经实现了json数据的获取,下一篇讲解如何使用官方json接口解析json数据。