22#ifndef BOARD_DETECTOR_H
33#define BOARD_DETECTOR_H
44
5- #include " core/logger.hpp"
5+ #include < cstdint>
6+
67#include < driver/gpio.h>
78#include < driver/i2c_master.h>
89#include < driver/i2s_pdm.h>
910#include < driver/i2s_std.h>
1011#include < freertos/FreeRTOS.h>
1112#include < freertos/task.h>
12- #include < cstdint>
13+
14+ #include " core/logger.hpp"
1315
1416namespace porting {
1517
16- enum class BoardType {
17- UNKNOWN = 0 ,
18- XIAO_S3 ,
19- RESPEAKER_LITE ,
20- RESPEAKER_XVF3800
21- };
18+ enum class BoardType { UNKNOWN = 0 , XIAO_S3 , RESPEAKER_LITE , RESPEAKER_XVF3800 };
2219
23- struct BoardConfig {
20+ struct BoardConfig
21+ {
2422 BoardType type;
25- const char * name;
23+ const char * name;
2624 bool use_pdm;
2725 gpio_num_t pdm_clk;
2826 gpio_num_t pdm_din;
@@ -32,68 +30,87 @@ struct BoardConfig {
3230 gpio_num_t i2s_dout;
3331 i2s_role_t i2s_role;
3432 uint32_t sample_rate;
35- const int * gpio_pins;
33+ const int * gpio_pins;
3634 size_t gpio_pins_count;
3735};
3836
39- inline BoardType detectBoard () noexcept {
40- LOG (INFO , " Detecting board type via I2C..." );
41-
42- i2c_master_bus_config_t i2c_cfg = {
43- .i2c_port = I2C_NUM_0 ,
44- .sda_io_num = GPIO_NUM_5 ,
45- .scl_io_num = GPIO_NUM_6 ,
46- .clk_source = I2C_CLK_SRC_DEFAULT ,
47- .glitch_ignore_cnt = 7 ,
48- .flags = {.enable_internal_pullup = true },
49- };
50-
51- i2c_master_bus_handle_t bus_handle;
52- if (i2c_new_master_bus (&i2c_cfg, &bus_handle) != ESP_OK ) {
53- LOG (WARNING , " Failed to init I2C, defaulting to XIAO S3" );
54- return BoardType::XIAO_S3 ;
55- }
37+ #ifdef DYN_BOARD_TYPE_FROM_I2C_ONCE
38+ #error "DYN_BOARD_TYPE_FROM_I2C is already defined"
39+ #endif
40+ #define DYN_BOARD_TYPE_FROM_I2C_ONCE porting::__DynamicBoardTypeFromI2COnce ()
41+
42+ inline BoardType __DynamicBoardTypeFromI2COnce() noexcept
43+ {
44+ static auto type = []() noexcept -> BoardType {
45+ LOG (INFO , " Detecting board type via I2C..." );
46+
47+ i2c_master_bus_config_t i2c_cfg = {
48+ .i2c_port = I2C_NUM_0 ,
49+ .sda_io_num = GPIO_NUM_5 ,
50+ .scl_io_num = GPIO_NUM_6 ,
51+ .clk_source = I2C_CLK_SRC_DEFAULT ,
52+ .glitch_ignore_cnt = 7 ,
53+ .intr_priority = 1 ,
54+ .trans_queue_depth = 0 ,
55+ .flags = { .enable_internal_pullup = true , .allow_pd = 0 },
56+ };
57+
58+ i2c_master_bus_handle_t bus_handle;
59+ if (i2c_new_master_bus (&i2c_cfg, &bus_handle) != ESP_OK )
60+ {
61+ LOG (WARNING , " Failed to init I2C, defaulting to XIAO S3" );
62+ return BoardType::XIAO_S3 ;
63+ }
64+
65+ // Check for ReSpeaker Lite (I2C address 0x42)
66+ if (i2c_master_probe (bus_handle, 0x42 , 100 ) == ESP_OK )
67+ {
68+ i2c_del_master_bus (bus_handle);
69+ LOG (INFO , " Detected: ReSpeaker Lite (I2C 0x42)" );
70+ return BoardType::RESPEAKER_LITE ;
71+ }
72+
73+ // Check for 0x2C device
74+ if (i2c_master_probe (bus_handle, 0x2C , 100 ) == ESP_OK )
75+ {
76+ i2c_del_master_bus (bus_handle);
77+ LOG (INFO , " Detected: ReSpeaker XVF3800 (I2C 0x2C)" );
78+ return BoardType::RESPEAKER_XVF3800 ;
79+ }
5680
57- // Check for ReSpeaker Lite (I2C address 0x42)
58- if (i2c_master_probe (bus_handle, 0x42 , 100 ) == ESP_OK ) {
5981 i2c_del_master_bus (bus_handle);
60- LOG (INFO , " Detected: ReSpeaker Lite (I2C 0x42)" );
61- return BoardType::RESPEAKER_LITE ;
62- }
6382
64- // Check for 0x2C device
65- if (i2c_master_probe (bus_handle, 0x2C , 100 ) == ESP_OK ) {
66- i2c_del_master_bus (bus_handle);
67- LOG (INFO , " Detected: ReSpeaker XVF3800 (I2C 0x2C)" );
68- return BoardType::RESPEAKER_XVF3800 ;
69- }
70-
71- i2c_del_master_bus (bus_handle);
83+ LOG (INFO , " Default: XIAO ESP32-S3" );
84+ return BoardType::XIAO_S3 ;
85+ }();
7286
73- // No I2C device found, assume XIAO S3
74- LOG (INFO , " Detected: XIAO ESP32-S3 (default)" );
75- return BoardType::XIAO_S3 ;
87+ return type;
7688}
7789
78- inline const BoardConfig& getBoardConfig (BoardType type) noexcept {
90+ #ifdef DYN_BOARD_CONFIG_FORM_TYPE
91+ #error "DYN_BOARD_CONFIG_FORM_TYPE is already defined"
92+ #endif
93+ #define DYN_BOARD_CONFIG_FORM_TYPE (type ) porting::__DynamicBoardConfigFromType(type)
94+
95+ inline const BoardConfig &__DynamicBoardConfigFromType (BoardType type) noexcept
96+ {
7997 static const int xiao_s3_gpios[] = { 1 , 2 , 3 , 21 , 41 , 42 };
8098 static const int respeaker_lite_gpios[] = { 1 , 2 , 3 , 21 , 41 , 42 };
8199 static const int respeaker_xvf3800_gpios[] = { 1 , 3 , 4 , 43 , 44 };
82100
83101 static const BoardConfig configs[] = {
84- { BoardType::XIAO_S3 , " XIAO ESP32-S3" , true , GPIO_NUM_42 , GPIO_NUM_41 ,
85- GPIO_NUM_NC , GPIO_NUM_NC , GPIO_NUM_NC , GPIO_NUM_NC , I2S_ROLE_MASTER , 44100 ,
86- xiao_s3_gpios, 6 },
87- { BoardType::RESPEAKER_LITE , " ReSpeaker Lite" , false , GPIO_NUM_NC , GPIO_NUM_NC ,
88- GPIO_NUM_8 , GPIO_NUM_7 , GPIO_NUM_44 , GPIO_NUM_43 , I2S_ROLE_SLAVE , 16000 ,
89- respeaker_lite_gpios, 6 },
90- { BoardType::RESPEAKER_XVF3800 , " ReSpeaker XVF3800" , false , GPIO_NUM_NC , GPIO_NUM_NC ,
91- GPIO_NUM_8 , GPIO_NUM_7 , GPIO_NUM_43 , GPIO_NUM_44 , I2S_ROLE_MASTER , 16000 ,
92- respeaker_xvf3800_gpios, 5 },
102+ { BoardType::XIAO_S3 , " XIAO ESP32-S3" , true , GPIO_NUM_42 , GPIO_NUM_41 , GPIO_NUM_NC , GPIO_NUM_NC , GPIO_NUM_NC ,
103+ GPIO_NUM_NC , I2S_ROLE_MASTER , 44100 , xiao_s3_gpios, 6 },
104+ { BoardType::RESPEAKER_LITE , " ReSpeaker Lite" , false , GPIO_NUM_NC , GPIO_NUM_NC , GPIO_NUM_8 , GPIO_NUM_7 ,
105+ GPIO_NUM_44 , GPIO_NUM_43 , I2S_ROLE_SLAVE , 16000 , respeaker_lite_gpios, 6 },
106+ { BoardType::RESPEAKER_XVF3800 , " ReSpeaker XVF3800" , false , GPIO_NUM_NC , GPIO_NUM_NC , GPIO_NUM_8 , GPIO_NUM_7 ,
107+ GPIO_NUM_43 , GPIO_NUM_44 , I2S_ROLE_MASTER , 16000 , respeaker_xvf3800_gpios, 5 },
93108 };
94109
95- for (const auto & cfg : configs) {
96- if (cfg.type == type) return cfg;
110+ for (const auto &cfg: configs)
111+ {
112+ if (cfg.type == type)
113+ return cfg;
97114 }
98115 return configs[0 ]; // Default to ESP32-S3
99116}
0 commit comments