更新httpfiledownload.py,适配现有SPI时序 2879/1 2879/head 2880/target/1
authorpenglei <1624952103@qq.com>
Sat, 6 Dec 2025 11:57:34 +0000 (19:57 +0800)
committerpenglei <1624952103@qq.com>
Sat, 6 Dec 2025 11:57:34 +0000 (19:57 +0800)
cat1modem/src/LeiNiao/httpfiledownload.py
code/sdk/zhihui/utils/custom_spi.c

index 3f461b5..fc3b006 100644 (file)
@@ -25,6 +25,7 @@ from usr.EventMesh import eventMesh
 import usocket
 import _thread
 from machine import SPI
+from machine import Pin
 
 # spi - 通道选择[0,1],int类型。
 
@@ -56,7 +57,13 @@ from machine import SPI
 
 
 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:
     """
@@ -276,8 +283,8 @@ class HttpFileDownloadTcpServer:
         # 初始化 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")
@@ -422,53 +429,113 @@ class HttpFileDownloadTcpServer:
             
             # 下载数据并通过 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
             
@@ -563,8 +630,8 @@ class HttpFileDownloadSpiTest:
             # 默认创建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")
@@ -628,46 +695,107 @@ class HttpFileDownloadSpiTest:
             
             # 下载数据并通过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
@@ -676,12 +804,17 @@ class HttpFileDownloadSpiTest:
             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()
index 4bc69a4..f8d64b1 100644 (file)
@@ -44,10 +44,12 @@ void custom_spi_read(void)
 
     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]);
@@ -56,41 +58,44 @@ void custom_spi_read(void)
         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内)