reference: 早先那版 C 写的装甲板固件(ESP-IDF 工程)
`armor/` 是它的 Rust 改写版,这一份留着当参考:ADC 阈值的 2000 就是从它标定出来的 (`.env.example` 里那句 "same as the reference firmware" 指的就是它),而且它的 README 记着实测设备与 MAC,换硬件时是有用的现场记录。 只收了 20 个源文件。它自带的 `.gitignore` 已经排掉 `build/`(211 MB 的 ESP-IDF 构建产物) 与生成的 `sdkconfig`,所以仓库里不会多出这些东西。 两处顺带处理: - `reference/armor/.git` 是一个**空的**仓库壳(`git init` 过,零提交、零 remote、零 ref), 而外层 git 正因为它的存在而拒绝索引 `reference/` 下的任何文件 (`error: 'reference/armor/' does not have a commit checked out`)。它被挪到 `desktop/.dev/backup/reference-armor-git`(可逆,且该目录已被忽略),不是删除。 - 它的 README 指着 `../armor-platformio-backup/`,那份备份并不存在。改成明说"没有进仓库", 免得以后有人照着找一个不存在的目录。 另外把 `/docs/` 加进 .gitignore:那是工作区里另起的一个 Astro 文档站,与本仓库无关。
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* ESP-IDF entry point for the "armor" hit-detection node (ESP32-C3).
|
||||
*
|
||||
* This is the ESP-IDF counterpart of the original Arduino `main.cpp`:
|
||||
* setup() -> app_main()
|
||||
* loop() -> hit_task() (only ran Hit::onLoop())
|
||||
* loop2() -> loop2_task() (button, ESP-NOW and serial bridging)
|
||||
* Serial -> USB Serial/JTAG console + driver (CDC protocol)
|
||||
* Serial0 -> UART0 on GPIO20/21 (DBUS bridge)
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "air.hpp"
|
||||
#include "armor_time.hpp"
|
||||
#include "button.hpp"
|
||||
#include "hit.hpp"
|
||||
#include "storage.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char *TAG = "armor";
|
||||
|
||||
constexpr uint32_t TIMEOUT_MS = 100;
|
||||
|
||||
// GPIO9 is the on-board BOOT button of the ESP32-C3 DevKitM-1, active low.
|
||||
// Original: `OneButton button(9, true);`
|
||||
Button button(9, true);
|
||||
|
||||
volatile bool g_click = false;
|
||||
volatile bool g_long_click = false;
|
||||
volatile uint32_t g_last_cdc_receive_ms = 0;
|
||||
|
||||
void handleClick() {
|
||||
g_click = true;
|
||||
}
|
||||
|
||||
void handleLongPressStart() {
|
||||
g_long_click = true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- UART0 -----
|
||||
// Original: `Serial0.begin(115200, SERIAL_8N1, 20, 21);` (rx=20, tx=21)
|
||||
constexpr uart_port_t DBUS_UART = UART_NUM_0;
|
||||
constexpr int DBUS_UART_RX = 20;
|
||||
constexpr int DBUS_UART_TX = 21;
|
||||
|
||||
void serial0_begin() {
|
||||
uart_config_t cfg = {};
|
||||
cfg.baud_rate = 115200;
|
||||
cfg.data_bits = UART_DATA_8_BITS;
|
||||
cfg.parity = UART_PARITY_DISABLE;
|
||||
cfg.stop_bits = UART_STOP_BITS_1;
|
||||
cfg.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||
cfg.source_clk = UART_SCLK_DEFAULT;
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(DBUS_UART, 256, 256, 0, nullptr, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(DBUS_UART, &cfg));
|
||||
ESP_ERROR_CHECK(uart_set_pin(DBUS_UART, DBUS_UART_TX, DBUS_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- USB CDC -------
|
||||
// Replaces Arduino's `serialEvent()`: 10-byte DBUS frames arrive over the USB
|
||||
// CDC port, and the original truncated/committed them in 10-byte units.
|
||||
void cdc_task(void *) {
|
||||
uint8_t chunk[32];
|
||||
uint8_t frame[10];
|
||||
size_t frame_len = 0;
|
||||
|
||||
while (true) {
|
||||
const int n = usb_serial_jtag_read_bytes(chunk, sizeof(chunk), pdMS_TO_TICKS(20));
|
||||
for (int i = 0; i < n; i++) {
|
||||
frame[frame_len++] = chunk[i];
|
||||
if (frame_len == sizeof(frame)) {
|
||||
Air::dbusSet(frame, sizeof(frame));
|
||||
g_last_cdc_receive_ms = millis();
|
||||
frame_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ business -----
|
||||
void handle_air() {
|
||||
static Air::packet_t peer_packet_last;
|
||||
|
||||
// 处理收到的数据包
|
||||
// 颜色变化
|
||||
if (Air::peer_packet.color != peer_packet_last.color && Air::peer_packet.color != 0) {
|
||||
Hit::color = Air::peer_packet.color;
|
||||
Storage::putUInt("color", Hit::color);
|
||||
}
|
||||
// 击打次数变化
|
||||
if (Air::peer_packet.hit_cnt != peer_packet_last.hit_cnt) {
|
||||
Hit::last_hit_ms = millis();
|
||||
}
|
||||
peer_packet_last = Air::peer_packet;
|
||||
|
||||
// 发送自己的数据包
|
||||
Air::my_packet.color = Hit::color;
|
||||
Air::my_packet.hit_cnt = Hit::hit_cnt;
|
||||
if (millis() - g_last_cdc_receive_ms > TIMEOUT_MS) { // 超时数据清零
|
||||
Air::dbusClear();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_serial() {
|
||||
// 串口发送 DBUS 数据
|
||||
if (millis() - Air::last_air_ms > TIMEOUT_MS) { // 超时数据清零
|
||||
memset(Air::peer_packet.dbus, 0, sizeof(Air::peer_packet.dbus));
|
||||
}
|
||||
uart_write_bytes(DBUS_UART, Air::peer_packet.dbus, sizeof(Air::peer_packet.dbus));
|
||||
uart_wait_tx_done(DBUS_UART, pdMS_TO_TICKS(20)); // Serial0.flush()
|
||||
|
||||
// CDC发送:颜色、击打次数、信号强度(tx, rx)、距离最后一次收到消息的毫秒数
|
||||
const uint32_t latency_ms = millis() - Air::last_air_ms;
|
||||
printf("%d,%d,%d,%d,%d\n",
|
||||
static_cast<int>(Air::my_packet.color),
|
||||
static_cast<int>(Air::peer_packet.hit_cnt),
|
||||
static_cast<int>(Air::peer_packet.rssi),
|
||||
static_cast<int>(Air::my_packet.rssi),
|
||||
static_cast<int>(latency_ms));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- tasks -------
|
||||
// Equivalent of the original Arduino `loop2()`.
|
||||
void loop2_task(void *) {
|
||||
while (true) {
|
||||
button.tick();
|
||||
Air::onLoop();
|
||||
|
||||
if (!Air::is_pairing) { // 不在配对中
|
||||
if (g_long_click) { // 长按配对
|
||||
Air::entryPairing();
|
||||
Hit::detect_hit = false;
|
||||
} else if (g_click) { // 短按切换颜色
|
||||
Hit::color = (Hit::color == Hit::RED) ? Hit::BLUE : Hit::RED;
|
||||
Storage::putUInt("color", Hit::color);
|
||||
} else { // 正常运行业务逻辑
|
||||
handle_air();
|
||||
handle_serial();
|
||||
}
|
||||
} else { // 在配对中
|
||||
if (g_click) { // 短按保存配对
|
||||
Air::savePairing();
|
||||
Hit::color = Hit::RED;
|
||||
Storage::putUInt("color", Hit::color);
|
||||
Hit::detect_hit = true;
|
||||
} else {
|
||||
Hit::color = Air::pairing_found ? Hit::GREEN : Hit::YELLOW;
|
||||
}
|
||||
}
|
||||
|
||||
g_click = false;
|
||||
g_long_click = false;
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of the original Arduino `loop()`.
|
||||
void hit_task(void *) {
|
||||
while (true) {
|
||||
Hit::onLoop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
// 初始化 NVS(原 Preferences 底层就是 NVS)
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
ESP_ERROR_CHECK(Storage::begin("armor"));
|
||||
|
||||
// With CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG the console initialisation has
|
||||
// already installed the USB Serial/JTAG driver, so only install it when
|
||||
// that did not happen; reading raw CDC bytes then works either way.
|
||||
if (!usb_serial_jtag_is_driver_installed()) {
|
||||
usb_serial_jtag_driver_config_t usb_cfg = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
|
||||
usb_cfg.rx_buffer_size = 256;
|
||||
if (usb_serial_jtag_driver_install(&usb_cfg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "USB Serial/JTAG driver unavailable, CDC protocol disabled");
|
||||
}
|
||||
}
|
||||
|
||||
serial0_begin();
|
||||
|
||||
// 绑定回调函数
|
||||
button.attachClick(handleClick);
|
||||
button.attachLongPressStart(handleLongPressStart);
|
||||
button.setClickMs(50); // 短按时间(毫秒)
|
||||
button.setPressMs(500); // 长按时间(毫秒)
|
||||
|
||||
Hit::begin();
|
||||
Air::begin();
|
||||
|
||||
ESP_LOGI(TAG, "armor node started");
|
||||
|
||||
xTaskCreate(cdc_task, "cdc", 3072, nullptr, 5, nullptr);
|
||||
xTaskCreate(loop2_task, "loop2", 8192, nullptr, 5, nullptr);
|
||||
xTaskCreate(hit_task, "hit", 4096, nullptr, 5, nullptr);
|
||||
}
|
||||
Reference in New Issue
Block a user