hi3861芯片集成WiFi功能,鸿蒙是为了实现万物互联而设计的系统,所以系统内集成了完善的联网功能,只需根据需求调用系统功能就可以。
我自己归纳为2大部分:
第一步WiFi接入
1. 设备初始化,系统默认已经加载网络设备,就是知道有这个过程就好。
static int Wifi_Event_Init(void)
{
if(hi_wifi_config_callback(1, NULL, NULL) != HISI_OK)
{
return 0;
}
if(hi_wifi_register_event_callback(Wifi_Event_CD) != HISI_OK)
{
return 0;
}
return 1;
}
先检查,是否加载,没加载就加载一下,如果有问题返回0,添加回调,实时反馈网络状态信息。
2. 输入Wifi用户名密码,然后搜索,找到匹配的Wifi热点就连接。
static int WiFi_STA_Start(char *wifi_name, char *wifi_pass)
{
int sta_namlen = sizeof(sta_ifname);
if(hi_wifi_sta_start(sta_ifname, &sta_namlen) != HISI_OK)
{
return 0;
}
if(hi_wifi_sta_scan() != HISI_OK)
{
return 0;
}
while(wifi_state != 1)
{
osDelay(10);
}
unsigned int ap_num = 8;
unsigned int ap_info_len = sizeof(hi_wifi_ap_info) * ap_num;
hi_wifi_ap_info *ap_list = malloc(ap_info_len);
memset_s(ap_list, ap_info_len, 0, ap_info_len);
if(hi_wifi_sta_scan_results(ap_list, &ap_num) != HISI_OK)
{
return 0;
}
int idx;
for(idx = 0; idx < ap_num; idx ++)
{
if(strlen(wifi_name) == strlen(ap_list[idx].ssid))
{
if(memcmp(wifi_name, ap_list[idx].ssid, strlen(wifi_name)) == HISI_OK)
{
conn_ap = 1;
break;
}
}
}
if(conn_ap == 0)
{
free(ap_list);
return 0;
}
hi_wifi_assoc_request conn_req = {0};
memcpy_s(conn_req.ssid, (HI_WIFI_MAX_SSID_LEN + 1), wifi_name, strlen(wifi_name));
conn_req.auth = ap_list[idx].auth;
memcpy_s(conn_req.key, (HI_WIFI_MAX_KEY_LEN + 1), wifi_pass, strlen(wifi_pass));
memcpy_s(conn_req.bssid, HI_WIFI_MAC_LEN, ap_list[idx].bssid, strlen(ap_list[idx].bssid));
conn_req.pairwise = 0;
if(hi_wifi_sta_connect(&conn_req) != HISI_OK)
{
return 0;
}
while(wifi_state != 2)
{
osDelay(10);
}
free(ap_list);
return 1;
}
代码写的有点啰嗦,但是过程基本一步步都写到,等待系统反馈,接入成功就返回。
3.通过DHCP配置协议分配地址
static int WiFi_DHCP_Start(void)
{
wlan_netif = netifapi_netif_find(sta_ifname);
if (wlan_netif == NULL )
{
return 0;
}
if(netifapi_dhcp_start(wlan_netif) != ERR_OK)
{
return 0;
}
osDelay(200);
return 1;
}
这样就有了一个IP地址,就可以配置网络协议进行通信了。
第二步通过网络协议通信
常用的网络协议就是TCP / UDP,我采用的是TCP协议,让hi3861作为服务端,外部应用做为客户端连接hi3861, 这个方式主要是为了方便,hi3861运行中再设置参数很麻烦,不如就被动接入,用TCP协议发现发送没有被接收,可以认为客户端以断开,就可以关闭网络,或者重启网络。
TCP/IP协议都是标准的流程。
创建服务端套接字
int TCP_Server_Socket(char *server_ip, unsigned short server_port)
{
int ret = 0;
int server_sock = -1;
server_sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
if(server_sock < 0)
{
return -1;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
server_addr.sin_addr.s_addr = inet_addr(server_ip);
ret = lwip_bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret < 0)
{
return -1;
}
ret = lwip_listen(server_sock, 1);
if(ret < 0)
{
return -1;
}
return server_sock;
}
接入客户端,这个步骤是阻塞的,一直等待有客户端接入,才进行后面的操作。
int TCP_Server_Accept(int server_sock, char *client_ip, unsigned short *client_port)
{
int client_sock = -1;
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
socklen_t addr_len = sizeof(client_addr);
client_sock = lwip_accept(server_sock, (struct sockaddr *)&client_addr, &addr_len);
if(client_sock < 0)
{
return -1;
}
*client_port = ntohs(client_addr.sin_port);
memset(client_ip, 0, sizeof(client_ip));
strcpy(client_ip, inet_ntoa(client_addr.sin_addr));
return client_sock;
}
接通后就是收发通信
int TCP_Recv_Nonblocking(int client_sock, unsigned char *recv_buff, size_t buff_size)
{
int len;
len = lwip_recv(client_sock, recv_buff, buff_size, MSG_DONTWAIT);
if(len < 0)
{
return -1;
}
return len;
}
int TCP_Send(int client_sock, unsigned char *send_buff, size_t buff_size)
{
int ret;
ret = lwip_send(client_sock, send_buff, buff_size, 0);
if(ret < 0)
{
return -1;
}
return ret;
}
接收是非阻塞模式,每次检查是否有信息输入,如果没有就跳过。
这样一个完整的网络应用就完成了。实际使用还要考虑使用的易用性。
比如接入WIFI,调试中可以把WiFi的用户名密码写在代码里,但是改变环境,如果在使用中输入用户名密码呢?我知道有2种方式,一种是先将Hi3861自己设置为热点,通过手机或者其他设备访问hi3861,进行通信输入用户名密码,然后再将hi3861切换到站点模式连接WiFi。还有一种很方便的是碰一碰外设来输入用户名密码,或者是串口方式。
我做了一个通过红外遥控器输入的方法。
通过输入ASCII码来输入内容。
主菜单:
因为屏幕太小了,为了尽量显示大一点字体,一行只能显示16个字符,所以都是简写,简的只有我自己能看懂吧。
[1] 输入用户名密码 [2] 连接网络 [3] 网络通信 [4] 网络关闭
这是输入页,按数字输入ASCII码,显示相应的字符,插入到数组里。
觉得这个功能也许有些场合能用上,实现过程挺碎的,如果代码看不懂,就加我QQ:1164192255,也许能交换出更好的方法。
主要函数:
hi_void Device_Init(hi_void);
int WiFi_Conn_Start(char *wifi_name, char *wifi_pass, char *ip_str);
void Wifi_Conn_Stop(void);
int TCP_Server_Socket(char *server_ip, unsigned short server_port);
int TCP_Server_Accept(int server_sock, char *client_ip, unsigned short *client_port);
int TCP_Recv(int client_sock, unsigned char *recv_buff, size_t buff_size);
int TCP_Recv_Nonblocking(int client_sock, unsigned char *recv_buff, size_t buff_size);
int TCP_Send(int client_sock, unsigned char *send_buff, size_t buff_size);
int UDP_Socket(int udp_port, char *udp_ip);
int UDP_Recvfrom(int udp_sock, unsigned char *recv_buff, size_t buff_size, int *client_port, char *client_ip);
int UDP_Sendto(int udp_sock, unsigned char *send_buff, size_t buff_size, int client_port, char *client_ip);
void Socket_Close(int *sock);
// 网络连接
hi_u8 Network_Connection(hi_void);
// 网络关闭
hi_u8 Network_Close(hi_void);
// 发送数据
hi_u8 Send_Data(hi_void);
// 接收数据
hi_u8 Recv_Data(hi_void);
// 返回 用户名 和 密码
hi_void Get_Name_Pass(char *n, char *p);
// 红外 控制
hi_u8 RC_Control(hi_u8 val);
// 显示
hi_void Display_Menu(hi_u8 n);
按键设置:
先写到这。