import usocket
import _thread
from machine import SPI
+from machine import Pin
# spi - 通道选择[0,1],int类型。
REQUESTS_AVAILABLE = True
+# 创建gpio对象(唤醒MCU的引脚,GPIO4,输出模式,初始高电平)
+gpioWakeBT = Pin(Pin.GPIO4, Pin.OUT, Pin.PULL_DISABLE, 1)
+# 设置输入输出模式
+gpioWakeBT.set_dir(Pin.OUT)
+# 设置引脚电平
+gpioWakeBT.write(1)
class HttpFileDownloader:
"""
# 初始化 SPI 对象
if spi_obj is None:
# 默认创建 SPI(1, 0, 1): 通道1, 模式0, 时钟频率1(1.625MHz)
- self.spi_obj = SPI(2, 0, 8)
- clog.info("Created default SPI object: SPI(2, 0, 8)")
+ self.spi_obj = SPI(2, 0, 12)
+ clog.info("Created default SPI object: SPI(2, 0, 12)")
else:
self.spi_obj = spi_obj
clog.info("Using provided SPI object")
# 下载数据并通过 SPI 发送
downloaded_size = 0
+ # 缓存未发送的剩余数据
+ remaining_data = b''
+ # 累计补0字节数
+ total_padded_zeros = 0
# response.content 是 bytes 类型生成器
for chunk in response.content:
if chunk: # 过滤掉空块
try:
- # 通过 SPI 发送数据块
- # SPI API: write(data, datasize) 或 write_read(read_buf, write_data, datasize, timeout)
- chunk_len = len(chunk)
- if hasattr(self.spi_obj, 'write'):
- # write(data, datasize) - datasize 参数必需
- self.spi_obj.write(chunk, chunk_len)
- elif hasattr(self.spi_obj, 'write_read'):
- # write_read(read_buf, write_data, datasize, timeout)
- # 或者 write_read(read_buf, write_data, datasize)
- read_buf = bytearray(chunk_len)
- try:
- # 尝试带timeout的调用
- self.spi_obj.write_read(read_buf, chunk, chunk_len, 5)
- except TypeError:
- # 尝试不带timeout的调用
- self.spi_obj.write_read(read_buf, chunk, chunk_len)
- else:
- clog.error("SPI object does not have write or write_read method")
- return False, 0.0, -1
+ # 合并剩余数据和当前chunk
+ combined_data = remaining_data + chunk
+ remaining_data = b''
- downloaded_size += len(chunk)
+ # 拆分数据为1024字节的块
+ while len(combined_data) >= 1024:
+ # 取前1024字节
+ send_chunk = combined_data[:1024]
+ # 剩余数据保留
+ combined_data = combined_data[1024:]
+
+ gpioWakeBT.write(0)
+ utime.sleep_ms(2)
+ gpioWakeBT.write(1)
+ utime.sleep_ms(2)
+
+ # 通过 SPI 发送1024字节数据块
+ chunk_len = len(send_chunk) # 固定为1024
+ if hasattr(self.spi_obj, 'write'):
+ self.spi_obj.write(send_chunk, chunk_len)
+ utime.sleep_ms(5)
+ elif hasattr(self.spi_obj, 'write_read'):
+ read_buf = bytearray(chunk_len)
+ try:
+ self.spi_obj.write_read(read_buf, send_chunk, chunk_len, 5)
+ except TypeError:
+ self.spi_obj.write_read(read_buf, send_chunk, chunk_len)
+ else:
+ clog.error("SPI object does not have write or write_read method")
+ return False, 0.0, -1
+
+ downloaded_size += len(send_chunk)
+
+ # 显示进度(每发送 64KB 打印一次进度)
+ if total_size > 0:
+ progress = (downloaded_size / total_size) * 100
+ if downloaded_size % (64 * 1024) < 1024:
+ clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes (TX: 1024 bytes, total padded zeros: {})".format(
+ progress, downloaded_size, total_size, total_padded_zeros))
+
+ # 保存剩余不足1024字节的数据
+ remaining_data = combined_data
- # 显示进度(每发送一定数据量后打印一次)
- if total_size > 0:
- progress = (downloaded_size / total_size) * 100
- # 每发送 64KB 打印一次进度
- if downloaded_size % (64 * 1024) < self.sizeof:
- clog.info("Progress: {:.2f}% ({}/{}) bytes".format(
- progress, downloaded_size, total_size))
except Exception as e:
clog.error("Error sending data via SPI: {}".format(e))
return False, 0.0, -1
+ # 处理最后不足1024字节的剩余数据(拼接空字节,完全避开bytearray下标赋值)
+ if len(remaining_data) > 0:
+ try:
+ # 计算需要补的空字节数
+ pad_len = 1024 - len(remaining_data)
+ total_padded_zeros += pad_len # 累计补0字节数
+ # 拼接空字节(直接生成pad_len个0字节的bytes)
+ send_chunk = remaining_data + b'\x00' * pad_len
+
+ gpioWakeBT.write(0)
+ utime.sleep_ms(2)
+ gpioWakeBT.write(1)
+ utime.sleep_ms(2)
+
+ if hasattr(self.spi_obj, 'write'):
+ self.spi_obj.write(send_chunk, 1024)
+ utime.sleep_ms(5)
+ elif hasattr(self.spi_obj, 'write_read'):
+ read_buf = bytearray(1024)
+ try:
+ self.spi_obj.write_read(read_buf, send_chunk, 1024, 5)
+ except TypeError:
+ self.spi_obj.write_read(read_buf, send_chunk, 1024)
+
+ downloaded_size += len(remaining_data) # 只统计实际数据长度
+ clog.info("=== Final SPI Chunk Info ===")
+ clog.info("Actual data bytes: {}".format(len(remaining_data)))
+ clog.info("Padded zero bytes: {}".format(pad_len))
+ clog.info("Total padded zeros in whole transmission: {}".format(total_padded_zeros))
+ clog.info("============================")
+
+ # 最后一块进度显示
+ if total_size > 0:
+ progress = (downloaded_size / total_size) * 100
+ clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes (TX: 1024 bytes, final chunk, total padded zeros: {})".format(
+ progress, downloaded_size, total_size, total_padded_zeros))
+ except Exception as e:
+ clog.error("Error sending final SPI chunk: {}".format(e))
+ return False, 0.0, -1
+
# 记录结束时间并计算耗时
end_time = utime.time()
download_time = end_time - start_time
- clog.info("Download and send via SPI completed: {} bytes in {:.3f}s".format(
- downloaded_size, download_time))
-
- # 注意:TCP服务器模式下,SPI对象在服务器运行期间保持打开,不在这里关闭
- # 只有在服务器停止时才关闭SPI
+ # 打印整体传输统计
+ clog.info("=== SPI Transmission Summary ===")
+ clog.info("Total actual data sent: {} bytes".format(downloaded_size))
+ clog.info("Total padded zero bytes: {} bytes".format(total_padded_zeros))
+ clog.info("Total SPI packets sent: {} (each 1024 bytes)".format((downloaded_size + total_padded_zeros) // 1024))
+ clog.info("Transmission time: {:.3f} seconds".format(download_time))
+ clog.info("================================")
return True, download_time, downloaded_size
# 默认创建SPI(2, 0, 1): 通道2, 模式0, 时钟频率1(26MHz)
# 注意:Python端SPI2对应MCU端SPI1
# 频率参数1表示26MHz(根据实际SPI驱动实现)
- self.spi_obj = SPI(2, 0, 8)
- clog.info("Created default SPI object: SPI(2, 0, 8) for 26MHz")
+ self.spi_obj = SPI(2, 0, 12)
+ clog.info("Created default SPI object: SPI(2, 0, 12) for 26MHz")
else:
self.spi_obj = spi_obj
clog.info("Using provided SPI object")
# 下载数据并通过SPI发送
downloaded_size = 0
+ # 缓存未发送的剩余数据
+ remaining_data = b''
+ # 累计补0字节数
+ total_padded_zeros = 0
# response.content是bytes类型生成器
for chunk in response.content:
if chunk: # 过滤掉空块
try:
- # 通过SPI发送数据块
- # SPI API: write(data, datasize) 或 write_read(read_buf, write_data, datasize, timeout)
- chunk_len = len(chunk)
- if hasattr(self.spi_obj, 'write'):
- # write(data, datasize) - datasize 参数必需
- self.spi_obj.write(chunk, chunk_len)
- elif hasattr(self.spi_obj, 'write_read'):
- # write_read(read_buf, write_data, datasize, timeout)
- # 或者 write_read(read_buf, write_data, datasize)
- read_buf = bytearray(chunk_len)
- try:
- # 尝试带timeout的调用
- self.spi_obj.write_read(read_buf, chunk, chunk_len, 5)
- except TypeError:
- # 尝试不带timeout的调用
- self.spi_obj.write_read(read_buf, chunk, chunk_len)
- else:
- clog.error("SPI object does not have write or write_read method")
- self.close() # 关闭SPI
- return False, 0.0, -1
+ # 合并剩余数据和当前chunk
+ combined_data = remaining_data + chunk
+ remaining_data = b''
- downloaded_size += len(chunk)
+ # 拆分数据为1024字节的块
+ while len(combined_data) >= 1024:
+ # 取前1024字节
+ send_chunk = combined_data[:1024]
+ # 剩余数据保留
+ combined_data = combined_data[1024:]
+
+ gpioWakeBT.write(0)
+ utime.sleep_ms(2)
+ gpioWakeBT.write(1)
+ utime.sleep_ms(2)
+
+ # 通过SPI发送1024字节数据块
+ chunk_len = len(send_chunk) # 固定为1024
+ if hasattr(self.spi_obj, 'write'):
+ self.spi_obj.write(send_chunk, chunk_len)
+ utime.sleep_ms(5)
+ elif hasattr(self.spi_obj, 'write_read'):
+ read_buf = bytearray(chunk_len)
+ try:
+ self.spi_obj.write_read(read_buf, send_chunk, chunk_len, 5)
+ except TypeError:
+ self.spi_obj.write_read(read_buf, send_chunk, chunk_len)
+ else:
+ clog.error("SPI object does not have write or write_read method")
+ self.close() # 关闭SPI
+ return False, 0.0, -1
+
+ downloaded_size += len(send_chunk)
+
+ # 显示进度(每发送64KB打印一次,减少打印数量)
+ if total_size > 0:
+ progress = (downloaded_size / total_size) * 100
+ # 每发送64KB打印一次进度(64*1024=65536)
+ if downloaded_size % (64 * 1024) < 1024:
+ clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes (TX: 1024 bytes, total padded zeros: {})".format(
+ progress, downloaded_size, total_size, total_padded_zeros))
+
+ # 保存剩余不足1024字节的数据
+ remaining_data = combined_data
- # 显示进度(每发送64KB打印一次,减少打印数量)
- if total_size > 0:
- progress = (downloaded_size / total_size) * 100
- # 每发送64KB打印一次进度
- if downloaded_size % (64 * 1024) < self.sizeof:
- clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes".format(
- progress, downloaded_size, total_size))
except Exception as e:
clog.error("Error sending data via SPI: {}".format(e))
self.close() # 关闭SPI
return False, 0.0, -1
+ # 处理最后不足1024字节的剩余数据(拼接空字节,完全避开bytearray下标赋值)
+ if len(remaining_data) > 0:
+ try:
+ # 计算需要补的空字节数
+ pad_len = 1024 - len(remaining_data)
+ total_padded_zeros += pad_len # 累计补0字节数
+ # 直接拼接空字节(b'\x00' * pad_len),无需bytearray
+ send_chunk = remaining_data + (b'\x00' * pad_len)
+
+ gpioWakeBT.write(0)
+ utime.sleep_ms(2)
+ gpioWakeBT.write(1)
+ utime.sleep_ms(2)
+
+ if hasattr(self.spi_obj, 'write'):
+ self.spi_obj.write(send_chunk, 1024)
+ utime.sleep_ms(5)
+ elif hasattr(self.spi_obj, 'write_read'):
+ read_buf = bytearray(1024)
+ try:
+ self.spi_obj.write_read(read_buf, send_chunk, 1024, 5)
+ except TypeError:
+ self.spi_obj.write_read(read_buf, send_chunk, 1024)
+
+ downloaded_size += len(remaining_data) # 只统计实际数据长度
+ # 打印最后一块补0详情
+ clog.info("=== Final SPI Chunk Detail ===")
+ clog.info("Last chunk actual data: {} bytes".format(len(remaining_data)))
+ clog.info("Last chunk padded zeros: {} bytes".format(pad_len))
+ clog.info("Total padded zeros in transmission: {} bytes".format(total_padded_zeros))
+ clog.info("==============================")
+
+ # 最后一块进度显示
+ if total_size > 0:
+ progress = (downloaded_size / total_size) * 100
+ clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes (TX: 1024 bytes, final chunk, total padded zeros: {})".format(
+ progress, downloaded_size, total_size, total_padded_zeros))
+ except Exception as e:
+ clog.error("Error sending final SPI chunk: {}".format(e))
+ self.close() # 关闭SPI
+ return False, 0.0, -1
+
# 记录结束时间并计算耗时
end_time = utime.time()
download_time = end_time - start_time
speed_kbps = (downloaded_size * 8.0) / download_time / 1024.0 # Kbps
speed_mbps = speed_kbps / 1024.0 # Mbps
+ # 打印整体传输统计信息
+ clog.info("=== SPI Transmission Complete Summary ===")
+ clog.info("Total actual data transmitted: {} bytes ({:.2f} MB)".format(downloaded_size, downloaded_size/1024/1024))
+ clog.info("Total padded zero bytes: {} bytes ({:.2f} KB)".format(total_padded_zeros, total_padded_zeros/1024))
+ clog.info("Total SPI packets sent: {} (each 1024 bytes)".format((downloaded_size + total_padded_zeros) // 1024))
+ clog.info("Total transmission time: {:.3f} seconds".format(download_time))
if speed_mbps >= 1.0:
- clog.info("SPI speed test completed: {} bytes in {:.3f}s, Speed: {:.2f} Mbps ({:.2f} Kbps)".format(
- downloaded_size, download_time, speed_mbps, speed_kbps))
+ clog.info("Effective transmission speed: {:.2f} Mbps ({:.2f} Kbps)".format(speed_mbps, speed_kbps))
else:
- clog.info("SPI speed test completed: {} bytes in {:.3f}s, Speed: {:.2f} Kbps".format(
- downloaded_size, download_time, speed_kbps))
+ clog.info("Effective transmission speed: {:.2f} Kbps".format(speed_kbps))
+ clog.info("==========================================")
# 传输完成后关闭SPI
self.close()
ret = uapi_spi_slave_read(SPI_BUS_1, &spi_data, 50);
- if(ret == 0 && spi_data.rx_bytes == 1024)
+ printf("total_cnt:%d,spi_data.rx_bytes:%d\n",total_cnt,spi_data.rx_bytes);
+
+ if(ret == 0)
{
total_cnt += spi_data.rx_bytes;
- printf("total_cnt:%d\n",total_cnt);
+ printf("ret:%x,total_cnt:%d,spi_data.rx_bytes:%d\n",ret,total_cnt,spi_data.rx_bytes);
// printf("spi_data.rx_buff[0]:0x%x,total_cnt:%d\n",spi_data.rx_buff[0],total_cnt);
// printf("spi_data.rx_bytes : %d, spi_data.rx_data[0]:0x%02X,spi_data.rx_data[1023]:0x%02X\n",
// spi_data.rx_bytes, current_seq, spi_data.rx_buff[1023]);
pkg_recv_cnt++;
// --------------- 逐字节严格递增判断(无跳过,首个包就校验)---------------
- uint8_t byte_error_cnt = 0; // 单包内字节错误计数
- uint8_t prev_byte = spi_data.rx_buff[0]; // 初始化为第一个字节
- // printf("head\n");
- // 遍历1024字节(从第2个字节开始校验)
- for (int i = 1; i < 1024; i++)
- {
- // if(i < 20)
- // printf("(0x%02X)",spi_data.rx_buff[i]);
- // if(i == 20)
- // printf("\n");
- uint8_t curr_byte = spi_data.rx_buff[i];
- // 8位字节递增规则:0xFF后应为0x00,其余为前一字节+1
- uint8_t expected_byte = (prev_byte == 0xFF) ? 0x00 : (prev_byte + 1);
+ // uint8_t byte_error_cnt = 0; // 单包内字节错误计数
+ // uint8_t prev_byte = spi_data.rx_buff[0]; // 初始化为第一个字节
+ // // printf("head\n");
+ // // 遍历1024字节(从第2个字节开始校验)
+ // for (int i = 1; i < 1024; i++)
+ // {
+ // // if(i < 20)
+ // // printf("(0x%02X)",spi_data.rx_buff[i]);
+ // // if(i == 20)
+ // // printf("\n");
+ // uint8_t curr_byte = spi_data.rx_buff[i];
+ // // 8位字节递增规则:0xFF后应为0x00,其余为前一字节+1
+ // uint8_t expected_byte = (prev_byte == 0xFF) ? 0x00 : (prev_byte + 1);
- // 校验当前字节是否等于期望的递增字节(无跳过)
- if (curr_byte != expected_byte)
- {
- byte_error_cnt++;
- // 打印错误详情(调试用,正式环境可注释)
- printf("字节[%d]不连续:当前0x%02X, 期望0x%02X(前一字节0x%02X)\n",
- i, curr_byte, expected_byte, prev_byte);
- }
+ // // 校验当前字节是否等于期望的递增字节(无跳过)
+ // if (curr_byte != expected_byte)
+ // {
+ // byte_error_cnt++;
+ // // 打印错误详情(调试用,正式环境可注释)
+ // printf("字节[%d]不连续:当前0x%02X, 期望0x%02X(前一字节0x%02X)\n",
+ // i, curr_byte, expected_byte, prev_byte);
+ // }
- // 更新前一字节,用于下一轮校验
- prev_byte = curr_byte;
- }
+ // // 更新前一字节,用于下一轮校验
+ // prev_byte = curr_byte;
+ // }
// printf("该包无错误\n");
- // 单包字节校验结果汇总(首个包就统计)
- if (byte_error_cnt > 0)
- {
- printf("【包%d】字节递增错误数:%d | 累计字节错误数:%d\n",
- pkg_recv_cnt, byte_error_cnt, total_byte_error_cnt += byte_error_cnt);
- }
+ // // 单包字节校验结果汇总(首个包就统计)
+ // if (byte_error_cnt > 0)
+ // {
+ // printf("【包%d】字节递增错误数:%d | 累计字节错误数:%d\n",
+ // pkg_recv_cnt, byte_error_cnt, total_byte_error_cnt += byte_error_cnt);
+ // }
+ }
+ else
+ {
+ printf("error ret:%x,spi_data.rx_bytes:%d\n",ret,spi_data.rx_bytes);
}
-
// else
// {
// // 新增:包计数自增(失败/长度不符的包也计数,若仅统计成功包可移到上面if内)