AP模式/ESP32作為TCP服務端,轉發串口接收的數據給網絡調試助手

此代碼為接收STM32的數據然后直接轉發到網絡調試助手,當有設備連接到esp32軟件熱點時會通過串口發送字符’a’給STM32,當有設備斷開連接時會通過串口發送字符’b’,

ESP32的TX:GPIO4, RX:GPIO5

ESP32作為TCP服務器地址為192.168.4.1 監聽端口為3333


#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h" //lwip錯誤代碼
#include "lwip/sys.h"
#include "sdkconfig.h"
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include "esp_netif.h"
#include <sys/param.h>
#include "esp_system.h"
#include "lwip/sockets.h"
#include <lwip/netdb.h>
#include "driver/uart.h"
#include "driver/gpio.h"#define EXAMPLE_ESP_WIFI_SSID "laotie666"                // 熱點名
#define EXAMPLE_ESP_WIFI_PASS "12345678"                 // 熱點密碼
#define EXAMPLE_ESP_WIFI_CHANNEL CONFIG_ESP_WIFI_CHANNEL // 信道(來自menuconfig)
#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONN     // 最大連接數(來自menuconfig)
#define CONFIG_EXAMPLE_IPV4 1                            // 啟用IPv4
#define PORT 3333                                        // 服務器監聽的端口號
#define KEEPALIVE_IDLE 5                                 // TCP Keepalive空閑時間(秒)
#define KEEPALIVE_INTERVAL 5                             // Keepalive探測間隔(秒)
#define KEEPALIVE_COUNT 3                                // 超時前的探測次數
#define EX_UART_NUM UART_NUM_1                           // 使用UART1端口
#define BUF_SIZE (1024)                                  // UART緩沖區大小
#define RD_BUF_SIZE (BUF_SIZE)                           // 讀取緩沖區大小/*函數聲明*/uint8_t mac[6];
// 日志標簽
static const char *TAG = "wifi softAP";
static const char *TAG_ZH = "Zhanghui:";static uint8_t uart_buffer1[1024];
uint8_t uart_data;static QueueHandle_t uart0_queue;// 當建立tcp連接之后才會進行串口接收震動數據
uint8_t uart_re_en_flag = 0;
// TCP發送錯誤標志
int tcp_send_error_flag;// WiFi事件處理函數
static void wifi_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{if (event_id == WIFI_EVENT_AP_STACONNECTED){// 有設備連接到我們的軟件熱點時會觸發這個事件wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",MAC2STR(event->mac), event->aid);// 當有設備連接到esp32軟件熱點時會通過串口發送字符’a’uart_data = 'a';uart_write_bytes(EX_UART_NUM, &uart_data, 1);}else if (event_id == WIFI_EVENT_AP_STADISCONNECTED){// 斷開連接時wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;// 打印斷開設備的信息,如ipESP_LOGI(TAG, "station " MACSTR " leave, AID=%d, reason=%d",MAC2STR(event->mac), event->aid, event->reason);// 當有設備斷開連接時會通過串口發送字符’b’uart_data = 'b';uart_write_bytes(EX_UART_NUM, &uart_data, 1);}
}// 初始化SoftAP模式
void wifi_init_softap(void)
{// 通過調用esp_netif_init()來啟動LWIPtaskESP_ERROR_CHECK(esp_netif_init()); // 初始化底層TCP/IP棧// 通過esp_event_loop_create_default()來創建啟動事件task--eventtaskESP_ERROR_CHECK(esp_event_loop_create_default()); // 創建默認事件循環esp_netif_create_default_wifi_ap();               // 創建默認WIFI AP網絡接口// 初始化WIFI驅動配置為默認值wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();// esp_wifi_init() 初始化WIFI driverESP_ERROR_CHECK(esp_wifi_init(&cfg));// 4.對我們所需處理的一些事件注冊了一個回調函數wifi_event_handlerESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));// 配置driverwifi_config_t wifi_config = {.ap = {.ssid = EXAMPLE_ESP_WIFI_SSID,             // 熱點的名字.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), // SSID長度.channel = EXAMPLE_ESP_WIFI_CHANNEL,       // 無線信道 WiFi信號工作在2.4GHz或5GHz頻段(取決于設備支持),這些頻段被劃分為多個子頻段,每個子頻段稱為一個信道。.password = EXAMPLE_ESP_WIFI_PASS,         // 熱點的密碼.max_connection = EXAMPLE_MAX_STA_CONN,    // 熱點的最大連接數目
#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT              // 用于根據系統配置決定使用哪種 Wi-Fi 安全協議.authmode = WIFI_AUTH_WPA3_PSK,            // 授權的模式,登錄的加密模式 // WPA3加密模式.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,          // SAE密碼交換方法
#else                                                  /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */.authmode = WIFI_AUTH_WPA2_PSK, // 默認WPA2加密
#endif.pmf_cfg = {// 受保護的管理幀配置.required = true, // 要求PMF},},};// 如果密碼為空則使用開放模式if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0){wifi_config.ap.authmode = WIFI_AUTH_OPEN;}// 使用esp_wifi_set_mode()對driver進行配置ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); // 設置WIFI為AP模式// 應用AP配置ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));// 啟動driverESP_ERROR_CHECK(esp_wifi_start()); // 啟動WIFI// 打印熱點配置信息ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/*wifi driver被啟動之后, 會發送WIFI_EVENT_AP_START這個事件到event Task中,如果有處理這個事件的回調函數,就會再這個回調函數中進行處理;如果有設備進行連接,就會發送WIFI_EVENT_AP_STACONNECTED這個事件到event Task,之后再wifi_event_handler中進行處理(實例代碼中只是打印了相應的信息)如果有斷開連接的事件WIFI_EVENT_AP_STADISCONNECTED,也會發送到event Task,event Task調用wifi_event_handler進行處理
*/// 數據轉發函數
static void do_retransmit(const int sock)
{int len;uart_event_t event; // UART事件結構體uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE);while (1){//從名為`uart0_queue`的隊列中接收數據,并將接收到的數據存儲到`event`變量中,如果沒有數據可接收,則無限期等待(阻塞)直到有數據到來。if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)){//清零內存區域,即將這段內存區域中的所有字節都設置為0,與memset()函數類似但功能受限。由于bzero()已被廢棄,推薦使用memset()進行內存設置。bzero(dtmp, RD_BUF_SIZE);ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);switch (event.type){// 接收到的數據通常會在這里被處理 dtmp指向接收到的數據  event.size為接收到數據的大小case UART_DATA: {ESP_LOGI(TAG, "[UART DATA]: %d", event.size);uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);int written = send(sock, dtmp, event.size, 0);if (written < 0){ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);// Failed to retransmit, giving upreturn;}}break;// 硬件FIFO溢出事件case UART_FIFO_OVF:ESP_LOGI(TAG, "hw fifo overflow");// If fifo overflow happened, you should consider adding flow control for your application.// The ISR has already reset the rx FIFO,// As an example, we directly flush the rx buffer here in order to read more data.uart_flush_input(EX_UART_NUM);xQueueReset(uart0_queue);break;// 環形緩沖區滿事件case UART_BUFFER_FULL:ESP_LOGI(TAG, "ring buffer full");// If buffer full happened, you should consider increasing your buffer size// As an example, we directly flush the rx buffer here in order to read more data.uart_flush_input(EX_UART_NUM);xQueueReset(uart0_queue);break;// 檢測到UART線路斷開case UART_BREAK:ESP_LOGI(TAG, "uart rx break");break;// 幀錯誤case UART_FRAME_ERR:ESP_LOGI(TAG, "uart frame error");break;default:ESP_LOGI(TAG, "uart event type: %d", event.type);break;}}}// do {//     len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);//     if (len < 0) {//         ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);//     } else if (len == 0) {//         ESP_LOGW(TAG, "Connection closed");//     } else {//         rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string//         ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);//         // send() can return less bytes than supplied length.//         // Walk-around for robust implementation.//         int to_write = len;//         while (to_write > 0) {//             int written = send(sock, rx_buffer + (len - to_write), to_write, 0);//             if (written < 0) {//                 ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);//                 // Failed to retransmit, giving up//                 return;//             }//             to_write -= written;//         }//     }// } while (len > 0);
}
/* UART事件處理任務 */// TCP服務器任務
static void tcp_server_task(void *pvParameters)
{char addr_str[128];                  // 存儲客戶端IP字符串int addr_family = (int)pvParameters; // 獲取地址族參數int ip_protocol = 0;                 // IP協議類型int keepAlive = 1;                   // 啟用Keepaliveint keepIdle = 5;                    // Keepalive空閑時間int keepInterval = 5;                // 探測間隔int keepCount = 3;                   // 探測次數struct sockaddr_storage dest_addr;   // 服務器地址存儲結構// 配置服務器地址if (addr_family == AF_INET){struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); // 監聽所有接口dest_addr_ip4->sin_family = AF_INET;                // IPv4地址族dest_addr_ip4->sin_port = htons(PORT);              // 設置端口ip_protocol = IPPROTO_IP;                           // IP協議}// 創建監聽套接字ESP_LOGE(TAG_ZH, "create socket");int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);if (listen_sock < 0){ESP_LOGE(TAG_ZH, "Unable to create socket: errno %d", errno);vTaskDelete(NULL);return;}// 設置套接字選項(地址重用)int opt = 1;setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)// Note that by default IPV6 binds to both protocols, it is must be disabled// if both protocols used at the same time (used in CI)setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
#endifESP_LOGI(TAG, "套接字已創建");int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err != 0){ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); // 套接字綁定失敗ESP_LOGE(TAG, "IPPROTO: %d", addr_family);goto CLEAN_UP;}ESP_LOGI(TAG, "Socket bound, port %d", PORT);err = listen(listen_sock, 1); // 最大掛起連接數為1if (err != 0){ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);goto CLEAN_UP;}while (1){struct sockaddr_storage source_addr; // 客戶端地址存儲socklen_t addr_len = sizeof(source_addr);// 接受客戶端連接int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);if (sock < 0){ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);break;}// 設置TCP Keepalive選項setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));// 將客戶端IP地址轉換為字符串
#ifdef CONFIG_EXAMPLE_IPV4if (source_addr.ss_family == PF_INET){inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);}
#endif
#ifdef CONFIG_EXAMPLE_IPV6if (source_addr.ss_family == PF_INET6){inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);}
#endifESP_LOGI(TAG_ZH, "Socket accepted ip address: %s", addr_str); // 接受的客戶端IP:uart_re_en_flag = 1;                                          // 設置標志位,表示可以接收串口數據// do_retransmit(sock);do_retransmit(sock);shutdown(sock, 0);close(sock);}CLEAN_UP:close(listen_sock);vTaskDelete(NULL);
}void app_main(void)
{// 初始化存儲空間esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);uart_config_t uart_config = {.baud_rate = 115200,.data_bits = UART_DATA_8_BITS,.parity = UART_PARITY_DISABLE,.stop_bits = UART_STOP_BITS_1,.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,.source_clk = UART_SCLK_DEFAULT,};// 安裝UART驅動程序(創建事件隊列)uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);// 應用參數配置uart_param_config(EX_UART_NUM, &uart_config);// 設置UART引腳(TX:GPIO4, RX:GPIO5)uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");ESP_ERROR_CHECK(esp_efuse_mac_get_default(mac));wifi_init_softap();xTaskCreate(tcp_server_task, "tcp_server", 4096, (void *)AF_INET, 5, NULL);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95418.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95418.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95418.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

kafka 中的Broker 是什么?它在集群中起什么作用?

Kafka中的Broker&#xff1a;集群的核心支柱 在分布式消息系統Apache Kafka中&#xff0c;Broker是構成Kafka集群的核心節點或服務器。 簡單來說&#xff0c;每一個Broker就是運行著Kafka服務的一個實例&#xff0c;多臺Broker共同協作&#xff0c;形成了強大的、可擴展的消息處…

【SOA用于噪聲抑制】光纖DFB激光器中弛豫振蕩噪聲抑制

概述&#xff1a;本章記錄了我們在光纖分布式反饋DFB激光器中使用飽和SOA來降低RIN的工作&#xff0c;以用于低頻傳感器應用。結果表明&#xff0c;放大器的增益動力學允許光纖激光器的弛豫振蕩RO噪聲分量減少30dB。 1 背景到目前為止&#xff0c;我研究了將飽和半導體光放大器…

神經網絡的核心組件解析:從理論到實踐

神經網絡作為深度學習的核心技術&#xff0c;其復雜性常常令人望而卻步。然而&#xff0c;盡管神經網絡的結構、參數和計算過程看似繁瑣&#xff0c;但其核心組件卻是相對簡潔且易于理解的。本文將深入探討神經網絡的四大核心組件——層、模型、損失函數與優化器&#xff0c;并…

Spring Boot項目通過Feign調用三方接口的詳細教程

目錄 一、環境準備 二、啟用Feign客戶端 三、定義Feign客戶端接口 四、定義請求/響應DTO 五、調用Feign客戶端 六、高級配置 1. 添加請求頭&#xff08;如認證&#xff09; 2. 超時配置&#xff08;application.yml&#xff09; 3. 日志配置 七、錯誤處理 自定義錯誤…

ubuntu24.04安裝 bpftool 以及生成 vmlinux.h 文件

文章目錄前言一、apt安裝二、源碼安裝三、生成vmlinux.h參考資料前言 $ cat /etc/os-release PRETTY_NAME"Ubuntu 24.04.2 LTS"$ uname -r 6.14.0-27-generic一、apt安裝 安裝bpftool&#xff1a; $ sudo apt install linux-tools-commonThe following NEW packa…

Pytorch FSDP權重分片保存與合并

注&#xff1a;本文章方法只適用Pytorch FSDP1的模型&#xff0c;且切分策略為SHARDED_STATE_DICT場景。 在使用FSDP訓練模型時&#xff0c;為了節省顯存通常會把模型權重也進行切分&#xff0c;在保存權重時為了加速保存通常每個進程各自保存自己持有的部分權重&#xff0c;避…

IDEA自動生成Mapper、XML和實體文件

1. 引入插件 <build><finalName>demo</finalName><plugins><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</version><depe…

單例模式的理解

目錄單例模式1.餓漢式(線程安全)2.懶漢式(通過synchronized修飾獲取實例的方法保證線程安全)3.雙重校驗鎖的方式實現單例模式4.靜態內部類方式實現單例模式【推薦】單例模式 1.餓漢式(線程安全) package 并發的例子.單例模式; // 餓漢式單例模式&#xff08;天然線程安全&…

NLP---IF-IDF案例分析

一案例 - 紅樓夢1首先準備語料庫http://www.dxsxs.com這個網址去下載2 任務一&#xff1a;拆分提取import os import redef split_hongloumeng():# 1. 配置路徑&#xff08;關鍵&#xff1a;根據實際文件位置修改&#xff09; # 腳本所在文件夾&#xff08;自動獲取&#xff0…

LaTeX(排版系統)Texlive(環境)Vscode(編輯器)環境配置與安裝

LaTeX、Texlive 和 Vscode 三者之間的關系&#xff0c;可以把它們理解成語言、工具鏈和編輯器的配合關系。 1.下載Texlive 華為鏡像網站下載 小編這邊下載的是texlive2025.iso最新版的&#xff0c;下載什么版本看自己需求&#xff0c;只要下載后綴未.iso的即可。為避免錯誤&am…

【深入淺出STM32(1)】 GPIO 深度解析:引腳特性、工作模式、速度選型及上下拉電阻詳解

GPIO 深度解析&#xff1a;引腳特性、工作模式、速度選型及上下拉電阻詳解一、GPIO概述二、GPIO的工作模式1、簡述&#xff08;1&#xff09;4種輸入模式&#xff08;2&#xff09;4種輸出模式&#xff08;3&#xff09;4種最大輸出速度2、引腳速度&#xff08;1&#xff09;輸…

第1節 大模型分布式推理基礎與技術體系

前言:為什么分布式推理是大模型時代的核心能力? 當我們談論大模型時,往往首先想到的是訓練階段的千億參數、千卡集群和數月的訓練周期。但對于商業落地而言,推理階段的技術挑戰可能比訓練更復雜。 2025年,某頭部AI公司推出的130B參數模型在單機推理時面臨兩個選擇:要么…

《軟件工程導論》實驗報告一 軟件工程文檔

目 錄 一、實驗目的 二、實驗環境 三、實驗內容與步驟 四、實驗心得 一、實驗目的 1. 理解軟件工程的基本概念&#xff0c;熟悉軟件&#xff0c;軟件生命周期&#xff0c;軟件生存周期過程和軟件生命周期各階段的定義和內容。 2. 了解軟件工程文檔的類別、內容及撰寫軟件工…

基于elk實現分布式日志

1.基本介紹 1.1 什么是分布式日志 在分布式應用中&#xff0c;日志被分散在儲存不同的設備上。如果你管理數十上百臺服務器&#xff0c;你還在使用依次登錄每臺機器的傳統方法查閱日志。這樣是不是感覺很繁瑣和效率低下。所以我們使用集中化的日志管理&#xff0c;分布式日志…

多模態RAG賽題實戰之策略優化--Datawhale AI夏令營

科大訊飛AI大賽&#xff08;多模態RAG方向&#xff09; - Datawhale 項目流程圖 1、升級數據解析方案&#xff1a;從 fitz 到 MinerU PyMuPDF&#xff08;fitz&#xff09;是基于規則的方式提取pdf里面的數據&#xff1b;MinerU是基于深度學習模型通過把PDF內的頁面看成是圖片…

09--解密棧與隊列:數據結構核心原理

1. 棧 1.1. 棧的簡介 棧 是一種 特殊的線性表&#xff0c;具有數據 先進后出 特點。 注意&#xff1a; stack本身 不支持迭代器操作 主要原因是因為stack不支持數據的隨機訪問&#xff0c;必須保證數據先進后出的特點。stack在CPP庫中實現為一種 容器適配器 所謂容器適配器&a…

打造專屬 React 腳手架:從 0 到 1 開發 CLI 工具

前言: 在前端開發中&#xff0c;重復搭建項目環境是個低效的事兒。要是團隊技術棧固定&#xff08;比如 React AntD Zustand TS &#xff09;&#xff0c;每次從零開始配路由、狀態管理、UI 組件&#xff0c;既耗時又容易出錯。這時候&#xff0c;自定義 CLI 腳手架 就派上…

Python day43

浙大疏錦行 Python day43 import torch import numpy as np import pandas as pd import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.utils.data import Da…

python基于Hadoop的超市數據分析系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 摘要&…

如何用 COLMAP 制作 Blender 格式的數據集

如何用 COLMAP 制作 Blender 格式的數據集并劃分出 transforms_train.json、transforms_val.json 和 transforms_test.json。 一、什么是 Blender 格式數據集? Blender 格式數據集是 Nerf 和 Nerfstudio 常用的輸入格式,其核心是包含了相機內外參的 JSON 文件,一般命名為:…