该章节主要为ESP8266方面的应用程序

一.ESP8266连接AP

int esp8266_connect_ap(char *ssid, char *passwd)
{
	PAT_Device ptDev = get_esp8266_device();
  if(NULL == ptDev)
		return -1;
	
	char cmd[128];
	char *fix_cmd = NULL;
	
	//设置WiFi模式为STA
	fix_cmd = "AT+CWMODE=1\r\n";
	if(at_exec_cmd(ptDev, (int8_t *)fix_cmd, NULL, 0, NULL, AT_TIMEOUT))
		return -1;

	//连接AP
	if(passwd)
	{
		snprintf((char *)cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, passwd);
	}
	else
	{
		snprintf((char *)cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"\"\r\n", ssid);
	}
	if(at_exec_cmd(ptDev,(int8_t *)cmd, NULL, 0, NULL, 5000))    // 5秒超时
		return -1;

	//查询IP地址(可选)
	fix_cmd = "AT+CIFSR\r\n";
	if(at_exec_cmd(ptDev, (int8_t *)fix_cmd, NULL, 0, NULL, AT_TIMEOUT))
		return -1;
 
	//执行: AT+GMR(可选)
//	fix_cmd = "AT+GMR\r\n";
//	if(at_exec_cmd(ptDev, (int8_t *)fix_cmd, NULL, 0, NULL, AT_TIMEOUT))
//		return -1;

  //执行: AT+CIPRECVMODE=0 接收数据的模式
	fix_cmd = "AT+CIPRECVMODE=0\r\n";
	if(at_exec_cmd(ptDev, (int8_t *)fix_cmd, NULL, 0, NULL, AT_TIMEOUT))
		return -1;
    
  return 0;
}

二.ESP8266作为server监听(TCP连接)

//esp8266作为server监听(TCP连接)
//backlog对ESP8266来说最大支持4个连接
int esp8266_listen(int socket, int backlog)
{
	PAT_Device ptDev = get_esp8266_device();
	if(NULL == ptDev)
		return -1;
	if(socket < 0 || socket > AT_MAX_SOCKETS_NUM)
		return -1;
	PAT_Socket ptSocket = &ptDev->sockets[socket];
	
	char cmd[32];
			
	//执行: AT+CIPMUX=1\r\n  使能多连接
	if(at_exec_cmd(ptDev, (int8_t *)"AT+CIPMUX=1\r\n", NULL, 0, NULL, AT_TIMEOUT))
		return -1;
	
	//执行: AT+CIPSERVERMAXCONN=4\r\n  允许4个连接
	sprintf(cmd, "AT+CIPSERVERMAXCONN=%d\r\n", backlog);
	if(at_exec_cmd(ptDev, (int8_t *)cmd, NULL, 0, NULL, AT_TIMEOUT))
		return -1;

	//执行: AT+CIPSERVER=1,8888  建立服务器监听端口
	//获取到端口号
	char cmdbuf[32];
	struct sockaddr_in *ptAddr = (struct sockaddr_in *)&ptSocket->local;
	uint16_t port = ntohs(ptAddr->sin_port);
	sprintf(cmdbuf, "AT+CIPSERVER=1,%d\r\n", port);
	if(at_exec_cmd(ptDev, (int8_t *)cmdbuf, NULL, 0, NULL, AT_TIMEOUT))
		return -1;

	return 0;	
}

三.ESP8266作为server被client连接(TCP连接)

