243 lines
8.5 KiB
C
243 lines
8.5 KiB
C
#include <stdio.h> // 标准输入输出
|
||
#include <unistd.h> // POSIX标准接口
|
||
#include <errno.h> // 错误码
|
||
#include <string.h> // 字符串处理(操作字符数组)
|
||
|
||
#include "lwip/sockets.h" // lwIP TCP/IP协议栈:Socket API
|
||
#include "ohos_init.h" // 用于初始化服务(services)和功能(features)
|
||
#include "cmsis_os2.h" // CMSIS-RTOS API V2
|
||
#include "oled_ssd1306.h"
|
||
#include "json_parser.h" // JSON解析器
|
||
#include "wifi_connecter.h" // WiFi连接器
|
||
|
||
|
||
|
||
extern int control_flag ;
|
||
|
||
// 要发送的数据
|
||
static char request[] = "connecting";
|
||
|
||
// 要接收的数据
|
||
char response[128] = "";
|
||
|
||
// 全局变量存储解析后的命令
|
||
JsonCommand g_current_command = {0};
|
||
|
||
// 发送IP地址到服务器
|
||
void SendIpToServer(const char *host, unsigned short port) {
|
||
char ip_buffer[32] = {0};
|
||
char message_buffer[128] = {0};
|
||
|
||
// 获取本机IP地址
|
||
if (GetLocalIpAddress(ip_buffer, sizeof(ip_buffer)) != 0) {
|
||
printf("Failed to get local IP address\r\n");
|
||
return;
|
||
}
|
||
|
||
// 创建IP消息
|
||
if (CreateIpMessage(message_buffer, sizeof(message_buffer), ip_buffer) != 0) {
|
||
printf("Failed to create IP message\r\n");
|
||
return;
|
||
}
|
||
|
||
// 创建UDP socket
|
||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
if (sockfd < 0) {
|
||
printf("Failed to create socket\r\n");
|
||
return;
|
||
}
|
||
|
||
struct sockaddr_in toAddr = {0};
|
||
toAddr.sin_family = AF_INET;
|
||
toAddr.sin_port = htons(port);
|
||
|
||
if (inet_pton(AF_INET, host, &toAddr.sin_addr) <= 0) {
|
||
printf("inet_pton failed!\r\n");
|
||
lwip_close(sockfd);
|
||
return;
|
||
}
|
||
|
||
// 发送IP地址消息
|
||
ssize_t retval = sendto(sockfd, message_buffer, strlen(message_buffer), 0,
|
||
(struct sockaddr *)&toAddr, sizeof(toAddr));
|
||
|
||
if (retval < 0) {
|
||
printf("Failed to send IP message!\r\n");
|
||
} else {
|
||
printf("IP message sent: %s\r\n", message_buffer);
|
||
}
|
||
|
||
lwip_close(sockfd);
|
||
}
|
||
|
||
/// @brief UDP客户端测试函数
|
||
/// @param host UDP服务端IP地址
|
||
/// @param port UDP服务端端口
|
||
void UdpClientTest(const char *host, unsigned short port)
|
||
{
|
||
// 用于接收Socket API接口返回值
|
||
ssize_t retval = 0;
|
||
// 创建一个UDP Socket,返回值为文件描述符
|
||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
if (sockfd < 0) {
|
||
printf("创建socket失败!\r\n");
|
||
return;
|
||
}
|
||
|
||
// 用于设置服务端的地址信息
|
||
struct sockaddr_in toAddr = {0};
|
||
// 用于设置本地绑定的地址信息
|
||
struct sockaddr_in localAddr = {0};
|
||
|
||
// 使用IPv4协议
|
||
toAddr.sin_family = AF_INET;
|
||
localAddr.sin_family = AF_INET;
|
||
|
||
// 端口号,从主机字节序转为网络字节序
|
||
toAddr.sin_port = htons(port);
|
||
localAddr.sin_port = htons(port); // 绑定到相同端口接收数据
|
||
localAddr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用的网络接口
|
||
|
||
// 将服务端IP地址从"点分十进制"字符串,转化为标准格式(32位整数)
|
||
if (inet_pton(AF_INET, host, &toAddr.sin_addr) <= 0)
|
||
{
|
||
// 转化失败
|
||
printf("inet_pton failed!\r\n"); // 输出日志
|
||
lwip_close(sockfd);
|
||
return;
|
||
}
|
||
|
||
// 绑定本地端口,这样才能接收数据
|
||
printf("绑定本地端口 %d...\r\n", port);
|
||
if (bind(sockfd, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
|
||
printf("绑定端口失败!错误: %d\r\n", errno);
|
||
lwip_close(sockfd);
|
||
return;
|
||
}
|
||
printf("端口绑定成功!\r\n");
|
||
|
||
// 发送设备IP地址到服务器
|
||
SendIpToServer(sockfd, &toAddr);
|
||
|
||
// 发送数据
|
||
// UDP socket是 "无连接的",因此每次发送都必须先指定目标主机和端口,主机可以是多播地址
|
||
// 发送数据的时候,使用本地随机端口N
|
||
//
|
||
// 参数:
|
||
// s:socket文件描述符
|
||
// dataptr:要发送的数据
|
||
// size:要发送的数据的长度,最大65332字节
|
||
// flags:消息传输标志位
|
||
// to:目标的地址信息
|
||
// tolen:目标的地址信息长度
|
||
//
|
||
// 返回值:
|
||
// 发送的字节数,如果出错,返回-1
|
||
printf("发送连接消息到服务器...\r\n");
|
||
retval = sendto(sockfd, request, sizeof(request), 0, (struct sockaddr *)&toAddr, sizeof(toAddr));
|
||
|
||
// 检查接口返回值,小于0表示发送失败
|
||
if (retval < 0)
|
||
{
|
||
// 发送失败
|
||
printf("发送消息失败!错误: %d\r\n", errno); // 输出日志
|
||
lwip_close(sockfd);
|
||
return;
|
||
}
|
||
|
||
// 发送成功
|
||
// 输出日志
|
||
printf("发送UDP消息成功: {%s} %ld 字节\r\n", request, retval);
|
||
|
||
// 显示等待接收状态
|
||
printf("开始监听UDP消息,等待来自 %s 的数据...\r\n", host);
|
||
|
||
// 用于记录发送方的地址信息(IP地址和端口号)
|
||
struct sockaddr_in fromAddr = {0};
|
||
|
||
// 用于记录发送方的地址信息长度
|
||
socklen_t fromLen = sizeof(fromAddr);
|
||
|
||
// 在本地随机端口N上面接收数据
|
||
// UDP socket是 “无连接的”,因此每次接收时并不知道消息来自何处,通过fromAddr参数可以得到发送方的信息(主机、端口号)
|
||
// device\hisilicon\hispark_pegasus\sdk_liteos\third_party\lwip_sack\include\lwip\sockets.h -> lwip_recvfrom
|
||
//
|
||
// 参数:
|
||
// s:socket文件描述符
|
||
// buffer:接收数据的缓冲区的地址
|
||
// length:接收数据的缓冲区的长度
|
||
// flags:消息接收标志位
|
||
// address:发送方的地址信息
|
||
// address_len:发送方的地址信息长度
|
||
//
|
||
// 返回值:
|
||
// 接收的字节数,如果出错,返回-1
|
||
while (1)
|
||
{
|
||
// 清空接收缓冲区
|
||
memset(response, 0, sizeof(response));
|
||
|
||
retval = lwip_recvfrom(sockfd, response, sizeof(response) - 1, 0, (struct sockaddr *)&fromAddr, &fromLen);
|
||
|
||
// 检查接口返回值,小于0表示接收失败
|
||
if (retval <= 0)
|
||
{
|
||
// 接收失败,或者收到0长度的数据(忽略掉)
|
||
printf("recvfrom failed or abort, %ld, %d!\r\n", retval, errno); // 输出日志
|
||
continue; // 继续接收,不要关闭socket
|
||
}
|
||
|
||
// 接收成功
|
||
// 末尾添加字符串结束符'\0',以便后续的字符串操作
|
||
response[retval] = '\0';
|
||
|
||
// 输出日志 - 显示所有收到的消息
|
||
printf("=== 收到UDP消息 ===\r\n");
|
||
printf("消息内容: {%s}\r\n", response);
|
||
printf("消息长度: %ld 字节\r\n", retval);
|
||
printf("发送方IP: %s\r\n", inet_ntoa(fromAddr.sin_addr));
|
||
printf("发送方端口: %d\r\n", ntohs(fromAddr.sin_port));
|
||
printf("==================\r\n");
|
||
|
||
// 尝试解析JSON命令
|
||
JsonCommand temp_cmd = {0};
|
||
if (ParseJsonCommand(response, &temp_cmd) == 0) {
|
||
printf("JSON解析成功: cmd=%d, text=%s\r\n", temp_cmd.cmd, temp_cmd.text);
|
||
|
||
// 保存解析的命令
|
||
g_current_command = temp_cmd;
|
||
|
||
// 根据命令类型设置控制标志
|
||
if (temp_cmd.cmd >= 1 && temp_cmd.cmd <= 4) {
|
||
control_flag = temp_cmd.cmd;
|
||
printf("设置控制标志为: %d\r\n", control_flag);
|
||
} else {
|
||
printf("无效的命令类型: %d\r\n", temp_cmd.cmd);
|
||
}
|
||
} else {
|
||
printf("JSON解析失败,尝试旧格式命令\r\n");
|
||
|
||
// 兼容旧的字符串命令格式
|
||
if(strlen(response) > 10) {
|
||
control_flag = 2;
|
||
g_current_command.cmd = 0; // 标记为旧命令
|
||
printf("设置为复杂字符串命令,控制标志: %d\r\n", control_flag);
|
||
} else if(strcmp(response,"T:on") == 0) {
|
||
control_flag = 1;
|
||
g_current_command.cmd = 0; // 标记为旧命令
|
||
printf("设置为开启命令,控制标志: %d\r\n", control_flag);
|
||
} else if(strcmp(response,"T:off") == 0) {
|
||
control_flag = 0;
|
||
g_current_command.cmd = 0; // 标记为旧命令
|
||
printf("设置为关闭命令,控制标志: %d\r\n", control_flag);
|
||
} else {
|
||
printf("未识别的命令格式: %s\r\n", response);
|
||
}
|
||
}
|
||
|
||
sleep(1);
|
||
}
|
||
// 关闭socket
|
||
lwip_close(sockfd);
|
||
}
|