/*********************************************************************************************************************
* STC32G144K Opensourec Library 即(STC32G144K 开源库)是一个基于官方 SDK 接口的第三方开源库
* Copyright (c) 2025 SEEKFREE 逐飞科技
*
* 本文件是STC32G144K开源库的一部分
*
* STC32G144K 开源库 是免费软件
* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款
* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它
*
* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证
* 甚至没有隐含的适销性或适合特定用途的保证
* 更多细节请参见 GPL
*
* 您应该在收到本开源库的同时收到一份 GPL 的副本
* 如果没有,请参阅<https://www.gnu.org/licenses/>
*
* 额外注明:
* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本
* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中
* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件
* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明)
*
* 文件名称
* 公司名称 成都逐飞科技有限公司
* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明
* 开发环境 MDK FOR C251
* 适用平台 STC32G144K
* 店铺链接 https://seekfree.taobao.com/
*
* 修改记录
* 日期 作者 备注
* 2025-11-20 大W first version
********************************************************************************************************************/
/*********************************************************************************************************************
* 接线定义:
* ------------------------------------
* 模块管脚 单片机管脚
* RST 查看 zf_device_wifi_spi.h 中 WIFI_SPI_RST_PIN 宏定义
* INT 查看 zf_device_wifi_spi.h 中 WIFI_SPI_INT_PIN 宏定义
* CS 查看 zf_device_wifi_spi.h 中 WIFI_SPI_CS_PIN 宏定义
* MISO 查看 zf_device_wifi_spi.h 中 WIFI_SPI_MISO_PIN 宏定义
* SCK 查看 zf_device_wifi_spi.h 中 WIFI_SPI_SCK_PIN 宏定义
* MOSI 查看 zf_device_wifi_spi.h 中 WIFI_SPI_MOSI_PIN 宏定义
* 5V 5V 电源
* GND 电源地
* 其余引脚悬空
* ------------------------------------
*********************************************************************************************************************/
#include "stdio.h"
#include "zf_common_clock.h"
#include "zf_common_debug.h"
#include "zf_common_fifo.h"
#include "zf_driver_delay.h"
#include "zf_driver_gpio.h"
#include "zf_driver_spi.h"
#include "zf_device_type.h"
#include "zf_device_wifi_spi.h"
#define WIFI_CONNECT_TIME_OUT 10000 // 单位毫秒
#define SOCKET_CONNECT_TIME_OUT 50000 // 单位毫秒
#define OTHER_TIME_OUT 1000 // 单位毫秒
#if ((WIFI_SPI_RECVIVE_SIZE < 32) || (WIFI_SPI_RECVIVE_SIZE > 4088))
#error "WIFI_SPI_RECVIVE_SIZE must be >= 32 or <= 4088"
#endif
#if (WIFI_SPI_RECVIVE_SIZE >= WIFI_SPI_RECVIVE_FIFO_SIZE)
#error "WIFI_SPI_RECVIVE_FIFO_SIZE must be > WIFI_SPI_RECVIVE_SIZE"
#endif
#if (WIFI_SPI_TRANSFER_SIZE != 4088)
#error "WIFI_SPI_TRANSFER_SIZE must be == 4088"
#endif
char wifi_spi_version[12] = {0}; // 保存模块固件版本信息
char wifi_spi_mac_addr[20] = {0}; // 保存模块MAC地址信息
char wifi_spi_ip_addr_port[25] = {0}; // 保存模块IP地址与端口信息
static fifo_struct wifi_spi_fifo = {0};
static uint8 wifi_spi_buffer[WIFI_SPI_RECVIVE_FIFO_SIZE] = {0};
static volatile wifi_spi_state_enum wifi_spi_mutex = {0};
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 等待WIFI SPI就绪
// 参数说明 wait_time 最大等待时间 单位毫秒
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_wait_idle (uint32 wait_time)
{
uint32 time = 0;
uint8 level;
wait_time = wait_time*100;
while(1)
{
level = gpio_get_level(WIFI_SPI_INT_PIN);
if(level)
break;
system_delay_us(10);
time++;
if(wait_time <= time)
{
printf("[wifi_spi] wait_idle timeout, level=%d\r\n", level);
break;
}
}
return (wait_time <= time);
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 写入数据到WIFI SPI
// 参数说明 *buffer1 第一组需要发送的数据缓冲区地址
// 参数说明 length1 第一组数据长度
// 参数说明 *buffer2 第二组需要发送的数据缓冲区地址
// 参数说明 length2 第二组数据长度
// 返回参数 void
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static void wifi_spi_dma_write (const uint8 *buffer1, uint16 length1, const uint8 *buffer2, uint16 length2)
{
WIFI_SPI_CS(0);
if(NULL != buffer1)
{
spi_dma_write_8bit_array(WIFI_SPI_INDEX, buffer1, length1);
}
if(NULL != buffer2)
{
spi_dma_write_8bit_array(WIFI_SPI_INDEX, buffer2, length2);
}
WIFI_SPI_CS(1);
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 发送与接收同时进行(命令收发)
// 参数说明 *packets 发送与接收的地址
// 参数说明 length 需要接收的长度
// 返回参数 void
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static void wifi_spi_dma_transfer_command (wifi_spi_packets_struct *packets, uint16 length)
{
WIFI_SPI_CS(0);
spi_dma_transfer_8bit(WIFI_SPI_INDEX, (uint8 *)&(packets->head), (uint8 *)&(packets->head), sizeof(wifi_spi_head_struct));
if(length)
{
spi_dma_transfer_8bit(WIFI_SPI_INDEX, (const uint8 *)(packets->buffer), packets->buffer, length);
}
// 大小端不一致,高低字节交换
packets->head.length = (uint16)((packets->head.length&0xFF) << 8) | ((packets->head.length >> 8) & 0xFF);
WIFI_SPI_CS(1);
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 发送与接收同时进行(数据收发)
// 参数说明 *write_data 发送的数据缓冲区地址
// 参数说明 *read_data 接收到的数据的存储地址
// 参数说明 length 需要接收的长度
// 返回参数 void
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static void wifi_spi_dma_transfer_data (const uint8 *write_data, wifi_spi_packets_struct *read_data, uint16 length)
{
WIFI_SPI_CS(0);
read_data->head.command = WIFI_SPI_DATA;
// 大小端不一致,高低字节交换
read_data->head.length = (uint16)((length&0xFF) << 8) | ((length >> 8) & 0xFF);;
spi_dma_transfer_8bit(WIFI_SPI_INDEX, (uint8 *)&(read_data->head), (uint8 *)&(read_data->head), sizeof(wifi_spi_head_struct));
if(WIFI_SPI_RECVIVE_SIZE < length)
{
spi_dma_transfer_8bit(WIFI_SPI_INDEX, write_data, read_data->buffer, WIFI_SPI_RECVIVE_SIZE);
spi_dma_write_8bit_array(WIFI_SPI_INDEX, &write_data[WIFI_SPI_RECVIVE_SIZE], length - WIFI_SPI_RECVIVE_SIZE);
}
else
{
// 将需要发送的数据拷贝到读取缓冲区,避免出现write_data越界访问
memcpy(read_data->buffer, write_data, length);
spi_dma_transfer_8bit(WIFI_SPI_INDEX, read_data->buffer, read_data->buffer, WIFI_SPI_RECVIVE_SIZE);
}
// 大小端不一致,高低字节交换
read_data->head.length = (uint16)((read_data->head.length&0xFF) << 8) | ((read_data->head.length >> 8) & 0xFF);
WIFI_SPI_CS(1);
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 参数设置
// 参数说明 command 命令类型
// 参数说明 *buffer 参数地址
// 参数说明 length 参数长度
// 参数说明 wait_time 最大等待时间 单位100微妙
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_set_parameter (wifi_spi_packets_command_enum command, uint8 *buffer, uint16 length, uint32 wait_time)
{
uint8 return_state;
wifi_spi_head_struct head;
return_state = 1;
printf("[wifi_spi] set_parameter start, cmd=0x%02X, len=%d\r\n", command, length);
do
{
head.command = command;
head.length = length;
// 等待从机准备就绪
if(wifi_spi_wait_idle(wait_time))
{
printf("[wifi_spi] set_parameter: idle wait timeout before write\r\n");
break;
}
printf("[wifi_spi] set_parameter: slave ready for write\r\n");
wifi_spi_dma_write(&head.command, sizeof(wifi_spi_head_struct), buffer, length);
printf("[wifi_spi] set_parameter: header+data written\r\n");
if(wifi_spi_wait_idle(wait_time))
{
printf("[wifi_spi] set_parameter: idle wait timeout after write\r\n");
break;
}
printf("[wifi_spi] set_parameter: slave ready after write\r\n");
// 接收应答信号
head.command = WIFI_SPI_DATA;
head.length = 0;
wifi_spi_dma_transfer_command((wifi_spi_packets_struct *)&head, head.length);
system_delay_us(20);
printf("[wifi_spi] set_parameter: reply command=0x%02X\r\n", head.command);
if(WIFI_SPI_REPLY_OK == head.command)
{
return_state = 0;
printf("[wifi_spi] set_parameter: reply OK\r\n");
}
else
{
printf("[wifi_spi] set_parameter: reply not OK\r\n");
}
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 模块信息获取
// 参数说明 command 命令类型
// 参数说明 *buffer 保存接收到的参数地址
// 参数说明 wait_time 最大等待时间 单位100微妙
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 内部使用,用户无需关心
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_get_parameter (wifi_spi_packets_command_enum command, wifi_spi_packets_struct *read_data, uint32 wait_time)
{
uint8 return_state;
return_state = 1;
do
{
// 等待从机准备就绪
if(wifi_spi_wait_idle(wait_time))
{
break;
}
read_data->head.command = command;
wifi_spi_dma_write(&(read_data->head.command), WIFI_SPI_RECVIVE_SIZE, NULL, 0);
if(wifi_spi_wait_idle(wait_time))
{
break;
}
read_data->head.command = WIFI_SPI_DATA;
read_data->head.length = 0;
wifi_spi_dma_transfer_command(read_data, WIFI_SPI_RECVIVE_SIZE);
return_state = 0;
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 固件版本获取
// 参数说明 void 端口号
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 调用函数之后,固件版本信息以字符串形式保存在wifi_spi_version数组中
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_get_version (void)
{
uint8 return_state;
wifi_spi_packets_struct temp_packets = {0};
return_state = wifi_spi_get_parameter(WIFI_SPI_GET_VERSION, &temp_packets, OTHER_TIME_OUT);
if((0 == return_state) && (WIFI_SPI_REPLY_VERSION == temp_packets.head.command))
{
memcpy(wifi_spi_version, temp_packets.buffer, temp_packets.head.length);
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI MAC地址获取
// 参数说明 void 端口号
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 调用函数之后,MAC地址信息以字符串形式保存在wifi_spi_mac_addr数组中
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_get_mac_addr (void)
{
uint8 return_state;
wifi_spi_packets_struct temp_packets;
return_state = wifi_spi_get_parameter(WIFI_SPI_GET_MAC_ADDR, &temp_packets, OTHER_TIME_OUT);
if((0 == return_state) && (WIFI_SPI_REPLY_MAC_ADDR == temp_packets.head.command))
{
memcpy(wifi_spi_mac_addr, temp_packets.buffer, temp_packets.head.length);
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI IP地址与端口号获取
// 参数说明 void 端口号
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 调用函数之后,IP地址与端口号信息以字符串形式保存在wifi_spi_ip_addr_port数组中
// 需要在连接Socket之后调用此函数才能正常获取信息
//-------------------------------------------------------------------------------------------------------------------
static uint8 wifi_spi_get_ip_addr_port (void)
{
uint8 return_state;
wifi_spi_packets_struct temp_packets;
return_state = wifi_spi_get_parameter(WIFI_SPI_GET_IP_ADDR, &temp_packets, OTHER_TIME_OUT);
if((0 == return_state) && (WIFI_SPI_REPLY_IP_ADDR == temp_packets.head.command))
{
memcpy(wifi_spi_ip_addr_port, temp_packets.buffer, temp_packets.head.length);
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 获取系统时间
// 参数说明 time_format 时间格式
// 返回参数 *buffer 保存时间字符串地址 缓冲区大小至少需要30个字节
// 返回参数 buffer_size 缓冲区大小
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 需要连接有网络的热点之后才能获取到正确的时间,并且在调用这个函数之前需要确保WIFI模块中需要接收的数据已经全部接收完毕
// 备注信息 仅WIFI SPI 外接天线版本支持
// 备注信息 输出的信息为字符串信息,可直接printf到串口助手查看
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_get_time (wifi_spi_time_enum time_format, char *buffer, uint8 buffer_size)
{
uint8 return_state = 1;
wifi_spi_packets_struct temp_packets;
uint8 send_cmd, receive_cmd;
// 接收时间的数组必须大于30个字节
// 并且模块固件必须是V2版本
if((30 <= buffer_size) && (!strncmp(wifi_spi_version, "V2", 2)))
{
send_cmd = WIFI_SPI_GET_TIME1 + time_format - WIFI_SPI_UTC_0;
receive_cmd = WIFI_SPI_REPLY_TIME1 + time_format - WIFI_SPI_UTC_0;
return_state = wifi_spi_get_parameter(send_cmd, &temp_packets, OTHER_TIME_OUT);
if((0 == return_state) && (receive_cmd == temp_packets.head.command))
{
return_state = strncmp((const char *)temp_packets.buffer, "OK", 2);
if(0 == return_state)
{
memcpy(buffer, &temp_packets.buffer[3], temp_packets.head.length - 3);
buffer[temp_packets.head.length - 3] = 0;
}
}
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 扫描热点
// 参数说明 *buffer 保存扫描到的热点信息 包含名称与信号强度,每个信号强度后面会跟一个换行符
// 参数说明 buffer_size 缓冲区的长度
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 仅WIFI SPI 外接天线版本支持
// 备注信息 输出的信息为字符串信息,可直接printf到串口助手查看
// 备注信息 每一行包含一个wifi名称与密码
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_wifi_scan (char *buffer, uint16 buffer_size)
{
uint8 return_state = 0;
// 模块必须是V2版本的固件才支持此功能
if(!strncmp(wifi_spi_version, "V2", 2))
{
return_state = wifi_spi_set_parameter(WIFI_SPI_SET_WIFI_SCAN, NULL, 0, WIFI_CONNECT_TIME_OUT);
if(0 == return_state)
{
#if (0 == WIFI_SPI_READ_TRANSFER)
wifi_spi_send_buffer(NULL, 0);
#endif
while(0 == wifi_spi_read_buffer((uint8 *)buffer, buffer_size))
{
system_delay_ms(10);
}
}
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 设置连接的WiFi信息并尝试连接WiFi
// 参数说明 *wifi_ssid WIFI名称
// 参数说明 *pass_word WIFI密码
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 wifi_spi_wifi_connect("SEEKFREE", "SEEKFREE123");
// 备注信息 wifi_spi_wifi_connect("SEEKFREE", NULL); // 连接没有密码的WIFI热点
//-------------------------------------------------------------------------------------------------------------------
// helper: simple substring search (returns 1 if found)
static uint8 wifi_spi_str_contains(const char *haystack, const char *needle)
{
const char *p, *q;
if(NULL == haystack || NULL == needle)
return 0;
while(*haystack)
{
p = haystack;
q = needle;
while(*p && *q && (*p == *q))
{
p++;
q++;
}
if(!*q) // reached end of needle
return 1;
haystack++;
}
return 0;
}
uint8 wifi_spi_wifi_connect (char *wifi_ssid, char *pass_word)
{
uint8 return_state;
uint8 temp_buffer[64];
uint16 length;
char scan_buf[128];
// 在尝试连接之前先扫描附近的热点
scan_buf[0] = '\0';
return_state = wifi_spi_wifi_scan(scan_buf, sizeof(scan_buf)-1);
if(0 == return_state)
{
printf("[wifi_spi] wifi_scan result:\r\n%s\r\n", scan_buf);
if(wifi_spi_str_contains(scan_buf, wifi_ssid))
{
printf("[wifi_spi] target SSID '%s' found\r\n", wifi_ssid);
}
else
{
printf("[wifi_spi] target SSID '%s' NOT found\r\n", wifi_ssid);
}
}
else
{
printf("[wifi_spi] wifi_scan error %d\r\n", return_state);
}
if(NULL != pass_word)
{
// WIFI热点有密码发送热点名称与密码
length = sprintf((char *)temp_buffer, "%s\r\n%s\r\n", wifi_ssid, pass_word);
}
else
{
// WIFI热点没有密码只需要发送热点名称
length = sprintf((char *)temp_buffer, "%s\r\n", wifi_ssid);
}
/* debug info */
printf("[wifi_spi] wifi_connect: ssid='%s' pass='%s' len=%d\r\n", wifi_ssid, (pass_word?pass_word:"(none)"), length);
return_state = wifi_spi_set_parameter(WIFI_SPI_SET_WIFI_INFORMATION, temp_buffer, length, WIFI_CONNECT_TIME_OUT);
// 本机IP地址与端口号信息以字符串形式保存在wifi_spi_ip_addr_port数组中
wifi_spi_get_ip_addr_port();
printf("[wifi_spi] wifi_connect result=%d ip=%s\r\n", return_state, wifi_spi_ip_addr_port);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 设置连接的Socket信息并尝试连接Socket
// 参数说明 *transport_type 传输类型
// 参数说明 *ip_addr IP地址
// 参数说明 *port 目标端口号
// 参数说明 *local_port 本机端口号
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 wifi_spi_socket_connect("TCP", "192.168.2.5", "8080", "6060");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_socket_connect (char *transport_type, char *ip_addr, char *port, char *local_port)
{
uint8 return_state;
uint8 temp_buffer[41];
uint16 length;
printf("[wifi_spi] socket_connect: transport=%s target=%s:%s local=%s\r\n", transport_type, ip_addr, port, local_port);
length = sprintf((char *)temp_buffer, "%s\r\n%s\r\n%s\r\n%s\r\n", transport_type, ip_addr, port, local_port);
return_state = wifi_spi_set_parameter(WIFI_SPI_SET_SOCKET_INFORMATION, temp_buffer, length, SOCKET_CONNECT_TIME_OUT);
// 本机IP地址与端口号信息以字符串形式保存在wifi_spi_ip_addr_port数组中
wifi_spi_get_ip_addr_port();
printf("[wifi_spi] socket_connect result=%d ip=%s\r\n", return_state, wifi_spi_ip_addr_port);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 断开Socket连接
// 参数说明 void
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例 wifi_spi_socket_disconnect();
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_socket_disconnect (void)
{
wifi_spi_packets_struct temp_packets;
return wifi_spi_get_parameter(WIFI_SPI_CLOSE_SOCKET, &temp_packets, OTHER_TIME_OUT);
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 软复位
// 参数说明 void
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_reset (void)
{
uint8 return_state;
wifi_spi_head_struct head;
return_state = 1;
do
{
head.command = WIFI_SPI_RESET;
head.length = 0xA5A5;
return_state = wifi_spi_wait_idle(OTHER_TIME_OUT);
if(return_state)
{
break;
}
wifi_spi_dma_write(&head.command, sizeof(wifi_spi_head_struct), NULL, 0);
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI UDP模式时立即发送函数
// 参数说明 void
// 返回参数 uint8 状态 0-成功 1-错误
// 使用示例
// 备注信息 在UDP模式下模块收到数据后会等待2毫秒,2毫秒后未收到数据则将数据通过socket发送到网络,如果希望立即发送则在数据传输完毕后调用此函数
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_udp_send_now (void)
{
uint8 return_state = 1;
wifi_spi_packets_struct temp_packets;
if(WIFI_SPI_IDLE == wifi_spi_mutex)
{
// 将通讯状态设置为忙
wifi_spi_mutex = WIFI_SPI_BUSY;
do
{
if(wifi_spi_wait_idle(OTHER_TIME_OUT))
{
break;
}
// 立即开始socket发送
temp_packets.head.command = WIFI_SPI_UDP_SEND;
temp_packets.head.length = 0;
wifi_spi_dma_transfer_command(&temp_packets, WIFI_SPI_RECVIVE_SIZE);
// 检查收到的包中是否有数据
if((WIFI_SPI_REPLY_DATA_START == temp_packets.head.command) || (WIFI_SPI_REPLY_DATA_END == temp_packets.head.command))
{
// 保存接收到的数据
if(temp_packets.head.length)
{
fifo_write_buffer(&wifi_spi_fifo, temp_packets.buffer, temp_packets.head.length);
}
}
// 等待应答信号
if(wifi_spi_wait_idle(OTHER_TIME_OUT))
{
break;
}
// 接收应答信号
temp_packets.head.command = WIFI_SPI_DATA;
temp_packets.head.length = 0;
wifi_spi_dma_transfer_command(&temp_packets, temp_packets.head.length);
if(WIFI_SPI_REPLY_OK == temp_packets.head.command)
{
return_state = 0;
}
}while(0);
// 将通讯状态设置为空闲
wifi_spi_mutex = WIFI_SPI_IDLE;
}
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 数据块发送函数并同步接收数据
// 参数说明 *buff 需要发送的数据地址
// 参数说明 length 发送长度
// 返回参数 uint32 剩余未发送的长度
// 使用示例 wifi_spi_send_buffer(buffer, 100);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint32 wifi_spi_send_buffer (const uint8 *buffer, uint32 length)
{
uint16 send_length;
wifi_spi_packets_struct temp_packets;
// 检查WIFI SPI状态,如果在其他中断或者线程中已经发起了通讯,则本次不能发送数据
if(WIFI_SPI_IDLE == wifi_spi_mutex)
{
// 将通讯状态设置为忙
wifi_spi_mutex = WIFI_SPI_BUSY;
while(length)
{
send_length = length > WIFI_SPI_TRANSFER_SIZE ? WIFI_SPI_TRANSFER_SIZE : length;
if(wifi_spi_wait_idle(OTHER_TIME_OUT))
{
break;
}
wifi_spi_dma_transfer_data(buffer, &temp_packets, send_length);
// 检查收到的包中是否有数据
if((WIFI_SPI_REPLY_DATA_START == temp_packets.head.command) || (WIFI_SPI_REPLY_DATA_END == temp_packets.head.command))
{
// 保存接收到的数据
if(temp_packets.head.length)
{
fifo_write_buffer(&wifi_spi_fifo, temp_packets.buffer, temp_packets.head.length);
}
}
length -= send_length;
buffer += send_length;
}
// 检查最后一次的接收是否将所有的数据都接收完毕
while(WIFI_SPI_REPLY_DATA_START == temp_packets.head.command)
{
if(wifi_spi_wait_idle(OTHER_TIME_OUT))
{
break;
}
// 继续读取模块剩余数据
temp_packets.head.command = WIFI_SPI_DATA;
temp_packets.head.length = 0;
wifi_spi_dma_transfer_command(&temp_packets, WIFI_SPI_RECVIVE_SIZE);
// 检查收到的包中是否有数据
if((WIFI_SPI_REPLY_DATA_START == temp_packets.head.command) || (WIFI_SPI_REPLY_DATA_END == temp_packets.head.command))
{
// 保存接收到的数据
if(temp_packets.head.length)
{
fifo_write_buffer(&wifi_spi_fifo, temp_packets.buffer, temp_packets.head.length);
}
}
}
wifi_spi_mutex = WIFI_SPI_IDLE;
}
return length;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 字符串发送函数并同步接收数据
// 参数说明 *string 需要发送的字符串
// 返回参数 void
// 使用示例 wifi_spi_send_string("123");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
void wifi_spi_send_string(const char *string)
{
wifi_spi_send_buffer((uint8*)string, strlen(string));
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WIFI SPI 读取缓冲区
// 参数说明 *buff 接收缓冲区
// 参数说明 length 读取数据长度
// 返回参数 uint32 实际读取数据长度
// 使用示例 wifi_spi_read_buffer(buffer, 100);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint32 wifi_spi_read_buffer (uint8 *buffer, uint32 length)
{
uint32 fifo_read_length;
uint32 write_length = 0;
wifi_spi_packets_struct temp_packets;
zf_assert(NULL != buffer);
// 首先判断FIFO中是否有数据,如果有则先从FIFO读取
if(fifo_used(&wifi_spi_fifo))
{
fifo_read_length = fifo_used(&wifi_spi_fifo);
fifo_read_length = length < fifo_read_length ? length : fifo_read_length;
fifo_read_buffer(&wifi_spi_fifo, buffer, &fifo_read_length, FIFO_READ_AND_CLEAN);
buffer += fifo_read_length;
length -= fifo_read_length;
write_length += fifo_read_length;
}
#if(1 == WIFI_SPI_READ_TRANSFER)
if(WIFI_SPI_IDLE == wifi_spi_mutex)
{
wifi_spi_mutex = WIFI_SPI_BUSY; // 将通讯状态设置为忙
do
{
if( (WIFI_SPI_RECVIVE_SIZE > wifi_spi_fifo.siz) || // 如果缓冲区空间不够则不再读取
(wifi_spi_wait_idle(OTHER_TIME_OUT)) // 超时退出
)
{
break;
}
temp_packets.head.command = WIFI_SPI_DATA;
temp_packets.head.length = 0;
wifi_spi_dma_transfer_command(&temp_packets, WIFI_SPI_RECVIVE_SIZE);
// 检查收到的包中是否有数据
if( ((WIFI_SPI_REPLY_DATA_START == temp_packets.head.command) || (WIFI_SPI_REPLY_DATA_END == temp_packets.head.command)) &&
(temp_packets.head.length)
)
{
if(length)
{
fifo_read_length = length >= temp_packets.head.length ? temp_packets.head.length : length;
memcpy(buffer, temp_packets.buffer, (uint32)fifo_read_length);
buffer += fifo_read_length;
length -= fifo_read_length;
write_length += fifo_read_length;
if(fifo_read_length < temp_packets.head.length) // 外部缓冲不足多余部分写入FIFO
{
fifo_write_buffer(&wifi_spi_fifo, temp_packets.buffer + fifo_read_length, temp_packets.head.length - fifo_read_length);
}
}
else // 全部写入FIFO
{
fifo_write_buffer(&wifi_spi_fifo, temp_packets.buffer, temp_packets.head.length);
}
}
}while(WIFI_SPI_REPLY_DATA_START == temp_packets.head.command);
wifi_spi_mutex = WIFI_SPI_IDLE;
}
#endif
return write_length;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 WiFi 模块初始化
// 参数说明 *wifi_ssid 目标连接的 WiFi 的名称 字符串形式
// 参数说明 *pass_word 目标连接的 WiFi 的密码 字符串形式
// 返回参数 uint8 模块初始化状态 0-成功 1-错误
// 使用示例 wifi_spi_init("SEEKFREE", "SEEKFREE123");
// 备注信息 wifi_spi_init("SEEKFREE", NULL); // 连接没有密码的WIFI热点
//-------------------------------------------------------------------------------------------------------------------
uint8 wifi_spi_init (char *wifi_ssid, char *pass_word)
{
uint8 return_state = 0;
fifo_init(&wifi_spi_fifo, FIFO_DATA_8BIT, wifi_spi_buffer, WIFI_SPI_RECVIVE_FIFO_SIZE);
spi_dma_init(WIFI_SPI_INDEX, SPI_MODE3, WIFI_SPI_SPEED, WIFI_SPI_SCK_PIN, WIFI_SPI_MOSI_PIN, WIFI_SPI_MISO_PIN, SPI_CS_NULL);//硬件SPI初始化
gpio_init(WIFI_SPI_CS_PIN, GPO, 1, GPO_PUSH_PULL);
gpio_init(WIFI_SPI_RST_PIN, GPO, 1, GPO_PUSH_PULL);
gpio_init(WIFI_SPI_INT_PIN, GPI, 0, GPI_PULL_DOWN);
// 复位
printf("[wifi_spi] init: performing reset...\r\n");
gpio_set_level(WIFI_SPI_RST_PIN, 0);
system_delay_ms(10);
gpio_set_level(WIFI_SPI_RST_PIN, 1);
// 等待模块初始化
system_delay_ms(100);
wifi_spi_mutex = WIFI_SPI_IDLE;
printf("[wifi_spi] init: reset done, mutex set idle\r\n");
do
{
// 固件版本信息以字符串形式保存在wifi_spi_version数组中
printf("[wifi_spi] init: get firmware version...\r\n");
return_state = wifi_spi_get_version();
if(return_state)
{
printf("[wifi_spi] error: get_version failed (code=%d)\r\n", return_state);
break;
}
else
{
printf("[wifi_spi] firmware version: %s\r\n", wifi_spi_version);
}
// MAC地址信息以字符串形式保存在wifi_spi_mac_addr数组中
wifi_spi_get_mac_addr();
printf("[wifi_spi] mac address: %s\r\n", wifi_spi_mac_addr);
if(NULL == wifi_ssid)
{
// 初始化的时候不需要连接WIFI
printf("[wifi_spi] no SSID provided, skip wifi connect\r\n");
break;
}
printf("[wifi_spi] attempt wifi_connect -> ssid: %s, password: %s\r\n", wifi_ssid, (pass_word?pass_word:"(none)"));
return_state = wifi_spi_wifi_connect(wifi_ssid, pass_word);
if(return_state)
{
printf("[wifi_spi] error: wifi_connect failed (code=%d)\r\n", return_state);
break;
}
else
{
// 获取并打印本机 IP 信息
wifi_spi_get_ip_addr_port();
printf("[wifi_spi] wifi connected, ip: %s\r\n", wifi_spi_ip_addr_port);
}
#if(1 == WIFI_SPI_AUTO_CONNECT)
printf("[wifi_spi] AUTO_CONNECT enabled, attempting TCP socket connect to %s:%s\r\n", WIFI_SPI_TARGET_IP, WIFI_SPI_TARGET_PORT);
return_state = wifi_spi_socket_connect("TCP", WIFI_SPI_TARGET_IP, WIFI_SPI_TARGET_PORT, WIFI_SPI_LOCAL_PORT);
if(return_state)
{
printf("[wifi_spi] error: auto TCP socket_connect failed (code=%d)\r\n", return_state);
break;
}
else
{
printf("[wifi_spi] auto TCP socket connected, local/remote: %s\r\n", wifi_spi_ip_addr_port);
}
#endif
#if(2 == WIFI_SPI_AUTO_CONNECT)
return_state = wifi_spi_socket_connect("UDP", WIFI_SPI_TARGET_IP, WIFI_SPI_TARGET_PORT, WIFI_SPI_LOCAL_PORT);
if(return_state)
{
break;
}
#endif
}while(0);
return return_state;
}