//esp8266作为server被client连接(TCP连接)
//配置client的socket信息
int esp8266_accept(int socket, struct sockaddr *name, socklen_t *namelen)
{
	PAT_Device ptDev = get_esp8266_device();
	if(NULL == ptDev)
		return -1;
	if(socket < 0 || socket > AT_MAX_SOCKETS_NUM)
		return -1;
	if(NULL == name)
		return -1;
	
	PAT_Socket ptSocket = &ptDev->sockets[socket]; 
	//获得锁
	xSemaphoreTake(ptSocket->at_send_lock, portMAX_DELAY);
	
	//执行: AT+CIPSTATUS 查询网络连接信息
  char *cmd = "AT+CIPSTATUS\r\n";
	if(at_exec_cmd(ptDev, (int8_t *)cmd, NULL, 0, NULL, AT_TIMEOUT))
	{
		//释放锁
		xSemaphoreGive(ptSocket->at_send_lock);
		return -1;
	}
	
	struct sockaddr_in *ptAddr = (struct sockaddr_in *)&ptSocket->local;
	uint16_t server_port = ntohs(ptAddr->sin_port);
	
	//解析接收到的数据AT结构里的resp
	//STATUS:<stat>
	//+CIPSTATUS:<link ID>,<type>,<remote	IP>,<remote	port>,<local port>,<tetype>	
	if(ptDev->resp_line_counts >= 2) //跳过第1行
	{
		for(int i=1; i<ptDev->resp_line_counts && i <AT_RESP_MAX_LINE; i++)
		{
			uint8_t *line = ptDev->resp[i];							//指向当前行(每行以'\0'结尾)
			if(strstr((char *)line, "+CIPSTATUS:"))			//做对比
			{
				//解析格式: +CIPSTATUS:<link ID>,<type>,<remote IP>,<remote port>,<local port>,<tetype>
				int hw_socket;
				uint16_t recv_socket=0;                				
				char type[10] = {0};
				uint8_t remote_ip[32] = {0};
				uint16_t  remote_ip_len=0;
				uint16_t remote_port;
				uint16_t local_port;
				int tetype;
			
				int parsed = sscanf((const char *)line, "+CIPSTATUS:%hu,%9[^,],\"%31[^,],%hu,%hu,%d",
													(uint16_t *)&recv_socket, type, remote_ip, &remote_port, &local_port, &tetype);
				if(parsed == 6)
				{
					hw_socket = recv_socket;
					if(get_socket_for_hw_socket(hw_socket) != NULL)			//找到一个used为1,但是uaser_data不为hw_socket的socket。(已创建,但未连接)
					{																										//没找到的话,创建一个新的硬件socket,并填充			
						continue;
					}
          if(local_port != server_port)
					{
						continue;
					} 
					
					//新分配设置socket结构体,来填充返回的hw_socket结构	
					int sw_socket = esp8266_socket(AF_INET, SOCK_STREAM, 0);
					if(sw_socket < 0 || sw_socket > AT_DEVICE_SOCKETS_NUM)
					{
						return -1;
					}
					PAT_Socket ptSocket2 = &ptDev->sockets[sw_socket];
					ptSocket2->user_data = (void *)hw_socket;          
					ptSocket2->at_socket_open_flag=1;                    
			
					struct sockaddr_in *addr = (struct sockaddr_in *)name;
					addr->sin_family = AF_INET;																	//协议
					addr->sin_port = htons(remote_port);												//端口
					remote_ip_len = strlen((char *)remote_ip);
					if(remote_ip_len <=32)
          {
						remote_ip[remote_ip_len-1] =0;
						remote_ip[remote_ip_len] =0;
					}          
          inet_pton(AF_INET, (char *)remote_ip, &addr->sin_addr);			//ip
					if(namelen)
					{
						*namelen = sizeof(struct sockaddr_in);
					}
					
					ptSocket2->remote =(*((struct sockaddr*)addr));
					
					addr = (struct sockaddr_in *)&ptSocket->local;						//指向local,修改server端port
					addr->sin_family = AF_INET;  
					addr->sin_port = htons(local_port);
					
					//释放锁
					xSemaphoreGive(ptSocket->at_send_lock);
					at_reset_resp(ptDev);
					return sw_socket;  // 返回链接ID作为socket描述符
				}
			}
		}
	}
	//释放锁
	xSemaphoreGive(ptSocket->at_send_lock);
	return -1;  // 解析失败或无连接
}

四.ESP8266作为client去连接server端(TCP/UDP连接)

//esp8266作为client去连接server端(TCP连接)
//esp8266发送at命令去连接(UDP连接)
//AT+CIPSTART=<link ID>,<type>,<remote IP>,<remote port>[,<TCP keep alive>]
int esp8266_connect(int socket, const struct sockaddr *name, socklen_t namelen)
{
	PAT_Device ptDev = get_esp8266_device();
	if(NULL == ptDev)
		return -1;
	if(socket < 0 || socket > AT_MAX_SOCKETS_NUM)
		return -1;
	if(NULL == name)
		return -1;
	
	PAT_Socket ptSocket = &ptDev->sockets[socket]; 
	int link_id = 0;
	
	//作为client去连接server,link_id只有1个无所谓,我分配他索引值
	if(socket > AT_DEVICE_SOCKETS_NUM)
	{
		link_id = AT_MAX_SOCKETS_NUM;
	}
	else
	{
		link_id = socket;
		if(link_id < 0)
		{
			// 释放锁
			xSemaphoreGive(ptSocket->at_send_lock);
			return -1;
		}
	}
	
	//转化一下remote的ip和port
	struct sockaddr_in *ptAddr = (struct sockaddr_in *)name;
	uint16_t remote_port = ntohs(ptAddr->sin_port);		//remote port
	uint16_t local_port = 0;
	
	if(ptSocket->type == SOCK_DGRAM)
	{
		struct sockaddr_in *local = (struct sockaddr_in *)&ptSocket->local;
		local_port = ntohs(local->sin_port);	//local port
	}
  
	char cmd[64] = {0};
	char *ipstr;
	ipaddr_to_ipstr(name, ipstr);   //remote ip
	//发送指令
	if(ptSocket->type == SOCK_STREAM)		//TCP
	{
		sprintf(cmd, "AT+CIPSTART=%d,\"%s\",\"%s\",%d\r\n", link_id, "TCP", ipstr, remote_port);
	}
	else if(ptSocket->type == SOCK_DGRAM)		//UDP
	{
		sprintf(cmd, "AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d\r\n", link_id, "UDP", ipstr, remote_port, local_port);
	}
	if(at_exec_cmd(ptDev, (int8_t *)cmd, NULL, 0, NULL, AT_TIMEOUT))
	{
		// 释放锁
		xSemaphoreGive(ptSocket->at_send_lock);
		return -1;
	}	
	
	ptSocket->user_data = (void *)link_id;//socket id赋值
  ptSocket->at_socket_open_flag=1;
	
	// 释放锁
	xSemaphoreGive(ptSocket->at_send_lock);
	return 0;		
}

