taiji_pi_s3.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include "wifi_board.h"
  2. #include "audio_codecs/no_audio_codec.h"
  3. #include "display/lcd_display.h"
  4. #include "application.h"
  5. #include "i2c_device.h"
  6. #include "config.h"
  7. #include "iot/thing_manager.h"
  8. #include <esp_log.h>
  9. #include <driver/i2c.h>
  10. #include <driver/ledc.h>
  11. #include <wifi_station.h>
  12. #include <esp_lcd_panel_io.h>
  13. #include <esp_lcd_panel_ops.h>
  14. #include <esp_lcd_st77916.h>
  15. #include <esp_timer.h>
  16. #define TAG "TaijiPiS3Board"
  17. LV_FONT_DECLARE(font_puhui_20_4);
  18. LV_FONT_DECLARE(font_awesome_20_4);
  19. class Cst816s : public I2cDevice {
  20. public:
  21. struct TouchPoint_t {
  22. int num = 0;
  23. int x = -1;
  24. int y = -1;
  25. };
  26. Cst816s(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
  27. uint8_t chip_id = ReadReg(0xA3);
  28. ESP_LOGI(TAG, "Get chip ID: 0x%02X", chip_id);
  29. read_buffer_ = new uint8_t[6];
  30. }
  31. ~Cst816s() {
  32. delete[] read_buffer_;
  33. }
  34. void UpdateTouchPoint() {
  35. ReadRegs(0x02, read_buffer_, 6);
  36. tp_.num = read_buffer_[0] & 0x0F;
  37. tp_.x = ((read_buffer_[1] & 0x0F) << 8) | read_buffer_[2];
  38. tp_.y = ((read_buffer_[3] & 0x0F) << 8) | read_buffer_[4];
  39. }
  40. const TouchPoint_t& GetTouchPoint() {
  41. return tp_;
  42. }
  43. private:
  44. uint8_t* read_buffer_ = nullptr;
  45. TouchPoint_t tp_;
  46. };
  47. class TaijiPiS3Board : public WifiBoard {
  48. private:
  49. i2c_master_bus_handle_t i2c_bus_;
  50. Cst816s* cst816s_;
  51. LcdDisplay* display_;
  52. esp_timer_handle_t touchpad_timer_;
  53. void InitializeI2c() {
  54. // Initialize I2C peripheral
  55. i2c_master_bus_config_t i2c_bus_cfg = {
  56. .i2c_port = (i2c_port_t)1,
  57. .sda_io_num = TP_PIN_NUM_TP_SDA,
  58. .scl_io_num = TP_PIN_NUM_TP_SCL,
  59. .clk_source = I2C_CLK_SRC_DEFAULT,
  60. .glitch_ignore_cnt = 7,
  61. .intr_priority = 0,
  62. .trans_queue_depth = 0,
  63. .flags = {
  64. .enable_internal_pullup = 1,
  65. },
  66. };
  67. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  68. }
  69. static void touchpad_timer_callback(void* arg) {
  70. auto& board = (TaijiPiS3Board&)Board::GetInstance();
  71. auto touchpad = board.GetTouchpad();
  72. static bool was_touched = false;
  73. static int64_t touch_start_time = 0;
  74. const int64_t TOUCH_THRESHOLD_MS = 500; // 触摸时长阈值,超过500ms视为长按
  75. touchpad->UpdateTouchPoint();
  76. auto touch_point = touchpad->GetTouchPoint();
  77. // 检测触摸开始
  78. if (touch_point.num > 0 && !was_touched) {
  79. was_touched = true;
  80. touch_start_time = esp_timer_get_time() / 1000; // 转换为毫秒
  81. }
  82. // 检测触摸释放
  83. else if (touch_point.num == 0 && was_touched) {
  84. was_touched = false;
  85. int64_t touch_duration = (esp_timer_get_time() / 1000) - touch_start_time;
  86. // 只有短触才触发
  87. if (touch_duration < TOUCH_THRESHOLD_MS) {
  88. auto& app = Application::GetInstance();
  89. if (app.GetDeviceState() == kDeviceStateStarting &&
  90. !WifiStation::GetInstance().IsConnected()) {
  91. board.ResetWifiConfiguration();
  92. }
  93. app.ToggleChatState();
  94. }
  95. }
  96. }
  97. void InitializeCst816sTouchPad() {
  98. ESP_LOGI(TAG, "Init Cst816s");
  99. cst816s_ = new Cst816s(i2c_bus_, 0x15);
  100. // 创建定时器,10ms 间隔
  101. esp_timer_create_args_t timer_args = {
  102. .callback = touchpad_timer_callback,
  103. .arg = NULL,
  104. .dispatch_method = ESP_TIMER_TASK,
  105. .name = "touchpad_timer",
  106. .skip_unhandled_events = true,
  107. };
  108. ESP_ERROR_CHECK(esp_timer_create(&timer_args, &touchpad_timer_));
  109. ESP_ERROR_CHECK(esp_timer_start_periodic(touchpad_timer_, 10 * 1000)); // 10ms = 10000us
  110. }
  111. void BspLcdBlSet(int brightness_percent)
  112. {
  113. if (brightness_percent > 100) {
  114. brightness_percent = 100;
  115. }
  116. if (brightness_percent < 0) {
  117. brightness_percent = 0;
  118. }
  119. ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent);
  120. uint32_t duty_cycle = (1023 * brightness_percent) / 100; // LEDC resolution set to 10bits, thus: 100% = 1023
  121. ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty_cycle);
  122. ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
  123. }
  124. void InitializeSpi() {
  125. ESP_LOGI(TAG, "Initialize QSPI bus");
  126. const spi_bus_config_t bus_config = TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
  127. QSPI_PIN_NUM_LCD_DATA0,
  128. QSPI_PIN_NUM_LCD_DATA1,
  129. QSPI_PIN_NUM_LCD_DATA2,
  130. QSPI_PIN_NUM_LCD_DATA3,
  131. QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
  132. ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
  133. }
  134. void Initializest77916Display() {
  135. esp_lcd_panel_io_handle_t panel_io = nullptr;
  136. esp_lcd_panel_handle_t panel = nullptr;
  137. ESP_LOGI(TAG, "Install panel IO");
  138. const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(QSPI_PIN_NUM_LCD_CS, NULL, NULL);
  139. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)QSPI_LCD_HOST, &io_config, &panel_io));
  140. ESP_LOGI(TAG, "Install ST77916 panel driver");
  141. st77916_vendor_config_t vendor_config = {
  142. .flags = {
  143. .use_qspi_interface = 1,
  144. },
  145. };
  146. const esp_lcd_panel_dev_config_t panel_config = {
  147. .reset_gpio_num = QSPI_PIN_NUM_LCD_RST,
  148. .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
  149. .bits_per_pixel = QSPI_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
  150. .vendor_config = &vendor_config,
  151. };
  152. ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(panel_io, &panel_config, &panel));
  153. esp_lcd_panel_reset(panel);
  154. esp_lcd_panel_init(panel);
  155. esp_lcd_panel_disp_on_off(panel, true);
  156. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  157. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  158. display_ = new SpiLcdDisplay(panel_io, panel,
  159. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  160. {
  161. .text_font = &font_puhui_20_4,
  162. .icon_font = &font_awesome_20_4,
  163. .emoji_font = font_emoji_64_init(),
  164. });
  165. }
  166. // 物联网初始化,添加对 AI 可见设备
  167. void InitializeIot() {
  168. auto& thing_manager = iot::ThingManager::GetInstance();
  169. thing_manager.AddThing(iot::CreateThing("Speaker"));
  170. thing_manager.AddThing(iot::CreateThing("Backlight"));
  171. }
  172. void InitializeMute() {
  173. gpio_reset_pin(AUDIO_MUTE_PIN);
  174. /* Set the GPIO as a push/pull output */
  175. gpio_set_direction(AUDIO_MUTE_PIN, GPIO_MODE_OUTPUT);
  176. gpio_set_level(AUDIO_MUTE_PIN, 1);
  177. }
  178. public:
  179. TaijiPiS3Board() {
  180. InitializeI2c();
  181. InitializeCst816sTouchPad();
  182. InitializeSpi();
  183. Initializest77916Display();
  184. InitializeIot();
  185. InitializeMute();
  186. GetBacklight()->RestoreBrightness();
  187. }
  188. virtual AudioCodec* GetAudioCodec() override {
  189. static NoAudioCodecSimplex audio_codec(
  190. AUDIO_INPUT_SAMPLE_RATE,
  191. AUDIO_OUTPUT_SAMPLE_RATE,
  192. AUDIO_I2S_GPIO_BCLK,
  193. AUDIO_I2S_GPIO_WS,
  194. AUDIO_I2S_GPIO_DOUT,
  195. AUDIO_MIC_SCK_PIN,
  196. AUDIO_MIC_WS_PIN,
  197. AUDIO_MIC_SD_PIN
  198. );
  199. return &audio_codec;
  200. }
  201. virtual Display* GetDisplay() override {
  202. return display_;
  203. }
  204. virtual Backlight* GetBacklight() override {
  205. static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
  206. return &backlight;
  207. }
  208. Cst816s* GetTouchpad() {
  209. return cst816s_;
  210. }
  211. };
  212. DECLARE_BOARD(TaijiPiS3Board);