五.ESP8266连接上后发送指令

//esp8266连接上发送指令: AT+CIPSEND=<link ID>,<length>(TCP连接)
//esp8266连接上发送指令: AT+CIPSEND=[<link ID>,]<length>[,<remote IP>,<remote port>](UDP连接)
int esp8266_sendto(int socket, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
{
// 对于TCP连接: AT+CIPSEND=<link ID>,<length>
// 对于UDP:     AT+CIPSEND=[<link ID>,]<length>[,<remote IP>,<remote port>]
	PAT_Device ptDev = get_esp8266_device();
	if(NULL == ptDev)
		return -1;
	if(socket < 0 || socket > AT_MAX_SOCKETS_NUM)
		return -1;
	if(NULL == data)
		return -1;

	PAT_Socket ptSocket = &ptDev->sockets[socket];
	char cmd[64] = {0};
	
	int hw_socket = ((int)(ptSocket->user_data));
  if(hw_socket < 0 || hw_socket > AT_MAX_SOCKETS_NUM || size==0)
		return -1;
    
	// 获得锁
	xSemaphoreTake(ptSocket->at_send_lock, portMAX_DELAY);
    
	if(ptSocket->type == SOCK_STREAM)
	{
		sprintf(cmd, "AT+CIPSENDEX=%d,%d\r\n", hw_socket, size);
	}
	else if(ptSocket->type == SOCK_DGRAM && to != NULL)
	{
		char ipstr[32] = {0};
		struct sockaddr_in *paddr = (struct sockaddr_in *)to;
		uint16_t port = ntohs(paddr->sin_port);
		ipaddr_to_ipstr((const struct sockaddr *)paddr, ipstr);
		
		sprintf((char *)cmd, "AT+CIPSENDEX=%d,%d,\"%s\",%d\r\n", hw_socket, size, ipstr, port);
	}
	else
	{
		// 释放锁
		xSemaphoreGive(ptSocket->at_send_lock);
		return -1;
	}

	//发送AT命令
	at_exec_cmd(ptDev, (int8_t *)cmd, NULL, 0, NULL, (AT_TIMEOUT));
	osDelay(30);
  
  if(at_send_datas(ptDev,(uint8_t *)data, size, (AT_TIMEOUT)))
	{
		//释放锁
		xSemaphoreGive(ptSocket->at_send_lock);
		return -1;
	}
  
	// 释放锁
	xSemaphoreGive(ptSocket->at_send_lock);
	return 0;
}

六.ESP8266连接上后接收数据(TCP/UDP连接)

//esp8266连接上后接收数据(TCP/UDP连接)
int esp8266_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
	PAT_Device ptDev = get_esp8266_device();
	if(NULL == ptDev)
		return -1;
	if(socket < 0 || socket > AT_MAX_SOCKETS_NUM)
		return -1;
	if(NULL == mem)
		return -1;

	PAT_Socket ptSocket = &ptDev->sockets[socket];
   
	uint8_t data;
	size_t recv_len = 0;
	uint8_t *pdata = (uint8_t *)mem;
   
	//对于UDP,先发起AT命令来连接
	if((ptSocket->type == SOCK_DGRAM) && (from != NULL))
	{
		if(ptSocket->at_socket_open_flag==0)
		{
			if(esp8266_connect(socket, from, *fromlen))
			{
				return -1;
			}
		}
	}
 
	//尝试从接收队列读取遗留的数据
	while(xQueueReceive(ptSocket->recv_queue, &data, 0) == pdTRUE)
	{
		if(recv_len < len)
		{
			pdata[recv_len] = data;
		}    
    recv_len++;
     
		if(recv_len >= len)
		{
			return recv_len;
		}
	}
  
  if(recv_len > 0)
	{
		return recv_len;
	}
	//无数据则等待信号量
	if(xSemaphoreTake(ptSocket->at_packet_sem, portMAX_DELAY) != pdTRUE)
	{
		return -1;
	}
	//再次尝试从接收队列读取数据
	while(xQueueReceive(ptSocket->recv_queue, &data, 0) == pdTRUE)
	{
		if(recv_len < len)
		{
			pdata[recv_len] = data;
		}
		recv_len++;
		if(recv_len >= len)
		{
			return recv_len;
		}
	}
	return recv_len; 
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