diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb101fe5..04e0f8b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,15 @@ jobs: build: runs-on: ubuntu-latest + continue-on-error: true + + strategy: + matrix: + test: + - path: '.' + target: esp32s3 + - path: 'components/box-emu/example' + target: esp32s3 steps: - name: Checkout repo @@ -17,5 +26,5 @@ jobs: uses: espressif/esp-idf-ci-action@v1 with: esp_idf_version: release-v5.2 - target: esp32s3 - path: '.' + target: ${{matrix.test.target}} + path: ${{matrix.test.path}} diff --git a/CMakeLists.txt b/CMakeLists.txt index 1699558e..ceb349b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,7 @@ set(EMULATOR_COMPONENTS set( COMPONENTS - "main esptool_py esp_lcd esp_psram task format display display_drivers monitor timer ${EMULATOR_COMPONENTS} box-emu-hal gui menu" + "main esptool_py esp_lcd esp_psram task format display display_drivers monitor timer ${EMULATOR_COMPONENTS} box-emu gui menu" CACHE STRING "List of components to include" ) diff --git a/components/box-emu-hal/CMakeLists.txt b/components/box-emu-hal/CMakeLists.txt deleted file mode 100644 index 10ce0b37..00000000 --- a/components/box-emu-hal/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -idf_component_register( - INCLUDE_DIRS "include" - SRC_DIRS "src" - REQUIRES "driver" "heap" "fatfs" "esp_lcd" "esp_psram" "hal" "usb" "esp_tinyusb" "spi_flash" "nvs_flash" "codec" "adc" "aw9523" "button" "display" "display_drivers" "mcp23x17" "input_drivers" "tt21100" "gt911" "drv2605" "event_manager" "i2c" "task" "timer" "serialization" "max1704x" - ) diff --git a/components/box-emu-hal/Kconfig.projbuild b/components/box-emu-hal/Kconfig.projbuild deleted file mode 100644 index ee319254..00000000 --- a/components/box-emu-hal/Kconfig.projbuild +++ /dev/null @@ -1,14 +0,0 @@ -menu "BOX Emulator Configuration" - - choice - prompt "Module Configuration" - default HARDWARE_BOX - help - Select which display + SoC module you're using. - config HARDWARE_BOX - bool "ESP32-S3-BOX" - config HARDWARE_BOX_3 - bool "ESP32-S3-BOX-3" - endchoice - -endmenu diff --git a/components/box-emu-hal/include/box.hpp b/components/box-emu-hal/include/box.hpp deleted file mode 100644 index 2950e737..00000000 --- a/components/box-emu-hal/include/box.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "hal/spi_types.h" -#include "driver/gpio.h" -#include "driver/i2s_std.h" -#include "driver/spi_master.h" - -#include "i2c.hpp" -#include "st7789.hpp" -#include "touchpad_input.hpp" -#include "tt21100.hpp" - -static constexpr std::string_view dev_kit = "ESP32-S3-BOX"; - -// internal i2c (touchscreen, audio codec) -static constexpr auto internal_i2c_port = I2C_NUM_0; -static constexpr auto internal_i2c_clock_speed = 400 * 1000; -static constexpr gpio_num_t internal_i2c_sda = GPIO_NUM_8; -static constexpr gpio_num_t internal_i2c_scl = GPIO_NUM_18; - -// external I2c (peripherals) -static constexpr auto external_i2c_port = I2C_NUM_1; -static constexpr auto external_i2c_clock_speed = 400 * 1000; -static constexpr gpio_num_t external_i2c_sda = GPIO_NUM_41; -static constexpr gpio_num_t external_i2c_scl = GPIO_NUM_40; - -// LCD -static constexpr int lcd_clock_speed = 60 * 1000 * 1000; -static constexpr auto lcd_spi_num = SPI2_HOST; -static constexpr gpio_num_t lcd_cs_io = GPIO_NUM_5; -static constexpr gpio_num_t lcd_mosi_io = GPIO_NUM_6; -static constexpr gpio_num_t lcd_sclk_io = GPIO_NUM_7; -static constexpr gpio_num_t lcd_reset_io = GPIO_NUM_48; -static constexpr gpio_num_t lcd_dc_io = GPIO_NUM_4; -static constexpr gpio_num_t backlight_io = GPIO_NUM_45; -static constexpr size_t lcd_width = 320; -static constexpr size_t lcd_height = 240; -static constexpr bool backlight_value = true; -static constexpr bool reset_value = false; -static constexpr bool invert_colors = true; -static constexpr auto rotation = espp::Display::Rotation::LANDSCAPE; -static constexpr bool mirror_x = true; -static constexpr bool mirror_y = true; -using DisplayDriver = espp::St7789; - -// touch -static constexpr bool touch_swap_xy = false; -static constexpr bool touch_invert_x = true; -static constexpr bool touch_invert_y = false; -static constexpr gpio_num_t touch_interrupt = GPIO_NUM_3; -using TouchDriver = espp::Tt21100; - -// sound -static constexpr gpio_num_t sound_power_pin = GPIO_NUM_46; -static constexpr auto i2s_port = I2S_NUM_0; -static constexpr gpio_num_t i2s_mck_io = GPIO_NUM_2; -static constexpr gpio_num_t i2s_bck_io = GPIO_NUM_17; -static constexpr gpio_num_t i2s_ws_io = GPIO_NUM_47; -static constexpr gpio_num_t i2s_do_io = GPIO_NUM_15; -static constexpr gpio_num_t i2s_di_io = GPIO_NUM_16; -static constexpr gpio_num_t mute_pin = GPIO_NUM_1; - -// uSD card -static constexpr gpio_num_t sdcard_cs = GPIO_NUM_10; -static constexpr gpio_num_t sdcard_mosi = GPIO_NUM_11; -static constexpr gpio_num_t sdcard_miso = GPIO_NUM_13; -static constexpr gpio_num_t sdcard_sclk = GPIO_NUM_12; -static constexpr auto sdcard_spi_num = SPI3_HOST; - diff --git a/components/box-emu-hal/include/box_3.hpp b/components/box-emu-hal/include/box_3.hpp deleted file mode 100644 index 391af741..00000000 --- a/components/box-emu-hal/include/box_3.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "hal/spi_types.h" -#include "driver/gpio.h" -#include "driver/i2s_std.h" -#include "driver/spi_master.h" - -#include "i2c.hpp" -#include "st7789.hpp" -#include "touchpad_input.hpp" -#include "gt911.hpp" - -static constexpr std::string_view dev_kit = "ESP32-S3-BOX-3"; - -// internal i2c (touchscreen, audio codec) -static constexpr auto internal_i2c_port = I2C_NUM_0; -static constexpr auto internal_i2c_clock_speed = 400 * 1000; -static constexpr gpio_num_t internal_i2c_sda = GPIO_NUM_8; -static constexpr gpio_num_t internal_i2c_scl = GPIO_NUM_18; - -// external I2c (peripherals) -static constexpr auto external_i2c_port = I2C_NUM_1; -static constexpr auto external_i2c_clock_speed = 400 * 1000; -static constexpr gpio_num_t external_i2c_sda = GPIO_NUM_41; -static constexpr gpio_num_t external_i2c_scl = GPIO_NUM_40; - -// LCD -static constexpr int lcd_clock_speed = 60 * 1000 * 1000; -static constexpr auto lcd_spi_num = SPI2_HOST; -static constexpr gpio_num_t lcd_cs_io = GPIO_NUM_5; -static constexpr gpio_num_t lcd_mosi_io = GPIO_NUM_6; -static constexpr gpio_num_t lcd_sclk_io = GPIO_NUM_7; -static constexpr gpio_num_t lcd_reset_io = GPIO_NUM_48; -static constexpr gpio_num_t lcd_dc_io = GPIO_NUM_4; -static constexpr gpio_num_t backlight_io = GPIO_NUM_47; // was 45 on ESP32-S3-BOX -static constexpr size_t lcd_width = 320; -static constexpr size_t lcd_height = 240; -static constexpr bool backlight_value = true; -static constexpr bool reset_value = true; // was false on ESP32-S3-BOX -static constexpr bool invert_colors = true; -static constexpr auto rotation = espp::Display::Rotation::LANDSCAPE; -static constexpr bool mirror_x = true; -static constexpr bool mirror_y = true; -using DisplayDriver = espp::St7789; - -// touch -static constexpr bool touch_swap_xy = false; -static constexpr bool touch_invert_x = false; -static constexpr bool touch_invert_y = false; -static constexpr gpio_num_t touch_interrupt = GPIO_NUM_3; -using TouchDriver = espp::Gt911; - -// sound -static constexpr gpio_num_t sound_power_pin = GPIO_NUM_46; -static constexpr auto i2s_port = I2S_NUM_0; -static constexpr gpio_num_t i2s_mck_io = GPIO_NUM_2; -static constexpr gpio_num_t i2s_bck_io = GPIO_NUM_17; -static constexpr gpio_num_t i2s_ws_io = GPIO_NUM_45; // was 47 on ESP32-S3-BOX -static constexpr gpio_num_t i2s_do_io = GPIO_NUM_15; -static constexpr gpio_num_t i2s_di_io = GPIO_NUM_16; -static constexpr gpio_num_t mute_pin = GPIO_NUM_1; - -// uSD card -static constexpr gpio_num_t sdcard_cs = GPIO_NUM_10; -static constexpr gpio_num_t sdcard_mosi = GPIO_NUM_11; -static constexpr gpio_num_t sdcard_miso = GPIO_NUM_13; -static constexpr gpio_num_t sdcard_sclk = GPIO_NUM_12; -static constexpr auto sdcard_spi_num = SPI3_HOST; diff --git a/components/box-emu-hal/include/box_emu_hal.hpp b/components/box-emu-hal/include/box_emu_hal.hpp deleted file mode 100644 index c0554385..00000000 --- a/components/box-emu-hal/include/box_emu_hal.hpp +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "aw9523.hpp" -#include "button.hpp" -#include "event_manager.hpp" -#include "display.hpp" -#include "i2c.hpp" -#include "keypad_input.hpp" -#include "logger.hpp" -#include "max1704x.hpp" -#include "mcp23x17.hpp" -#include "oneshot_adc.hpp" -#include "serialization.hpp" -#include "st7789.hpp" -#include "task.hpp" -#include "timer.hpp" -#include "high_resolution_timer.hpp" -#include "touchpad_input.hpp" - -#if CONFIG_HARDWARE_BOX -#include "box.hpp" -#elif CONFIG_HARDWARE_BOX_3 -#include "box_3.hpp" -#else -#error "Invalid module selection" -#endif - -#include "emu_v0.hpp" -#include "emu_v1.hpp" - -#include "es7210.hpp" -#include "es8311.hpp" -#include "lvgl_inputs.h" -#include "make_color.h" - -#include "battery_info.hpp" -#include "fs_init.hpp" -#include "hal_events.hpp" -#include "input_state.hpp" -#include "mmap.hpp" -#include "statistics.hpp" -#include "usb.hpp" -#include "video_setting.hpp" - -namespace hal { - // top level init function - void init(); - - // i2c / peripheral interfaces - void i2c_init(); - std::shared_ptr get_internal_i2c(); - std::shared_ptr get_external_i2c(); - - // input - void init_input(); - void get_input_state(InputState *state); - - // video - static constexpr int NUM_ROWS_IN_FRAME_BUFFER = 50; - std::shared_ptr get_display(); - uint16_t *get_vram0(); - uint16_t *get_vram1(); - uint8_t *get_frame_buffer0(); - uint8_t *get_frame_buffer1(); - void lcd_write(const uint8_t *data, size_t length, uint32_t user_data); - void lcd_write_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, const uint8_t *data); - void lcd_send_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data); - void lcd_init(); - void set_display_brightness(float brightness); - float get_display_brightness(); - - void init_video_task(); - void set_display_size(size_t width, size_t height); - void set_native_size(size_t width, size_t height, int pitch = -1); - void set_palette(const uint16_t* palette, size_t size = 256); - void push_frame(const void* frame); - - VideoSetting get_video_setting(); - void set_video_setting(const VideoSetting& setting); - - // audio - void audio_init(); - void set_audio_sample_rate(uint32_t sample_rate); - uint32_t get_audio_sample_rate(); - void play_audio(const uint8_t *data, uint32_t num_bytes); - bool is_muted(); - void set_muted(bool mute); - int get_audio_volume(); - void set_audio_volume(int percent); - - // battery - void battery_init(); - std::shared_ptr get_battery(); -} diff --git a/components/box-emu-hal/include/emu_v0.hpp b/components/box-emu-hal/include/emu_v0.hpp deleted file mode 100644 index 019a1092..00000000 --- a/components/box-emu-hal/include/emu_v0.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "mcp23x17.hpp" - -class EmuV0 { -public: - static constexpr uint16_t START_PIN = (1<<0) << 0; // start pin is on port a of the MCP23x17 - static constexpr uint16_t SELECT_PIN = (1<<1) << 0; // select pin is on port a of the MCP23x17 - static constexpr uint16_t UP_PIN = (1<<0) << 8; // up pin is on port b of the MCP23x17 - static constexpr uint16_t DOWN_PIN = (1<<1) << 8; // down pin is on port b of the MCP23x17 - static constexpr uint16_t LEFT_PIN = (1<<2) << 8; // left pin is on port b of the MCP23x17 - static constexpr uint16_t RIGHT_PIN = (1<<3) << 8; // right pin is on port b of the MCP23x17 - static constexpr uint16_t A_PIN = (1<<4) << 8; // a pin is on port b of the MCP23x17 - static constexpr uint16_t B_PIN = (1<<5) << 8; // b pin is on port b of the MCP23x17 - static constexpr uint16_t X_PIN = (1<<6) << 8; // x pin is on port b of the MCP23x17 - static constexpr uint16_t Y_PIN = (1<<7) << 8; // y pin is on port b of the MCP23x17 - static constexpr uint16_t BAT_ALERT_PIN = 0; // battery alert pin doesn't exist on the MCP23x17 - static constexpr uint16_t VOL_UP_PIN = 0; // volume up pin doesn't exist on the MCP23x17 - static constexpr uint16_t VOL_DOWN_PIN = 0; // volume down pin doesn't exist on the MCP23x17 - static constexpr uint16_t DIRECTION_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN); - static constexpr uint16_t INTERRUPT_MASK = (START_PIN | SELECT_PIN); - static constexpr uint16_t INVERT_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN ); // pins are active low so invert them - static constexpr uint8_t PORT_0_DIRECTION_MASK = DIRECTION_MASK & 0xFF; - static constexpr uint8_t PORT_1_DIRECTION_MASK = (DIRECTION_MASK >> 8) & 0xFF; - static constexpr uint8_t PORT_0_INTERRUPT_MASK = INTERRUPT_MASK & 0xFF; - static constexpr uint8_t PORT_1_INTERRUPT_MASK = (INTERRUPT_MASK >> 8) & 0xFF; -}; diff --git a/components/box-emu-hal/include/emu_v1.hpp b/components/box-emu-hal/include/emu_v1.hpp deleted file mode 100644 index 5c614f78..00000000 --- a/components/box-emu-hal/include/emu_v1.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include "aw9523.hpp" -#include "oneshot_adc.hpp" - -class EmuV1 { -public: - using InputDriver = espp::Aw9523; - static constexpr gpio_num_t VBAT_SENSE_PIN = GPIO_NUM_14; // battery sense pin is on GPIO 14 - static constexpr gpio_num_t AW9523_INT_PIN = GPIO_NUM_21; // interrupt pin is on GPIO 21 - static constexpr uint16_t UP_PIN = (1<<0) << 0; // up pin is on port 0 of the AW9523 - static constexpr uint16_t DOWN_PIN = (1<<1) << 0; // down pin is on port 0 of the AW9523 - static constexpr uint16_t LEFT_PIN = (1<<2) << 0; // left pin is on port 0 of the AW9523 - static constexpr uint16_t RIGHT_PIN = (1<<3) << 0; // right pin is on port 0 of the AW9523 - static constexpr uint16_t A_PIN = (1<<4) << 0; // a pin is on port 0 of the AW9523 - static constexpr uint16_t B_PIN = (1<<5) << 0; // b pin is on port 0 of the AW9523 - static constexpr uint16_t X_PIN = (1<<6) << 0; // x pin is on port 0 of the AW9523 - static constexpr uint16_t Y_PIN = (1<<7) << 0; // y pin is on port 0 of the AW9523 - static constexpr uint16_t START_PIN = (1<<0) << 8; // start pin is on port 1 of the AW9523 - static constexpr uint16_t SELECT_PIN = (1<<1) << 8; // select pin is on port 1 of the AW9523 - static constexpr uint16_t BAT_ALERT_PIN = (1<<3) << 8; // battery alert pin is on port 1 of the AW9523 - static constexpr uint16_t VOL_UP_PIN = (1<<4) << 8; // volume up pin is on port 1 of the AW9523 - static constexpr uint16_t VOL_DOWN_PIN = (1<<5) << 8; // volume down pin is on port 1 of the AW9523 - static constexpr uint16_t DIRECTION_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN | BAT_ALERT_PIN | VOL_UP_PIN | VOL_DOWN_PIN); - static constexpr uint16_t INTERRUPT_MASK = (BAT_ALERT_PIN); - static constexpr uint16_t INVERT_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN | BAT_ALERT_PIN | VOL_UP_PIN | VOL_DOWN_PIN); // pins are active low so invert them - static constexpr uint8_t PORT_0_DIRECTION_MASK = DIRECTION_MASK & 0xFF; - static constexpr uint8_t PORT_1_DIRECTION_MASK = (DIRECTION_MASK >> 8) & 0xFF; - static constexpr uint8_t PORT_0_INTERRUPT_MASK = INTERRUPT_MASK & 0xFF; - static constexpr uint8_t PORT_1_INTERRUPT_MASK = (INTERRUPT_MASK >> 8) & 0xFF; - - // ADC for the battery voltage, it's on ADC2_CH3, which is IO14 - static constexpr adc_unit_t BATTERY_ADC_UNIT = ADC_UNIT_2; - static constexpr adc_channel_t BATTERY_ADC_CHANNEL = ADC_CHANNEL_3; -}; diff --git a/components/box-emu-hal/include/fs_init.hpp b/components/box-emu-hal/include/fs_init.hpp deleted file mode 100644 index 2613087a..00000000 --- a/components/box-emu-hal/include/fs_init.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include -#include - -#define MOUNT_POINT "/sdcard" - -#include "hal.hpp" -#include "format.hpp" - -void fs_init(); -sdmmc_card_t *get_sdcard(); diff --git a/components/box-emu-hal/include/hal.hpp b/components/box-emu-hal/include/hal.hpp deleted file mode 100644 index 343dfaa5..00000000 --- a/components/box-emu-hal/include/hal.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -#if defined(CONFIG_HARDWARE_BOX) -#include "box.hpp" -#elif defined(CONFIG_HARDWARE_BOX_3) -#include "box_3.hpp" -#else -#error "Unsupported hardware configuration specified" -#endif diff --git a/components/box-emu-hal/include/input_state.hpp b/components/box-emu-hal/include/input_state.hpp deleted file mode 100644 index 628296cc..00000000 --- a/components/box-emu-hal/include/input_state.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -struct InputState { - int a : 1; - int b : 1; - int x : 1; - int y : 1; - int select : 1; - int start : 1; - int up : 1; - int down : 1; - int left : 1; - int right : 1; -}; - -[[maybe_unused]] static bool operator==(const InputState& lhs, const InputState& rhs) { - return - lhs.a == rhs.a && - lhs.b == rhs.b && - lhs.x == rhs.x && - lhs.y == rhs.y && - lhs.select == rhs.select && - lhs.start == rhs.start && - lhs.up == rhs.up && - lhs.down == rhs.down && - lhs.left == rhs.left && - lhs.right == rhs.right; -} diff --git a/components/box-emu-hal/include/mmap.hpp b/components/box-emu-hal/include/mmap.hpp deleted file mode 100644 index 924c1f2b..00000000 --- a/components/box-emu-hal/include/mmap.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#include -#include "nvs_flash.h" -#include "spi_flash_mmap.h" -#include "esp_partition.h" - -#include "format.hpp" - -void init_memory(); -size_t copy_romdata_to_cart_partition(const std::string& rom_filename); -uint8_t *get_mmapped_romdata(); diff --git a/components/box-emu-hal/include/usb.hpp b/components/box-emu-hal/include/usb.hpp deleted file mode 100644 index de33e6aa..00000000 --- a/components/box-emu-hal/include/usb.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include -#include - -#include "fs_init.hpp" - -bool usb_is_enabled(); -void usb_init(); -void usb_deinit(); diff --git a/components/box-emu-hal/include/video_setting.hpp b/components/box-emu-hal/include/video_setting.hpp deleted file mode 100644 index a54fc8ae..00000000 --- a/components/box-emu-hal/include/video_setting.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -enum class VideoSetting { ORIGINAL, FIT, FILL, MAX_UNUSED }; diff --git a/components/box-emu-hal/src/battery.cpp b/components/box-emu-hal/src/battery.cpp deleted file mode 100644 index 73bb7fc9..00000000 --- a/components/box-emu-hal/src/battery.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "box_emu_hal.hpp" - -static std::shared_ptr battery_{nullptr}; -static std::shared_ptr adc_{nullptr}; -static std::shared_ptr battery_task_; -static bool battery_initialized_ = false; -static std::vector channels; - -using namespace std::chrono_literals; - -void hal::battery_init() { - if (battery_initialized_) { - return; - } - fmt::print("Initializing battery...\n"); - auto i2c = hal::get_external_i2c(); - bool can_communicate = i2c->probe_device(espp::Max1704x::DEFAULT_ADDRESS); - if (!can_communicate) { - fmt::print("Could not communicate with battery!\n"); - // go ahead and set the battery_initialized_ flag to true so we don't try to - // initialize the battery again - battery_initialized_ = true; - return; - } - - // // NOTE: we could also make an ADC for measuring battery voltage - // // make the adc channels - // channels.clear(); - // channels.push_back({ - // .unit = BATTERY_ADC_UNIT, - // .channel = BATTERY_ADC_CHANNEL, - // .attenuation = ADC_ATTEN_DB_12}); - // adc_ = std::make_shared(espp::OneshotAdc::Config{ - // .unit = BATTERY_ADC_UNIT, - // .channels = channels - // }); - - // now make the Max17048 that we'll use to get good state of charge, charge - // rate, etc. - battery_ = std::make_shared(espp::Max1704x::Config{ - .device_address = espp::Max1704x::DEFAULT_ADDRESS, - .write = std::bind(&espp::I2c::write, i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), - .read = std::bind(&espp::I2c::read, i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) - }); - // NOTE: the MAX17048 is tied to the VBAT for its power supply (as you would - // imagine), this means that we cannnot communicate with it if the battery is - // not connected. Therefore, if we are unable to communicate with the battery - // we will just return and not start the battery task. - battery_task_ = std::make_shared(espp::HighResolutionTimer::Config{ - .name = "battery", - .callback = []() { - std::error_code ec; - // get the voltage (V) - auto voltage = battery_->get_battery_voltage(ec); - if (ec) { - fmt::print("Error getting battery voltage: {}\n", ec.message()); - fmt::print("Battery is probably not connected!\n"); - fmt::print("Stopping battery task...\n"); - battery_task_->stop(); - return; - } - // get the state of charge (%) - auto soc = battery_->get_battery_percentage(ec); - if (ec) { - fmt::print("Error getting battery percentage: {}\n", ec.message()); - fmt::print("Battery is probably not connected!\n"); - fmt::print("Stopping battery task...\n"); - battery_task_->stop(); - return; - } - // get the charge rate (+/- % per hour) - auto charge_rate = battery_->get_battery_charge_rate(ec); - if (ec) { - fmt::print("Error getting battery charge rate: {}\n", ec.message()); - fmt::print("Battery is probably not connected!\n"); - fmt::print("Stopping battery task...\n"); - battery_task_->stop(); - return; - } - - // NOTE: we could also get voltage from the adc for the battery if we - // wanted, but the MAX17048 gives us the same voltage anyway - // auto maybe_mv = adc_->read_mv(channels[0]); - // if (maybe_mv.has_value()) { - // // convert mv -> V and from the voltage divider (R1=R2) to real - // // battery volts - // voltage = maybe_mv.value() / 1000.0f * 2.0f; - // } - - // now publish a BatteryInfo struct to the battery_topic - auto battery_info = BatteryInfo{ - .voltage = voltage, - .level = soc, - .charge_rate = charge_rate, - }; - std::vector battery_info_data; - // fmt::print("Publishing battery info: {}\n", battery_info); - auto bytes_serialized = espp::serialize(battery_info, battery_info_data); - if (bytes_serialized == 0) { - return; - } - espp::EventManager::get().publish(battery_topic, battery_info_data); - return; - }}); - uint64_t battery_period_us = 500 * 1000; // 500ms - battery_task_->periodic(battery_period_us); - battery_initialized_ = true; -} - -std::shared_ptr hal::get_battery() { - battery_init(); - return battery_; -} diff --git a/components/box-emu-hal/src/box_emu_hal.cpp b/components/box-emu-hal/src/box_emu_hal.cpp deleted file mode 100644 index 99b1769e..00000000 --- a/components/box-emu-hal/src/box_emu_hal.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "box_emu_hal.hpp" - -void hal::init() { - // init nvs and partition - init_memory(); - // init filesystem - fs_init(); - // init the display subsystem - hal::lcd_init(); - // initialize the i2c buses for touchpad, imu, audio codecs, gamepad, haptics, etc. - hal::i2c_init(); - // init the audio subsystem - hal::audio_init(); - // initialize the rest of the input system which is common to both v0 and v1 - hal::init_input(); - // initialize the video task for the emulators - hal::init_video_task(); - // initialize the battery system - hal::battery_init(); -} diff --git a/components/box-emu-hal/src/fs_init.cpp b/components/box-emu-hal/src/fs_init.cpp deleted file mode 100644 index 562f14a9..00000000 --- a/components/box-emu-hal/src/fs_init.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "fs_init.hpp" - -static sdmmc_card_t *sdcard = nullptr; - -static void sdcard_init() { - esp_err_t ret; - - // Options for mounting the filesystem. If format_if_mount_failed is set to - // true, SD card will be partitioned and formatted in case when mounting - // fails. - esp_vfs_fat_sdmmc_mount_config_t mount_config; - memset(&mount_config, 0, sizeof(mount_config)); - mount_config.format_if_mount_failed = false; - mount_config.max_files = 5; - mount_config.allocation_unit_size = 16 * 1024; - const char mount_point[] = "/sdcard"; - fmt::print("Initializing SD card\n"); - - // Use settings defined above to initialize SD card and mount FAT filesystem. - // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions. - // Please check its source code and implement error recovery when developing - // production applications. - fmt::print("Using SPI peripheral\n"); - - // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) - // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI) - // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; - sdmmc_host_t host = SDSPI_HOST_DEFAULT(); - host.slot = sdcard_spi_num; - // host.max_freq_khz = 20 * 1000; - - spi_bus_config_t bus_cfg; - memset(&bus_cfg, 0, sizeof(bus_cfg)); - bus_cfg.mosi_io_num = sdcard_mosi; - bus_cfg.miso_io_num = sdcard_miso; - bus_cfg.sclk_io_num = sdcard_sclk; - bus_cfg.quadwp_io_num = -1; - bus_cfg.quadhd_io_num = -1; - bus_cfg.max_transfer_sz = 8192; - spi_host_device_t host_id = (spi_host_device_t)host.slot; - ret = spi_bus_initialize(host_id, &bus_cfg, SDSPI_DEFAULT_DMA); - if (ret != ESP_OK) { - fmt::print("Failed to initialize bus.\n"); - return; - } - - // This initializes the slot without card detect (CD) and write protect (WP) signals. - // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. - sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - slot_config.gpio_cs = sdcard_cs; - slot_config.host_id = host_id; - - fmt::print("Mounting filesystem\n"); - ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &sdcard); - - if (ret != ESP_OK) { - if (ret == ESP_FAIL) { - fmt::print("Failed to mount filesystem. " - "If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.\n"); - } else { - fmt::print("Failed to initialize the card ({}). " - "Make sure SD card lines have pull-up resistors in place.\n", esp_err_to_name(ret)); - } - return; - } - fmt::print("Filesystem mounted\n"); - - // Card has been initialized, print its properties - sdmmc_card_print_info(stdout, sdcard); -} - -void fs_init() { - if (sdcard) return; - sdcard_init(); -} - -sdmmc_card_t *get_sdcard() { - return sdcard; -} diff --git a/components/box-emu-hal/src/hal_i2c.cpp b/components/box-emu-hal/src/hal_i2c.cpp deleted file mode 100644 index 79478369..00000000 --- a/components/box-emu-hal/src/hal_i2c.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "box_emu_hal.hpp" - -static std::shared_ptr internal_i2c = nullptr; -static std::shared_ptr external_i2c = nullptr; - -static bool initialized = false; - -void hal::i2c_init() { - if (initialized) return; - // make the i2c on core 1 so that the i2c interrupts are handled on core 1 - espp::Task::run_on_core([]() { - internal_i2c = std::make_shared(espp::I2c::Config{ - .port = internal_i2c_port, - .sda_io_num = internal_i2c_sda, - .scl_io_num = internal_i2c_scl, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .timeout_ms = 100, - }); - external_i2c = std::make_shared(espp::I2c::Config{ - .port = external_i2c_port, - .sda_io_num = external_i2c_sda, - .scl_io_num = external_i2c_scl, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .timeout_ms = 100, - }); - }, 1); - initialized = true; -} - -std::shared_ptr hal::get_internal_i2c() { - i2c_init(); - return internal_i2c; -} - -std::shared_ptr hal::get_external_i2c() { - i2c_init(); - return external_i2c; -} diff --git a/components/box-emu-hal/src/i2s_audio.cpp b/components/box-emu-hal/src/i2s_audio.cpp deleted file mode 100644 index 79190e32..00000000 --- a/components/box-emu-hal/src/i2s_audio.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include "box_emu_hal.hpp" - -static std::atomic muted_{false}; -static std::atomic volume_{60}; - -static std::shared_ptr mute_button; -static std::unique_ptr audio_task; -static TaskHandle_t main_task_handle = NULL; -static i2s_chan_handle_t tx_handle = NULL; - -// Scratch buffers -namespace hal { -static constexpr int DEFAULT_AUDIO_RATE = 48000; -static constexpr int NUM_CHANNELS = 2; -static constexpr int NUM_BYTES_PER_CHANNEL = 2; -static constexpr int UPDATE_FREQUENCY = 60; -static constexpr int AUDIO_BUFFER_SIZE = DEFAULT_AUDIO_RATE * NUM_CHANNELS * NUM_BYTES_PER_CHANNEL / UPDATE_FREQUENCY; -} -static uint8_t tx_buffer[hal::AUDIO_BUFFER_SIZE]; -static StreamBufferHandle_t tx_audio_stream; - -static i2s_std_config_t std_cfg; - -static i2s_event_callbacks_t tx_callbacks_; -std::atomic has_sound{false}; - -static void update_volume_output() { - if (muted_) { - es8311_codec_set_voice_volume(0); - } else { - es8311_codec_set_voice_volume(volume_); - } -} - -void hal::set_muted(bool mute) { - muted_ = mute; - update_volume_output(); -} - -bool hal::is_muted() { - return muted_; -} - -void hal::set_audio_volume(int percent) { - volume_ = percent; - update_volume_output(); -} - -int hal::get_audio_volume() { - return volume_; -} - -uint32_t hal::get_audio_sample_rate() { - return std_cfg.clk_cfg.sample_rate_hz; -} - -void hal::set_audio_sample_rate(uint32_t sample_rate) { - fmt::print("Setting sample rate to {}\n", sample_rate); - // disable i2s - i2s_channel_disable(tx_handle); - // update the config - std_cfg.clk_cfg.sample_rate_hz = sample_rate; - i2s_channel_reconfig_std_clock(tx_handle, &std_cfg.clk_cfg); - // clear the buffer - xStreamBufferReset(tx_audio_stream); - // re-enable i2s - i2s_channel_enable(tx_handle); -} - -static bool IRAM_ATTR audio_task_fn(std::mutex &m, std::condition_variable &cv) -{ - // Queue the next I2S out frame to write - uint16_t available = xStreamBufferBytesAvailable(tx_audio_stream); - available = std::min(available, hal::AUDIO_BUFFER_SIZE); - uint8_t* buffer = &tx_buffer[0]; - static constexpr int BUFF_SIZE = hal::AUDIO_BUFFER_SIZE; - memset(buffer, 0, BUFF_SIZE); - - if (available == 0) { - i2s_channel_write(tx_handle, buffer, BUFF_SIZE, NULL, portMAX_DELAY); - } else { - xStreamBufferReceive(tx_audio_stream, buffer, available, 0); - i2s_channel_write(tx_handle, buffer, available, NULL, portMAX_DELAY); - } - return false; // don't stop the task -} - -static bool IRAM_ATTR tx_sent_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) -{ - // notify the main task that we're done - vTaskNotifyGiveFromISR(main_task_handle, NULL); - return true; -} - -static esp_err_t i2s_driver_init(void) -{ - fmt::print("initializing i2s driver...\n"); - auto ret_val = ESP_OK; - fmt::print("Using newer I2S standard\n"); - i2s_chan_config_t chan_cfg = { \ - .id = i2s_port, - .role = I2S_ROLE_MASTER, - .dma_desc_num = 16, - .dma_frame_num = 48, - .auto_clear = true, - .intr_priority = 0, - }; - - ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, nullptr)); - - std_cfg = { - .clk_cfg = { - .sample_rate_hz = hal::DEFAULT_AUDIO_RATE, - .clk_src = I2S_CLK_SRC_DEFAULT, - .ext_clk_freq_hz = 0, - .mclk_multiple = I2S_MCLK_MULTIPLE_256, - }, - .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), - .gpio_cfg = { - .mclk = i2s_mck_io, - .bclk = i2s_bck_io, - .ws = i2s_ws_io, - .dout = i2s_do_io, - .din = i2s_di_io, - .invert_flags = { - .mclk_inv = false, - .bclk_inv = false, - .ws_inv = false, - }, - }, - }; - std_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256; - - ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); - - tx_audio_stream = xStreamBufferCreate(hal::AUDIO_BUFFER_SIZE*4, 0); - - memset(&tx_callbacks_, 0, sizeof(tx_callbacks_)); - tx_callbacks_.on_sent = tx_sent_callback; - i2s_channel_register_event_callback(tx_handle, &tx_callbacks_, NULL); - - main_task_handle = xTaskGetCurrentTaskHandle(); - - audio_task = std::make_unique(espp::Task::Config{ - .name = "audio task", - .callback = audio_task_fn, - .stack_size_bytes = 1024 * 4, - .priority = 19, - .core_id = 1, - }); - - xStreamBufferReset(tx_audio_stream); - - ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); - return ret_val; -} - -// es8311 is for audio output codec -static esp_err_t es8311_init_default(void) -{ - fmt::print("initializing es8311 codec...\n"); - esp_err_t ret_val = ESP_OK; - audio_hal_codec_config_t cfg; - memset(&cfg, 0, sizeof(cfg)); - cfg.codec_mode = AUDIO_HAL_CODEC_MODE_DECODE; - cfg.dac_output = AUDIO_HAL_DAC_OUTPUT_LINE1; - cfg.i2s_iface.bits = AUDIO_HAL_BIT_LENGTH_16BITS; - cfg.i2s_iface.fmt = AUDIO_HAL_I2S_NORMAL; - cfg.i2s_iface.mode = AUDIO_HAL_MODE_SLAVE; - cfg.i2s_iface.samples = AUDIO_HAL_16K_SAMPLES; - - ret_val |= es8311_codec_init(&cfg); - ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits); - ret_val |= es8311_config_fmt((es_i2s_fmt_t)cfg.i2s_iface.fmt); - ret_val |= es8311_codec_set_voice_volume(volume_); - ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START); - - if (ESP_OK != ret_val) { - fmt::print("Failed initialize codec\n"); - } else { - fmt::print("Codec initialized\n"); - } - - return ret_val; -} - -static std::unique_ptr mute_task; -static QueueHandle_t gpio_evt_queue; - -static void gpio_isr_handler(void *arg) { - uint32_t gpio_num = (uint32_t)arg; - xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); -} - -static void init_mute_button(void) { - // register that we publish the mute button state - espp::EventManager::get().add_publisher(mute_button_topic, "i2s_audio"); - - fmt::print("Initializing mute button\n"); - mute_button = std::make_shared(espp::Button::Config{ - .name = "mute button", - .interrupt_config = - { - .gpio_num = mute_pin, - .callback = - [&](const espp::Interrupt::Event &event) { - hal::set_muted(event.active); - // simply publish that the mute button was presssed - espp::EventManager::get().publish(mute_button_topic, {}); - }, - .active_level = espp::Interrupt::ActiveLevel::LOW, - .interrupt_type = espp::Interrupt::Type::ANY_EDGE, - .pullup_enabled = true, - .pulldown_enabled = false, - }, - .task_config = - { - .name = "mute button task", - .stack_size_bytes = 4 * 1024, - .priority = 5, - }, - .log_level = espp::Logger::Verbosity::WARN, - }); - - // update the mute state (since it's a flip-flop and may have been set if we - // restarted without power loss) - hal::set_muted(mute_button->is_pressed()); - - fmt::print("Mute button initialized\n"); -} - -static bool initialized = false; -void hal::audio_init() { - if (initialized) return; - - // Config power control IO - gpio_set_direction(sound_power_pin, GPIO_MODE_OUTPUT); - gpio_set_level(sound_power_pin, 1); - - auto internal_i2c = hal::get_internal_i2c(); - - set_es8311_write(std::bind(&espp::I2c::write, internal_i2c.get(), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - set_es8311_read(std::bind(&espp::I2c::read_at_register, internal_i2c.get(), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - - i2s_driver_init(); - es8311_init_default(); - - // now initialize the mute gpio - init_mute_button(); - - audio_task->start(); - - fmt::print("Audio initialized\n"); - - initialized = true; -} - -void IRAM_ATTR hal::play_audio(const uint8_t *data, uint32_t num_bytes) { - if (has_sound) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } - // don't block here - xStreamBufferSendFromISR(tx_audio_stream, data, num_bytes, NULL); - has_sound = true; -} diff --git a/components/box-emu-hal/src/input.cpp b/components/box-emu-hal/src/input.cpp deleted file mode 100644 index 9b602d5c..00000000 --- a/components/box-emu-hal/src/input.cpp +++ /dev/null @@ -1,260 +0,0 @@ - -#include "box_emu_hal.hpp" - -using namespace std::chrono_literals; - -struct TouchpadData { - uint8_t num_touch_points = 0; - uint16_t x = 0; - uint16_t y = 0; - uint8_t btn_state = 0; -}; - -class InputBase { -public: - virtual uint16_t get_pins(std::error_code& ec) = 0; - virtual InputState pins_to_gamepad_state(uint16_t pins) = 0; - virtual void handle_volume_pins(uint16_t pins) = 0; -}; - -template -class Input : public InputBase { -public: - explicit Input(std::shared_ptr input_driver) : input_driver(input_driver) {} - virtual uint16_t get_pins(std::error_code& ec) override { - auto val = input_driver->get_pins(ec); - if (ec) { - return 0; - } - return val ^ T::INVERT_MASK; - } - virtual InputState pins_to_gamepad_state(uint16_t pins) override { - InputState state; - state.a = (bool)(pins & T::A_PIN); - state.b = (bool)(pins & T::B_PIN); - state.x = (bool)(pins & T::X_PIN); - state.y = (bool)(pins & T::Y_PIN); - state.start = (bool)(pins & T::START_PIN); - state.select = (bool)(pins & T::SELECT_PIN); - state.up = (bool)(pins & T::UP_PIN); - state.down = (bool)(pins & T::DOWN_PIN); - state.left = (bool)(pins & T::LEFT_PIN); - state.right = (bool)(pins & T::RIGHT_PIN); - return state; - } - virtual void handle_volume_pins(uint16_t pins) override { - // check the volume pins and send out events if they're pressed / released - bool volume_up = (bool)(pins & T::VOL_UP_PIN); - bool volume_down = (bool)(pins & T::VOL_DOWN_PIN); - int volume_change = (volume_up * 10) + (volume_down * -10); - if (volume_change != 0) { - // change the volume - int current_volume = hal::get_audio_volume(); - int new_volume = std::clamp(current_volume + volume_change, 0, 100); - hal::set_audio_volume(new_volume); - // send out a volume change event - espp::EventManager::get().publish(volume_changed_topic, {}); - } - } -protected: - std::shared_ptr input_driver; -}; - -static std::shared_ptr input; - -static std::shared_ptr touch_driver; -static std::shared_ptr touchpad; -static std::shared_ptr keypad; -static std::shared_ptr input_timer; -static struct InputState gamepad_state; -static std::mutex gamepad_state_mutex; -static TouchpadData touchpad_data; -static std::mutex touchpad_data_mutex; - -/** - * Touch Controller configuration - */ -void touchpad_read(uint8_t* num_touch_points, uint16_t* x, uint16_t* y, uint8_t* btn_state) { - std::lock_guard lock(touchpad_data_mutex); - *num_touch_points = touchpad_data.num_touch_points; - *x = touchpad_data.x; - *y = touchpad_data.y; - *btn_state = touchpad_data.btn_state; -} - -void keypad_read(bool *up, bool *down, bool *left, bool *right, bool *enter, bool *escape) { - InputState state; - hal::get_input_state(&state); - *up = state.up; - *down = state.down; - *left = state.left; - *right = state.right; - - *enter = state.a || state.start; - *escape = state.b || state.select; -} - -void update_touchpad_input() { - // get the latest data from the device - std::error_code ec; - bool new_data = touch_driver->update(ec); - if (ec) { - fmt::print("error updating touch_driver: {}\n", ec.message()); - std::lock_guard lock(touchpad_data_mutex); - touchpad_data = {}; - return; - } - if (!new_data) { - std::lock_guard lock(touchpad_data_mutex); - touchpad_data = {}; - return; - } - // get the latest data from the touchpad - TouchpadData temp_data; - touch_driver->get_touch_point(&temp_data.num_touch_points, &temp_data.x, &temp_data.y); - temp_data.btn_state = touch_driver->get_home_button_state(); - // update the touchpad data - std::lock_guard lock(touchpad_data_mutex); - touchpad_data = temp_data; -} - -void update_gamepad_input() { - static bool can_read_input = true; - if (!input) { - return; - } - if (!can_read_input) { - return; - } - // pins are active low - // start, select = A0, A1 - std::error_code ec; - auto pins = input->get_pins(ec); - if (ec) { - fmt::print("error getting pins: {}\n", ec.message()); - can_read_input = false; - return; - } - - auto new_gamepad_state = input->pins_to_gamepad_state(pins); - { - std::lock_guard lock(gamepad_state_mutex); - gamepad_state = new_gamepad_state; - } - input->handle_volume_pins(pins); - // TODO: check the battery alert pin and if it's low, send out a battery alert event -} - -static void init_input_generic() { - auto internal_i2c = hal::get_internal_i2c(); - - fmt::print("Initializing touch driver\n"); - touch_driver = std::make_shared(TouchDriver::Config{ - .write = std::bind(&espp::I2c::write, internal_i2c.get(), std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3), - .read = std::bind(&espp::I2c::read, internal_i2c.get(), std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3), - .log_level = espp::Logger::Verbosity::WARN - }); - - fmt::print("Initializing touchpad\n"); - touchpad = std::make_shared(espp::TouchpadInput::Config{ - .touchpad_read = touchpad_read, - .swap_xy = touch_swap_xy, - .invert_x = touch_invert_x, - .invert_y = touch_invert_y, - .log_level = espp::Logger::Verbosity::WARN - }); - - auto external_i2c = hal::get_external_i2c(); - - fmt::print("Initializing keypad\n"); - keypad = std::make_shared(espp::KeypadInput::Config{ - .read = keypad_read, - .log_level = espp::Logger::Verbosity::WARN - }); - - fmt::print("Initializing input task\n"); - input_timer = std::make_shared(espp::HighResolutionTimer::Config{ - .name = "Input timer", - .callback = []() { - update_touchpad_input(); - update_gamepad_input(); - }}); - uint64_t period_us = 30 * 1000; - input_timer->periodic(period_us); -} - -static void init_input_v0() { - auto external_i2c = hal::get_external_i2c(); - fmt::print("initializing input driver\n"); - using InputDriver = espp::Mcp23x17; - auto raw_input = new Input( - std::make_shared(InputDriver::Config{ - .port_0_direction_mask = EmuV0::PORT_0_DIRECTION_MASK, - .port_0_interrupt_mask = EmuV0::PORT_0_INTERRUPT_MASK, - .port_1_direction_mask = EmuV0::PORT_1_DIRECTION_MASK, - .port_1_interrupt_mask = EmuV0::PORT_1_INTERRUPT_MASK, - .write = std::bind(&espp::I2c::write, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), - .read_register = std::bind(&espp::I2c::read_at_register, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), - .log_level = espp::Logger::Verbosity::WARN - })); - input.reset(raw_input); -} - -static void init_input_v1() { - auto external_i2c = hal::get_external_i2c(); - fmt::print("initializing input driver\n"); - using InputDriver = espp::Aw9523; - auto raw_input = new Input( - std::make_shared(InputDriver::Config{ - .port_0_direction_mask = EmuV1::PORT_0_DIRECTION_MASK, - .port_0_interrupt_mask = EmuV1::PORT_0_INTERRUPT_MASK, - .port_1_direction_mask = EmuV1::PORT_1_DIRECTION_MASK, - .port_1_interrupt_mask = EmuV1::PORT_1_INTERRUPT_MASK, - .write = std::bind(&espp::I2c::write, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), - .write_then_read = std::bind(&espp::I2c::write_read, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), - .log_level = espp::Logger::Verbosity::WARN - })); - input.reset(raw_input); -} - -static std::atomic initialized = false; -void hal::init_input() { - if (initialized) return; - fmt::print("Initializing input subsystem\n"); - // probe the i2c bus for the mcp23x17 (which would be v0) or the aw9523 (which - // would be v1) - auto i2c = hal::get_external_i2c(); - bool mcp23x17_found = i2c->probe_device(espp::Mcp23x17::DEFAULT_ADDRESS); - bool aw9523_found = i2c->probe_device(espp::Aw9523::DEFAULT_ADDRESS); - - if (mcp23x17_found) { - fmt::print("Found MCP23x17, initializing input VERSION 0\n"); - init_input_v0(); - } else if (aw9523_found) { - fmt::print("Found AW9523, initializing input VERSION 1\n"); - init_input_v1(); - } else { - fmt::print("ERROR: No input systems found!\n"); - } - - // now initialize the rest of the input systems which are common to both - // versions - init_input_generic(); - - initialized = true; -} - -extern "C" lv_indev_t *get_keypad_input_device() { - if (!keypad) { - fmt::print("cannot get keypad input device: keypad not initialized properly!\n"); - return nullptr; - } - return keypad->get_input_device(); -} - -void hal::get_input_state(struct InputState* state) { - std::lock_guard lock(gamepad_state_mutex); - *state = gamepad_state; -} diff --git a/components/box-emu-hal/src/mmap.cpp b/components/box-emu-hal/src/mmap.cpp deleted file mode 100644 index 83788bcf..00000000 --- a/components/box-emu-hal/src/mmap.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "mmap.hpp" -#include -#include "esp_heap_caps.h" - -static uint8_t* romdata = nullptr; - -void init_memory() { - // allocate memory for the ROM and make sure it's on the SPIRAM - romdata = (uint8_t*)heap_caps_malloc(4*1024*1024, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - if (romdata == nullptr) { - fmt::print(fg(fmt::terminal_color::red), "ERROR: Couldn't allocate memory for ROM!\n"); - } -} - -size_t copy_romdata_to_cart_partition(const std::string& rom_filename) { - // load the file data and iteratively copy it over - std::ifstream romfile(rom_filename, std::ios::binary | std::ios::ate); //open file at end - if (!romfile.is_open()) { - fmt::print("Error: ROM file does not exist\n"); - return 0; - } - size_t filesize = romfile.tellg(); // get size from current file pointer location; - romfile.seekg(0, std::ios::beg); //reset file pointer to beginning; - romfile.read((char*)(romdata), filesize); - romfile.close(); - return filesize; -} - -extern "C" uint8_t *osd_getromdata() { - return get_mmapped_romdata(); -} - -uint8_t *get_mmapped_romdata() { - return romdata; -} diff --git a/components/box-emu-hal/src/spi_lcd.cpp b/components/box-emu-hal/src/spi_lcd.cpp deleted file mode 100644 index f77da208..00000000 --- a/components/box-emu-hal/src/spi_lcd.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "box_emu_hal.hpp" - -static spi_device_handle_t spi; -static spi_device_interface_config_t devcfg; - -static constexpr size_t pixel_buffer_size = lcd_width * hal::NUM_ROWS_IN_FRAME_BUFFER; -static std::shared_ptr display; - -std::shared_ptr hal::get_display() { - return display; -} - -static constexpr size_t frame_buffer_size = (((320) * 2) * 240); -static uint8_t *frame_buffer0; -static uint8_t *frame_buffer1; - -// the user flag for the callbacks does two things: -// 1. Provides the GPIO level for the data/command pin, and -// 2. Sets some bits for other signaling (such as LVGL FLUSH) -static constexpr int FLUSH_BIT = (1 << (int)espp::display_drivers::Flags::FLUSH_BIT); -static constexpr int DC_LEVEL_BIT = (1 << (int)espp::display_drivers::Flags::DC_LEVEL_BIT); - -// This function is called (in irq context!) just before a transmission starts. -// It will set the D/C line to the value indicated in the user field -// (DC_LEVEL_BIT). -static void IRAM_ATTR lcd_spi_pre_transfer_callback(spi_transaction_t *t) -{ - uint32_t user_flags = (uint32_t)(t->user); - bool dc_level = user_flags & DC_LEVEL_BIT; - gpio_set_level(lcd_dc_io, dc_level); -} - -// This function is called (in irq context!) just after a transmission ends. It -// will indicate to lvgl that the next flush is ready to be done if the -// FLUSH_BIT is set. -static void IRAM_ATTR lcd_spi_post_transfer_callback(spi_transaction_t *t) -{ - uint16_t user_flags = (uint32_t)(t->user); - bool should_flush = user_flags & FLUSH_BIT; - if (should_flush) { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_flush_ready(disp->driver); - } -} -// Transaction descriptors. Declared static so they're not allocated on the -// stack; we need this memory even when this function is finished because the -// SPI driver needs access to it even while we're already calculating the next -// line. -static const int spi_queue_size = 6; -static spi_transaction_t trans[spi_queue_size]; -static std::atomic num_queued_trans = 0; - -static void IRAM_ATTR lcd_wait_lines() { - spi_transaction_t *rtrans; - esp_err_t ret; - // fmt::print("Waiting for {} queued transactions\n", num_queued_trans); - // Wait for all transactions to be done and get back the results. - while (num_queued_trans) { - ret = spi_device_get_trans_result(spi, &rtrans, 10 / portTICK_PERIOD_MS); - if (ret != ESP_OK) { - fmt::print("Could not get trans result: {} '{}'\n", ret, esp_err_to_name(ret)); - } - num_queued_trans--; - //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though. - } -} - - -void IRAM_ATTR hal::lcd_write(const uint8_t *data, size_t length, uint32_t user_data) { - if (length == 0) { - return; - } - lcd_wait_lines(); - esp_err_t ret; - memset(&trans[0], 0, sizeof(spi_transaction_t)); - trans[0].length = length * 8; - trans[0].user = (void*)user_data; - // look at the length of the data and use tx_data if it is <= 32 bits - if (length <= 4) { - // copy the data pointer to trans[0].tx_data - memcpy(trans[0].tx_data, data, length); - trans[0].flags = SPI_TRANS_USE_TXDATA; - } else { - trans[0].tx_buffer = data; - trans[0].flags = 0; - } - ret = spi_device_queue_trans(spi, &trans[0], 10 / portTICK_PERIOD_MS); - if (ret != ESP_OK) { - fmt::print("Couldn't queue trans: {} '{}'\n", ret, esp_err_to_name(ret)); - } else { - num_queued_trans++; - } -} - -void IRAM_ATTR hal::lcd_send_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data) { - // if we haven't waited by now, wait here... - lcd_wait_lines(); - esp_err_t ret; - size_t length = (xe-xs+1)*(ye-ys+1)*2; - if (length == 0) { - fmt::print("Bad length: ({},{}) to ({},{})\n", xs, ys, xe, ye); - } - // initialize the spi transactions - for (int i=0; i<6; i++) { - memset(&trans[i], 0, sizeof(spi_transaction_t)); - if ((i&1)==0) { - //Even transfers are commands - trans[i].length = 8; - trans[i].user = (void*)0; - } else { - //Odd transfers are data - trans[i].length = 8*4; - trans[i].user = (void*)DC_LEVEL_BIT; - } - trans[i].flags = SPI_TRANS_USE_TXDATA; - } - trans[0].tx_data[0] = (uint8_t)DisplayDriver::Command::caset; - trans[1].tx_data[0] = (xs)>> 8; - trans[1].tx_data[1] = (xs)&0xff; - trans[1].tx_data[2] = (xe)>>8; - trans[1].tx_data[3] = (xe)&0xff; - trans[2].tx_data[0] = (uint8_t)DisplayDriver::Command::raset; - trans[3].tx_data[0] = (ys)>>8; - trans[3].tx_data[1] = (ys)&0xff; - trans[3].tx_data[2] = (ye)>>8; - trans[3].tx_data[3] = (ye)&0xff; - trans[4].tx_data[0] = (uint8_t)DisplayDriver::Command::ramwr; - trans[5].tx_buffer = data; - trans[5].length = length*8; - // undo SPI_TRANS_USE_TXDATA flag - trans[5].flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL; - // we need to keep the dc bit set, but also add our flags - trans[5].user = (void*)(DC_LEVEL_BIT | user_data); - //Queue all transactions. - for (int i=0; i<6; i++) { - ret = spi_device_queue_trans(spi, &trans[i], 10 / portTICK_PERIOD_MS); - if (ret != ESP_OK) { - fmt::print("Couldn't queue trans: {} '{}'\n", ret, esp_err_to_name(ret)); - } else { - num_queued_trans++; - } - } - //When we are here, the SPI driver is busy (in the background) getting the - //transactions sent. That happens mostly using DMA, so the CPU doesn't have - //much to do here. We're not going to wait for the transaction to finish - //because we may as well spend the time calculating the next line. When that - //is done, we can call lcd_wait_lines, which will wait for the transfers - //to be done and check their status. -} - -extern "C" uint16_t make_color(uint8_t r, uint8_t g, uint8_t b) { - return lv_color_make(r,g,b).full; -} - -uint16_t* hal::get_vram0() { - return display->vram0(); -} - -uint16_t* hal::get_vram1() { - return display->vram1(); -} - -uint8_t* hal::get_frame_buffer0() { - return frame_buffer0; -} - -uint8_t* hal::get_frame_buffer1() { - return frame_buffer1; -} - -void hal::lcd_write_frame(const uint16_t xs, const uint16_t ys, const uint16_t width, const uint16_t height, const uint8_t * data){ - if (data) { - // have data, fill the area with the color data - lv_area_t area { - .x1 = (lv_coord_t)(xs), - .y1 = (lv_coord_t)(ys), - .x2 = (lv_coord_t)(xs+width-1), - .y2 = (lv_coord_t)(ys+height-1)}; - DisplayDriver::fill(nullptr, &area, (lv_color_t*)data); - } else { - // don't have data, so clear the area (set to 0) - DisplayDriver::clear(xs, ys, width, height); - } -} - -static bool initialized = false; -void hal::lcd_init() { - if (initialized) { - return; - } - esp_err_t ret; - - spi_bus_config_t buscfg; - memset(&buscfg, 0, sizeof(buscfg)); - buscfg.mosi_io_num = lcd_mosi_io; - buscfg.miso_io_num = -1; - buscfg.sclk_io_num = lcd_sclk_io; - buscfg.quadwp_io_num = -1; - buscfg.quadhd_io_num = -1; - buscfg.max_transfer_sz = frame_buffer_size * sizeof(lv_color_t) + 100; - - memset(&devcfg, 0, sizeof(devcfg)); - devcfg.mode = 0; - // devcfg.flags = SPI_DEVICE_NO_RETURN_RESULT; - devcfg.clock_speed_hz = lcd_clock_speed; - devcfg.input_delay_ns = 0; - devcfg.spics_io_num = lcd_cs_io; - devcfg.queue_size = spi_queue_size; - devcfg.pre_cb = lcd_spi_pre_transfer_callback; - devcfg.post_cb = lcd_spi_post_transfer_callback; - - //Initialize the SPI bus - ret = spi_bus_initialize(lcd_spi_num, &buscfg, SPI_DMA_CH_AUTO); - ESP_ERROR_CHECK(ret); - //Attach the LCD to the SPI bus - ret = spi_bus_add_device(lcd_spi_num, &devcfg, &spi); - ESP_ERROR_CHECK(ret); - // initialize the controller - DisplayDriver::initialize(espp::display_drivers::Config{ - .lcd_write = hal::lcd_write, - .lcd_send_lines = hal::lcd_send_lines, - .reset_pin = lcd_reset_io, - .data_command_pin = lcd_dc_io, - .reset_value = reset_value, - .invert_colors = invert_colors, - .mirror_x = mirror_x, - .mirror_y = mirror_y - }); - // initialize the display / lvgl - using namespace std::chrono_literals; - display = std::make_shared(espp::Display::AllocatingConfig{ - .width = lcd_width, - .height = lcd_height, - .pixel_buffer_size = pixel_buffer_size, - .flush_callback = DisplayDriver::flush, - .backlight_pin = backlight_io, - .backlight_on_value = backlight_value, - .task_config = { - .name = "display task", - .priority = 10, - .core_id = 1, - }, - .update_period = 5ms, - .double_buffered = true, - .allocation_flags = MALLOC_CAP_8BIT | MALLOC_CAP_DMA, - .rotation = rotation, - .software_rotation_enabled = true, - }); - - frame_buffer0 = (uint8_t*)heap_caps_malloc(frame_buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - frame_buffer1 = (uint8_t*)heap_caps_malloc(frame_buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - initialized = true; -} - -void hal::set_display_brightness(float brightness) { - display->set_brightness(brightness); -} - -float hal::get_display_brightness() { - return display->get_brightness(); -} diff --git a/components/box-emu-hal/src/usb.cpp b/components/box-emu-hal/src/usb.cpp deleted file mode 100644 index db7ba1d2..00000000 --- a/components/box-emu-hal/src/usb.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "usb.hpp" - -#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) - -enum { - ITF_NUM_MSC = 0, - ITF_NUM_TOTAL -}; - -enum { - EDPT_CTRL_OUT = 0x00, - EDPT_CTRL_IN = 0x80, - - EDPT_MSC_OUT = 0x01, - EDPT_MSC_IN = 0x81, -}; - -static uint8_t const desc_configuration[] = { - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - - // Interface number, string index, EP Out & EP In address, EP size - TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), -}; - -static tusb_desc_device_t descriptor_config = { - .bLength = sizeof(descriptor_config), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers - .idProduct = 0x4002, - .bcdDevice = 0x100, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - .bNumConfigurations = 0x01 -}; - -static char const *string_desc_arr[] = { - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "Finger563", // 1: Manufacturer - "ESP-Box-Emu", // 2: Product - "123456", // 3: Serials - "Box-Emu uSD Card", // 4. MSC -}; - -// callback that is delivered when storage is mounted/unmounted by application. -static void storage_mount_changed_cb(tinyusb_msc_event_t *event) -{ - fmt::print("Storage mounted to application: {}\n", event->mount_changed_data.is_mounted ? "Yes" : "No"); -} - -static bool usb_enabled_ = false; -static usb_phy_handle_t jtag_phy; - -bool usb_is_enabled() { - return usb_enabled_; -} - -void usb_init() { - // get the card from the filesystem initialization - auto card = get_sdcard(); - if (!card) { - fmt::print("No SD card found, skipping USB MSC initialization\n"); - return; - } - - fmt::print("Deleting JTAG PHY\n"); - usb_del_phy(jtag_phy); - - fmt::print("USB MSC initialization\n"); - // register the callback for the storage mount changed event. - const tinyusb_msc_sdmmc_config_t config_sdmmc = { - .card = card, - .callback_mount_changed = storage_mount_changed_cb, - .mount_config = { - .max_files = 5, - } - }; - ESP_ERROR_CHECK(tinyusb_msc_storage_init_sdmmc(&config_sdmmc)); - ESP_ERROR_CHECK(tinyusb_msc_register_callback(TINYUSB_MSC_EVENT_MOUNT_CHANGED, storage_mount_changed_cb)); - - // initialize the tinyusb stack - fmt::print("USB MSC initialization\n"); - const tinyusb_config_t tusb_cfg = { - .device_descriptor = &descriptor_config, - .string_descriptor = string_desc_arr, - .string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]), - .external_phy = false, - .configuration_descriptor = desc_configuration, - }; - ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); - fmt::print("USB MSC initialization DONE\n"); - usb_enabled_ = true; -} - -void usb_deinit() { - if (!usb_enabled_) { - return; - } - fmt::print("USB MSC deinitialization\n"); - auto err = tinyusb_driver_uninstall(); - if (err != ESP_OK) { - fmt::print("tinyusb_driver_uninstall failed: {}\n", esp_err_to_name(err)); - } - usb_enabled_ = false; - // and reconnect the CDC port, see: - // https://github.com/espressif/idf-extra-components/pull/229 - usb_phy_config_t phy_conf = { - // NOTE: for some reason, USB_PHY_CTRL_SERIAL_JTAG is not defined in the SDK - // for the ESP32s3 - .controller = (usb_phy_controller_t)1, - }; - usb_new_phy(&phy_conf, &jtag_phy); -} diff --git a/components/box-emu-hal/src/video_setting.cpp b/components/box-emu-hal/src/video_setting.cpp deleted file mode 100644 index d4b59a3c..00000000 --- a/components/box-emu-hal/src/video_setting.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "box_emu_hal.hpp" - -static std::atomic video_setting_{VideoSetting::FIT}; - -VideoSetting hal::get_video_setting() { - return video_setting_; -} - -void hal::set_video_setting(const VideoSetting& setting) { - video_setting_ = setting; -} diff --git a/components/box-emu-hal/src/video_task.cpp b/components/box-emu-hal/src/video_task.cpp deleted file mode 100644 index e0f53206..00000000 --- a/components/box-emu-hal/src/video_task.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "box_emu_hal.hpp" - -using namespace hal; - -static std::shared_ptr video_task_; -static QueueHandle_t video_queue_; - -static size_t display_width = lcd_width; -static size_t display_height = lcd_height; - -static size_t native_width = lcd_width; -static size_t native_height = lcd_height; -static int native_pitch = lcd_width; - -static const uint16_t* palette = nullptr; -static size_t palette_size = 256; - -static bool video_task(std::mutex &m, std::condition_variable& cv); - -void hal::init_video_task() { - static bool initialized = false; - if (initialized) { - return; - } - fmt::print("initializing video task...\n"); - video_queue_ = xQueueCreate(1, sizeof(uint16_t*)); - video_task_ = std::make_shared(espp::Task::Config{ - .name = "video task", - .callback = video_task, - .stack_size_bytes = 4*1024, - .priority = 20, - .core_id = 1 - }); - video_task_->start(); - initialized = true; -} - -void hal::set_display_size(size_t width, size_t height) { - display_width = width; - display_height = height; -} - -void hal::set_native_size(size_t width, size_t height, int pitch) { - native_width = width; - native_height = height; - native_pitch = pitch == -1 ? width : pitch; -} - -void hal::set_palette(const uint16_t* _palette, size_t size) { - palette = _palette; - palette_size = size; -} - -void hal::push_frame(const void* frame) { - if (video_queue_ == nullptr) { - fmt::print("video queue is null, make sure to call init_video_task() first\n"); - return; - } - xQueueSend(video_queue_, &frame, 10 / portTICK_PERIOD_MS); -} - -static bool has_palette() { - return palette != nullptr; -} - -static bool is_native() { - return native_width == display_width && native_height == display_height; -} - -static int get_x_offset() { - return (lcd_width-display_width)/2; -} - -static int get_y_offset() { - return (lcd_height-display_height)/2; -} - -static const uint16_t* get_palette() { - return palette; -} - -static bool video_task(std::mutex &m, std::condition_variable& cv) { - const void *_frame_ptr; - if (xQueuePeek(video_queue_, &_frame_ptr, 100 / portTICK_PERIOD_MS) != pdTRUE) { - // we couldn't get anything from the queue, return - return false; - } - if (_frame_ptr == nullptr) { - // make sure we clear the queue - xQueueReceive(video_queue_, &_frame_ptr, 10 / portTICK_PERIOD_MS); - // we got a nullptr, return - return false; - } - static constexpr int num_lines_to_write = NUM_ROWS_IN_FRAME_BUFFER; - static int vram_index = 0; // has to be static so that it persists between calls - const int x_offset = get_x_offset(); - const int y_offset = get_y_offset(); - const uint16_t* _palette = get_palette(); - if (is_native()) { - for (int y=0; y(num_lines_to_write, display_height-y); - if (has_palette()) { - const uint8_t* _frame = (const uint8_t*)_frame_ptr; - for (int i=0; i(x_scale * native_width, 0, lcd_width); - for (int y=0; y= max_y) { - break; - } - int source_y = (float)_y * inv_y_scale; - // shoudl i put this around the outer loop or is this loop a good - // balance for perfomance of the check? - if (has_palette()) { - const uint8_t* _frame = (const uint8_t*)_frame_ptr; - // write two pixels (32 bits) at a time because it's faster - for (int x=0; x +#include +#include + +#include "box-emu.hpp" + +using namespace std::chrono_literals; + +static std::vector circles; +static std::vector audio_bytes; + +static void draw_circle(int x0, int y0, int radius); +static void clear_circles(); + +static size_t load_audio(); +static void play_click(espp::EspBox &box); + +extern "C" void app_main(void) { + espp::Logger logger({.tag = "ESP BOX Example", .level = espp::Logger::Verbosity::INFO}); + logger.info("Starting example!"); + + //! [esp box example] + BoxEmu &emu = BoxEmu::get(); + emu.set_log_level(espp::Logger::Verbosity::INFO); + espp::EspBox &box = espp::EspBox::get(); + logger.info("Running on {}", box.box_type()); + logger.info("Box Emu version: {}", emu.version()); + + // initialize + if (!emu.initialize_box()) { + logger.error("Failed to initialize box!"); + return; + } + + if (!emu.initialize_sdcard()) { + logger.warn("Failed to initialize SD card!"); + logger.warn("This may happen if the SD card is not inserted."); + } + + if (!emu.initialize_memory()) { + logger.error("Failed to initialize memory!"); + return; + } + + if (!emu.initialize_gamepad()) { + logger.warn("Failed to initialize gamepad!"); + logger.warn("This may happen if the gamepad is not connected."); + } + + if (!emu.initialize_battery()) { + logger.warn("Failed to initialize battery!"); + logger.warn("This may happen if the battery is not connected."); + } + + if (!emu.initialize_video()) { + logger.error("Failed to initialize video!"); + return; + } + + // set the background color to black + lv_obj_t *bg = lv_obj_create(lv_scr_act()); + lv_obj_set_size(bg, box.lcd_width(), box.lcd_height()); + lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0); + + // add text in the center of the screen + lv_obj_t *label = lv_label_create(lv_scr_act()); + lv_label_set_text(label, "Touch the screen!\nPress the home button to clear circles."); + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); + + // start a simple thread to do the lv_task_handler every 16ms + espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool { + lv_task_handler(); + std::unique_lock lock(m); + cv.wait_for(lock, 16ms); + return false; + }, + .task_config = { + .name = "lv_task", + }}); + lv_task.start(); + + // load the audio file (wav file bundled in memory) + size_t wav_size = load_audio(); + logger.info("Loaded {} bytes of audio", wav_size); + + // unmute the audio and set the volume to 60% + box.mute(false); + box.volume(60.0f); + + // set the display brightness to be 75% + box.brightness(75.0f); + + auto previous_touchpad_data = box.touchpad_convert(box.touchpad_data()); + // NOTE: while in the EspBox example we had to call the + // EspBox::update_touch(), we don't have to anymore since the BoxEmu has an + // internal input update task which updates both the touchscreen and the + // gamepad + while (true) { + std::this_thread::sleep_for(100ms); + auto gamepad_state = emu.gamepad_state(); + if (gamepad_state.a) { + // clear the circles + clear_circles(); + } + if (gamepad_state.b) { + // play a click sound + play_click(box); + } + // NOTE: since we're directly using the touchpad data, and not using the + // TouchpadInput + LVGL, we'll need to ensure the touchpad data is + // converted into proper screen coordinates instead of simply using the + // raw values. + auto touchpad_data = box.touchpad_convert(box.touchpad_data()); + if (touchpad_data != previous_touchpad_data) { + logger.info("Touch: {}", touchpad_data); + previous_touchpad_data = touchpad_data; + // if the button is pressed, clear the circles + if (touchpad_data.btn_state) { + clear_circles(); + } + // if there is a touch point, draw a circle and play a click sound + if (touchpad_data.num_touch_points > 0) { + draw_circle(touchpad_data.x, touchpad_data.y, 10); + play_click(box); + } + } + } + //! [esp box example] +} + +static void draw_circle(int x0, int y0, int radius) { + lv_obj_t *my_Cir = lv_obj_create(lv_scr_act()); + lv_obj_set_scrollbar_mode(my_Cir, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_size(my_Cir, 42, 42); + lv_obj_set_pos(my_Cir, x0 - 21, y0 - 21); + lv_obj_set_style_radius(my_Cir, LV_RADIUS_CIRCLE, 0); + circles.push_back(my_Cir); +} + +static void clear_circles() { + // remove the circles from lvgl + for (auto circle : circles) { + lv_obj_del(circle); + } + // clear the vector + circles.clear(); +} + +static size_t load_audio() { + // if the audio_bytes vector is already populated, return the size + if (audio_bytes.size() > 0) { + return audio_bytes.size(); + } + + // these are configured in the CMakeLists.txt file + extern const char wav_start[] asm("_binary_click_wav_start"); + extern const char wav_end[] asm("_binary_click_wav_end"); + + // -1 due to the size being 1 byte too large, I think because end is the byte + // immediately after the last byte in the memory but I'm not sure - cmm 2022-08-20 + // + // Suppression as these are linker symbols and cppcheck doesn't know how to ensure + // they are the same object + // cppcheck-suppress comparePointers + size_t wav_size = (wav_end - wav_start) - 1; + FILE *fp = fmemopen((void *)wav_start, wav_size, "rb"); + // read the file into the audio_bytes vector + audio_bytes.resize(wav_size); + fread(audio_bytes.data(), 1, wav_size, fp); + fclose(fp); + return wav_size; +} + +static void play_click(espp::EspBox &box) { + // use the box.play_audio() function to play a sound, breaking it into + // audio_buffer_size chunks + auto audio_buffer_size = box.audio_buffer_size(); + size_t offset = 0; + while (offset < audio_bytes.size()) { + size_t bytes_to_play = std::min(audio_buffer_size, audio_bytes.size() - offset); + box.play_audio(audio_bytes.data() + offset, bytes_to_play); + offset += bytes_to_play; + } +} diff --git a/components/box-emu/example/main/click.wav b/components/box-emu/example/main/click.wav new file mode 100644 index 00000000..2183344a Binary files /dev/null and b/components/box-emu/example/main/click.wav differ diff --git a/components/box-emu/example/partitions.csv b/components/box-emu/example/partitions.csv new file mode 100644 index 00000000..b8a6dbe0 --- /dev/null +++ b/components/box-emu/example/partitions.csv @@ -0,0 +1,4 @@ +# Name, Type, SubType, Offset, Size +nvs, data, nvs, 0x9000, 0x6000 +phy_init, data, phy, 0xf000, 0x1000 +factory, app, factory, 0x10000, 6M diff --git a/components/box-emu/example/sdkconfig.defaults b/components/box-emu/example/sdkconfig.defaults new file mode 100644 index 00000000..4f790c3d --- /dev/null +++ b/components/box-emu/example/sdkconfig.defaults @@ -0,0 +1,63 @@ +CONFIG_IDF_TARGET="esp32s3" + +CONFIG_FREERTOS_HZ=1000 + +# set compiler optimization level to -O2 (compile for performance) +CONFIG_COMPILER_OPTIMIZATION_PERF=y + +# ESP32-specific +# +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240 + +# Common ESP-related +# +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384 + +# Set esp-timer task stack size to 6KB +CONFIG_ESP_TIMER_TASK_STACK_SIZE=6144 + +# SPIRAM Configuration +CONFIG_SPIRAM=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# anything larger than this is attempted to allocate within SPIRAM first +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 +# specifcally reserved internally for DMA +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=262144 +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y + +# set the functions into IRAM +CONFIG_SPI_MASTER_IN_IRAM=y + +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="16MB" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y # over twice as fast as DIO + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# +# LVGL configuration - # Color settings +# +# CONFIG_LV_COLOR_DEPTH_32 is not set +CONFIG_LV_COLOR_DEPTH_16=y +# CONFIG_LV_COLOR_DEPTH_8 is not set +# CONFIG_LV_COLOR_DEPTH_1 is not set +CONFIG_LV_COLOR_DEPTH=16 +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_COLOR_MIX_ROUND_OFS=128 +CONFIG_LV_COLOR_CHROMA_KEY_HEX=0x00FF00 + +# +# LVGL configuration - # Themes +# +CONFIG_LV_USE_THEME_DEFAULT=y +CONFIG_LV_THEME_DEFAULT_DARK=y +CONFIG_LV_THEME_DEFAULT_GROW=y +CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=80 diff --git a/components/box-emu-hal/idf_component.yml b/components/box-emu/idf_component.yml similarity index 100% rename from components/box-emu-hal/idf_component.yml rename to components/box-emu/idf_component.yml diff --git a/components/box-emu-hal/include/battery_info.hpp b/components/box-emu/include/battery_info.hpp similarity index 100% rename from components/box-emu-hal/include/battery_info.hpp rename to components/box-emu/include/battery_info.hpp diff --git a/components/box-emu/include/box-emu.hpp b/components/box-emu/include/box-emu.hpp new file mode 100644 index 00000000..5c0438a3 --- /dev/null +++ b/components/box-emu/include/box-emu.hpp @@ -0,0 +1,344 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "esp-box.hpp" +#include "event_manager.hpp" + +#include "aw9523.hpp" +#include "base_component.hpp" +#include "button.hpp" +#include "events.hpp" +#include "high_resolution_timer.hpp" +#include "keypad_input.hpp" +#include "max1704x.hpp" +#include "mcp23x17.hpp" +#include "oneshot_adc.hpp" +#include "serialization.hpp" +#include "task.hpp" +#include "timer.hpp" + +#include "battery_info.hpp" +#include "gamepad_state.hpp" +#include "video_setting.hpp" + +class BoxEmu : public espp::BaseComponent { +public: + /// The Version of the BoxEmu + enum class Version { + UNKNOWN, ///< unknown box + V0, ///< first version of the box + V1, ///< second version of the box + }; + + /// @brief Access the singleton instance of the BoxEmu class + /// @return Reference to the singleton instance of the BoxEmu class + static BoxEmu &get() { + static BoxEmu instance; + return instance; + } + + BoxEmu(const BoxEmu &) = delete; + BoxEmu &operator=(const BoxEmu &) = delete; + BoxEmu(BoxEmu &&) = delete; + BoxEmu &operator=(BoxEmu &&) = delete; + + static constexpr char mount_point[] = "/sdcard"; + + static uint16_t make_color(uint8_t r, uint8_t g, uint8_t b) { + return lv_color_make(r,g,b).full; + } + + /// Get the version of the BoxEmu that was detected + /// \return The version of the BoxEmu that was detected + /// \see Version + Version version() const; + + /// Get a reference to the internal I2C bus + /// \return A reference to the internal I2C bus + /// \note The internal I2C bus is used for the touchscreen and audio codec + espp::I2c &internal_i2c(); + + /// Get a reference to the external I2C bus + /// \return A reference to the external I2C bus + /// \note The external I2C bus is used for the gamepad functionality + espp::I2c &external_i2c(); + + /// Initialize the EspBox hardware + /// \return True if the initialization was successful, false otherwise + /// \note This initializes the touch, display, and sound subsystems which are + /// internal to the EspBox + /// \see EspBox + bool initialize_box(); + + ///////////////////////////////////////////////////////////////////////////// + // uSD Card + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_sdcard(); + sdmmc_card_t *sdcard() const; + + ///////////////////////////////////////////////////////////////////////////// + // Memory + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_memory(); + size_t copy_file_to_romdata(const std::string& filename); + uint8_t *romdata() const; + + ///////////////////////////////////////////////////////////////////////////// + // Gamepad + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_gamepad(); + bool update_gamepad_state(); + GamepadState gamepad_state(); + void keypad_read(bool *up, bool *down, bool *left, bool *right, bool *enter, bool *escape); + std::shared_ptr keypad() const; + + ///////////////////////////////////////////////////////////////////////////// + // Battery + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_battery(); + std::shared_ptr battery() const; + + ///////////////////////////////////////////////////////////////////////////// + // Video + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_video(); + void display_size(size_t width, size_t height); + void native_size(size_t width, size_t height, int pitch = -1); + void palette(const uint16_t *palette, size_t size = 256); + void push_frame(const void* frame); + VideoSetting video_setting() const; + void video_setting(const VideoSetting setting); + + ///////////////////////////////////////////////////////////////////////////// + // USB + ///////////////////////////////////////////////////////////////////////////// + + bool initialize_usb(); + bool deinitialize_usb(); + bool is_usb_enabled() const; + +protected: + BoxEmu(); + void detect(); + + bool has_palette() const; + bool is_native() const; + int x_offset() const; + int y_offset() const; + const uint16_t *palette() const; + bool video_task_callback(std::mutex &m, std::condition_variable &cv); + + class InputBase { + public: + virtual uint16_t get_pins(std::error_code& ec) = 0; + virtual GamepadState pins_to_gamepad_state(uint16_t pins) = 0; + virtual void handle_volume_pins(uint16_t pins) = 0; + }; + + template + class Input : public InputBase { + public: + explicit Input(std::shared_ptr input_driver) : input_driver(input_driver) {} + virtual uint16_t get_pins(std::error_code& ec) override { + auto val = input_driver->get_pins(ec); + if (ec) { + return 0; + } + return val ^ T::INVERT_MASK; + } + virtual GamepadState pins_to_gamepad_state(uint16_t pins) override { + GamepadState state; + state.a = (bool)(pins & T::A_PIN); + state.b = (bool)(pins & T::B_PIN); + state.x = (bool)(pins & T::X_PIN); + state.y = (bool)(pins & T::Y_PIN); + state.start = (bool)(pins & T::START_PIN); + state.select = (bool)(pins & T::SELECT_PIN); + state.up = (bool)(pins & T::UP_PIN); + state.down = (bool)(pins & T::DOWN_PIN); + state.left = (bool)(pins & T::LEFT_PIN); + state.right = (bool)(pins & T::RIGHT_PIN); + return state; + } + virtual void handle_volume_pins(uint16_t pins) override { + // check the volume pins and send out events if they're pressed / released + bool volume_up = (bool)(pins & T::VOL_UP_PIN); + bool volume_down = (bool)(pins & T::VOL_DOWN_PIN); + int volume_change = (volume_up * 10) + (volume_down * -10); + if (volume_change != 0) { + // change the volume + auto &box = espp::EspBox::get(); + float current_volume = box.volume(); + float new_volume = std::clamp(current_volume + volume_change, 0, 100); + box.volume(new_volume); + // send out a volume change event + espp::EventManager::get().publish(volume_changed_topic, {}); + } + } + protected: + std::shared_ptr input_driver; + }; + + struct version0 { + using InputDriver = espp::Mcp23x17; + typedef Input InputType; + static constexpr uint16_t START_PIN = (1<<0) << 0; // start pin is on port a of the MCP23x17 + static constexpr uint16_t SELECT_PIN = (1<<1) << 0; // select pin is on port a of the MCP23x17 + static constexpr uint16_t UP_PIN = (1<<0) << 8; // up pin is on port b of the MCP23x17 + static constexpr uint16_t DOWN_PIN = (1<<1) << 8; // down pin is on port b of the MCP23x17 + static constexpr uint16_t LEFT_PIN = (1<<2) << 8; // left pin is on port b of the MCP23x17 + static constexpr uint16_t RIGHT_PIN = (1<<3) << 8; // right pin is on port b of the MCP23x17 + static constexpr uint16_t A_PIN = (1<<4) << 8; // a pin is on port b of the MCP23x17 + static constexpr uint16_t B_PIN = (1<<5) << 8; // b pin is on port b of the MCP23x17 + static constexpr uint16_t X_PIN = (1<<6) << 8; // x pin is on port b of the MCP23x17 + static constexpr uint16_t Y_PIN = (1<<7) << 8; // y pin is on port b of the MCP23x17 + static constexpr uint16_t BAT_ALERT_PIN = 0; // battery alert pin doesn't exist on the MCP23x17 + static constexpr uint16_t VOL_UP_PIN = 0; // volume up pin doesn't exist on the MCP23x17 + static constexpr uint16_t VOL_DOWN_PIN = 0; // volume down pin doesn't exist on the MCP23x17 + static constexpr uint16_t DIRECTION_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN); + static constexpr uint16_t INTERRUPT_MASK = (START_PIN | SELECT_PIN); + static constexpr uint16_t INVERT_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN ); // pins are active low so invert them + static constexpr uint8_t PORT_0_DIRECTION_MASK = DIRECTION_MASK & 0xFF; + static constexpr uint8_t PORT_1_DIRECTION_MASK = (DIRECTION_MASK >> 8) & 0xFF; + static constexpr uint8_t PORT_0_INTERRUPT_MASK = INTERRUPT_MASK & 0xFF; + static constexpr uint8_t PORT_1_INTERRUPT_MASK = (INTERRUPT_MASK >> 8) & 0xFF; + }; + + struct version1 { + using InputDriver = espp::Aw9523; + typedef Input InputType; + static constexpr gpio_num_t VBAT_SENSE_PIN = GPIO_NUM_14; // battery sense pin is on GPIO 14 + static constexpr gpio_num_t AW9523_INT_PIN = GPIO_NUM_21; // interrupt pin is on GPIO 21 + static constexpr uint16_t UP_PIN = (1<<0) << 0; // up pin is on port 0 of the AW9523 + static constexpr uint16_t DOWN_PIN = (1<<1) << 0; // down pin is on port 0 of the AW9523 + static constexpr uint16_t LEFT_PIN = (1<<2) << 0; // left pin is on port 0 of the AW9523 + static constexpr uint16_t RIGHT_PIN = (1<<3) << 0; // right pin is on port 0 of the AW9523 + static constexpr uint16_t A_PIN = (1<<4) << 0; // a pin is on port 0 of the AW9523 + static constexpr uint16_t B_PIN = (1<<5) << 0; // b pin is on port 0 of the AW9523 + static constexpr uint16_t X_PIN = (1<<6) << 0; // x pin is on port 0 of the AW9523 + static constexpr uint16_t Y_PIN = (1<<7) << 0; // y pin is on port 0 of the AW9523 + static constexpr uint16_t START_PIN = (1<<0) << 8; // start pin is on port 1 of the AW9523 + static constexpr uint16_t SELECT_PIN = (1<<1) << 8; // select pin is on port 1 of the AW9523 + static constexpr uint16_t BAT_ALERT_PIN = (1<<3) << 8; // battery alert pin is on port 1 of the AW9523 + static constexpr uint16_t VOL_UP_PIN = (1<<4) << 8; // volume up pin is on port 1 of the AW9523 + static constexpr uint16_t VOL_DOWN_PIN = (1<<5) << 8; // volume down pin is on port 1 of the AW9523 + static constexpr uint16_t DIRECTION_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN | BAT_ALERT_PIN | VOL_UP_PIN | VOL_DOWN_PIN); + static constexpr uint16_t INTERRUPT_MASK = (BAT_ALERT_PIN); + static constexpr uint16_t INVERT_MASK = (UP_PIN | DOWN_PIN | LEFT_PIN | RIGHT_PIN | A_PIN | B_PIN | X_PIN | Y_PIN | START_PIN | SELECT_PIN | BAT_ALERT_PIN | VOL_UP_PIN | VOL_DOWN_PIN); // pins are active low so invert them + static constexpr uint8_t PORT_0_DIRECTION_MASK = DIRECTION_MASK & 0xFF; + static constexpr uint8_t PORT_1_DIRECTION_MASK = (DIRECTION_MASK >> 8) & 0xFF; + static constexpr uint8_t PORT_0_INTERRUPT_MASK = INTERRUPT_MASK & 0xFF; + static constexpr uint8_t PORT_1_INTERRUPT_MASK = (INTERRUPT_MASK >> 8) & 0xFF; + + // ADC for the battery voltage, it's on ADC2_CH3, which is IO14 + static constexpr adc_unit_t BATTERY_ADC_UNIT = ADC_UNIT_2; + static constexpr adc_channel_t BATTERY_ADC_CHANNEL = ADC_CHANNEL_3; + }; + + // external I2c (peripherals) + static constexpr auto external_i2c_port = I2C_NUM_1; + static constexpr auto external_i2c_clock_speed = 400 * 1000; + static constexpr gpio_num_t external_i2c_sda = GPIO_NUM_41; + static constexpr gpio_num_t external_i2c_scl = GPIO_NUM_40; + + // uSD card + static constexpr gpio_num_t sdcard_cs = GPIO_NUM_10; + static constexpr gpio_num_t sdcard_mosi = GPIO_NUM_11; + static constexpr gpio_num_t sdcard_miso = GPIO_NUM_13; + static constexpr gpio_num_t sdcard_sclk = GPIO_NUM_12; + static constexpr auto sdcard_spi_num = SPI3_HOST; + + static constexpr int num_rows_in_framebuffer = 50; + + Version version_{Version::UNKNOWN}; + + espp::I2c external_i2c_{{.port = external_i2c_port, + .sda_io_num = external_i2c_sda, + .scl_io_num = external_i2c_scl, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE}}; + + // sdcard + sdmmc_card_t *sdcard_{nullptr}; + + // memory + uint8_t *romdata_{nullptr}; + + // audio + std::shared_ptr mute_button_; + + // gamepad + std::atomic can_read_gamepad_{true}; + std::recursive_mutex gamepad_state_mutex_; + GamepadState gamepad_state_; + std::shared_ptr input_; + std::shared_ptr keypad_; + std::shared_ptr input_timer_; + + // battery + std::atomic battery_comms_good_{true}; + std::shared_ptr battery_{nullptr}; + std::shared_ptr adc_{nullptr}; + std::shared_ptr battery_task_; + std::vector channels; + + // video + std::atomic video_setting_{VideoSetting::FIT}; + std::shared_ptr video_task_{nullptr}; + QueueHandle_t video_queue_{nullptr}; + + size_t display_width_{espp::EspBox::lcd_width()}; + size_t display_height_{espp::EspBox::lcd_height()}; + + size_t native_width_{espp::EspBox::lcd_width()}; + size_t native_height_{espp::EspBox::lcd_height()}; + int native_pitch_{espp::EspBox::lcd_width()}; + + const uint16_t* palette_{nullptr}; + size_t palette_size_{256}; + + // usb + std::atomic usb_enabled_{false}; + usb_phy_handle_t jtag_phy_; +}; + +// for libfmt printing of the BoxEmu::Version enum +template <> +struct fmt::formatter : fmt::formatter { + template + auto format(BoxEmu::Version v, FormatContext &ctx) const { + std::string_view name; + switch (v) { + case BoxEmu::Version::UNKNOWN: + name = "UNKNOWN"; + break; + case BoxEmu::Version::V0: + name = "V0"; + break; + case BoxEmu::Version::V1: + name = "V1"; + break; + } + return fmt::formatter::format(name, ctx); + } +}; diff --git a/components/box-emu/include/gamepad_state.hpp b/components/box-emu/include/gamepad_state.hpp new file mode 100644 index 00000000..78347d9f --- /dev/null +++ b/components/box-emu/include/gamepad_state.hpp @@ -0,0 +1,16 @@ +#pragma once + +struct GamepadState { + int a : 1; + int b : 1; + int x : 1; + int y : 1; + int select : 1; + int start : 1; + int up : 1; + int down : 1; + int left : 1; + int right : 1; + + bool operator==(const GamepadState& other) const = default; +}; diff --git a/components/box-emu-hal/include/lvgl_inputs.h b/components/box-emu/include/lvgl_inputs.h similarity index 100% rename from components/box-emu-hal/include/lvgl_inputs.h rename to components/box-emu/include/lvgl_inputs.h diff --git a/components/box-emu-hal/include/make_color.h b/components/box-emu/include/make_color.h similarity index 100% rename from components/box-emu-hal/include/make_color.h rename to components/box-emu/include/make_color.h diff --git a/components/box-emu/include/video_setting.hpp b/components/box-emu/include/video_setting.hpp new file mode 100644 index 00000000..187b6a04 --- /dev/null +++ b/components/box-emu/include/video_setting.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "format.hpp" + +enum class VideoSetting { ORIGINAL, FIT, FILL, MAX_UNUSED }; + +// for libfmt printing of VideoSetting +template <> +struct fmt::formatter : fmt::formatter { + template + auto format(VideoSetting c, FormatContext& ctx) const { + std::string name; + switch (c) { + case VideoSetting::ORIGINAL: + name = "ORIGINAL"; + break; + case VideoSetting::FIT: + name = "FIT"; + break; + case VideoSetting::FILL: + name = "FILL"; + break; + default: + name = "UNKNOWN"; + break; + } + return fmt::formatter::format(name, ctx); + } +}; diff --git a/components/box-emu/src/box-emu.cpp b/components/box-emu/src/box-emu.cpp new file mode 100644 index 00000000..e11f8c03 --- /dev/null +++ b/components/box-emu/src/box-emu.cpp @@ -0,0 +1,749 @@ +#include "box-emu.hpp" + +BoxEmu::BoxEmu() : espp::BaseComponent("BoxEmu") { + detect(); +} + +BoxEmu::Version BoxEmu::version() const { + return version_; +} + +void BoxEmu::detect() { + bool mcp23x17_found = external_i2c_.probe_device(espp::Mcp23x17::DEFAULT_ADDRESS); + bool aw9523_found = external_i2c_.probe_device(espp::Aw9523::DEFAULT_ADDRESS); + if (aw9523_found) { + // Version 1 + version_ = BoxEmu::Version::V1; + } else if (mcp23x17_found) { + // Version 0 + version_ = BoxEmu::Version::V0; + } else { + logger_.warn("No box detected"); + // No box detected + version_ = BoxEmu::Version::UNKNOWN; + return; + } + logger_.info("version {}", version_); +} + +espp::I2c &BoxEmu::internal_i2c() { + return espp::EspBox::get().internal_i2c(); +} + +espp::I2c &BoxEmu::external_i2c() { + return external_i2c_; +} + +bool BoxEmu::initialize_box() { + logger_.info("Initializing EspBox"); + auto &box = espp::EspBox::get(); + // initialize the touchpad + if (!box.initialize_touch()) { + logger_.error("Failed to initialize touchpad!"); + return false; + } + // initialize the sound + if (!box.initialize_sound()) { + logger_.error("Failed to initialize sound!"); + return false; + } + // initialize the LCD + if (!box.initialize_lcd()) { + logger_.error("Failed to initialize LCD!"); + return false; + } + static constexpr size_t pixel_buffer_size = espp::EspBox::lcd_width() * num_rows_in_framebuffer; + // initialize the LVGL display for the esp-box + if (!box.initialize_display(pixel_buffer_size)) { + logger_.error("Failed to initialize display!"); + return false; + } + + // initialize the mute button to broadcast the mute state + logger_.info("Initializing mute button"); + mute_button_ = std::make_shared(espp::Button::Config{ + .name = "mute button", + .interrupt_config = + { + .gpio_num = espp::EspBox::get_mute_pin(), + .callback = + [](const espp::Interrupt::Event &event) { + espp::EspBox::get().mute(event.active); + // simply publish that the mute button was presssed + espp::EventManager::get().publish(mute_button_topic, {}); + }, + .active_level = espp::Interrupt::ActiveLevel::LOW, + .interrupt_type = espp::Interrupt::Type::ANY_EDGE, + .pullup_enabled = true, + .pulldown_enabled = false, + }, + .task_config = + { + .name = "mute button task", + .stack_size_bytes = 4 * 1024, + .priority = 5, + }, + .log_level = espp::Logger::Verbosity::WARN, + }); + + // update the mute state (since it's a flip-flop and may have been set if we + // restarted without power loss) + espp::EspBox::get().mute(mute_button_->is_pressed()); + return true; +} + +///////////////////////////////////////////////////////////////////////////// +// uSD Card +///////////////////////////////////////////////////////////////////////////// + +bool BoxEmu::initialize_sdcard() { + if (sdcard_) { + logger_.error("SD card already initialized!"); + return false; + } + + logger_.info("Initializing SD card"); + + esp_err_t ret; + // Options for mounting the filesystem. If format_if_mount_failed is set to + // true, SD card will be partitioned and formatted in case when mounting + // fails. + esp_vfs_fat_sdmmc_mount_config_t mount_config; + memset(&mount_config, 0, sizeof(mount_config)); + mount_config.format_if_mount_failed = false; + mount_config.max_files = 5; + mount_config.allocation_unit_size = 16 * 1024; + + // Use settings defined above to initialize SD card and mount FAT filesystem. + // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions. + // Please check its source code and implement error recovery when developing + // production applications. + logger_.debug("Using SPI peripheral"); + + // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) + // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI) + // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + host.slot = sdcard_spi_num; + // host.max_freq_khz = 20 * 1000; + + spi_bus_config_t bus_cfg; + memset(&bus_cfg, 0, sizeof(bus_cfg)); + bus_cfg.mosi_io_num = sdcard_mosi; + bus_cfg.miso_io_num = sdcard_miso; + bus_cfg.sclk_io_num = sdcard_sclk; + bus_cfg.quadwp_io_num = -1; + bus_cfg.quadhd_io_num = -1; + bus_cfg.max_transfer_sz = 8192; + spi_host_device_t host_id = (spi_host_device_t)host.slot; + ret = spi_bus_initialize(host_id, &bus_cfg, SDSPI_DEFAULT_DMA); + if (ret != ESP_OK) { + logger_.error("Failed to initialize bus."); + return false; + } + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + slot_config.gpio_cs = sdcard_cs; + slot_config.host_id = host_id; + + logger_.debug("Mounting filesystem"); + ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &sdcard_); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + logger_.error("Failed to mount filesystem. " + "If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option."); + return false; + } else { + logger_.error("Failed to initialize the card ({}). " + "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); + return false; + } + return false; + } + + logger_.info("Filesystem mounted"); + + // Card has been initialized, print its properties + sdmmc_card_print_info(stdout, sdcard_); + + return true; +} + +sdmmc_card_t *BoxEmu::sdcard() const { + return sdcard_; +} + +///////////////////////////////////////////////////////////////////////////// +// Memory +///////////////////////////////////////////////////////////////////////////// + +extern "C" uint8_t *osd_getromdata() { + auto &emu = BoxEmu::get(); + return emu.romdata(); +} + +bool BoxEmu::initialize_memory() { + if (romdata_) { + logger_.error("ROM already initialized!"); + return false; + } + + logger_.info("Initializing memory (romdata)"); + // allocate memory for the ROM and make sure it's on the SPIRAM + romdata_ = (uint8_t*)heap_caps_malloc(4*1024*1024, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + if (romdata_ == nullptr) { + logger_.error("Couldn't allocate memory for ROM!"); + return false; + } + + return true; +} + +size_t BoxEmu::copy_file_to_romdata(const std::string& filename) { + // load the file data and iteratively copy it over + std::ifstream romfile(filename, std::ios::binary | std::ios::ate); //open file at end + if (!romfile.is_open()) { + logger_.error("ROM file does not exist"); + return 0; + } + size_t filesize = romfile.tellg(); // get size from current file pointer location; + romfile.seekg(0, std::ios::beg); //reset file pointer to beginning; + romfile.read((char*)(romdata_), filesize); + romfile.close(); + + return filesize; +} + +uint8_t *BoxEmu::romdata() const { + return romdata_; +} + +///////////////////////////////////////////////////////////////////////////// +// Gamepad +///////////////////////////////////////////////////////////////////////////// + +bool BoxEmu::initialize_gamepad() { + logger_.info("Initializing gamepad"); + if (version_ == BoxEmu::Version::V0) { + auto raw_input = new version0::InputType( + std::make_shared(version0::InputDriver::Config{ + .port_0_direction_mask = version0::PORT_0_DIRECTION_MASK, + .port_0_interrupt_mask = version0::PORT_0_INTERRUPT_MASK, + .port_1_direction_mask = version0::PORT_1_DIRECTION_MASK, + .port_1_interrupt_mask = version0::PORT_1_INTERRUPT_MASK, + .write = std::bind(&espp::I2c::write, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + .read_register = std::bind(&espp::I2c::read_at_register, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), + .log_level = espp::Logger::Verbosity::WARN + }) + ); + input_.reset(raw_input); + } else if (version_ == BoxEmu::Version::V1) { + auto raw_input = new version1::InputType( + std::make_shared(version1::InputDriver::Config{ + .port_0_direction_mask = version1::PORT_0_DIRECTION_MASK, + .port_0_interrupt_mask = version1::PORT_0_INTERRUPT_MASK, + .port_1_direction_mask = version1::PORT_1_DIRECTION_MASK, + .port_1_interrupt_mask = version1::PORT_1_INTERRUPT_MASK, + .write = std::bind(&espp::I2c::write, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + .write_then_read = std::bind(&espp::I2c::write_read, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + .log_level = espp::Logger::Verbosity::WARN + }) + ); + input_.reset(raw_input); + } else { + return false; + } + + // now initialize the keypad driver + keypad_ = std::make_shared(espp::KeypadInput::Config{ + .read = std::bind(&BoxEmu::keypad_read, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), + .log_level = espp::Logger::Verbosity::WARN + }); + + // now initialize the input timer + input_timer_ = std::make_shared(espp::HighResolutionTimer::Config{ + .name = "Input timer", + .callback = [this]() { + espp::EspBox::get().update_touch(); + update_gamepad_state(); + }}); + uint64_t period_us = 30 * 1000; + input_timer_->periodic(period_us); + + return true; +} + +GamepadState BoxEmu::gamepad_state() { + std::lock_guard lock(gamepad_state_mutex_); + return gamepad_state_; +} + +bool BoxEmu::update_gamepad_state() { + if (!input_) { + return false; + } + if (!can_read_gamepad_) { + return false; + } + std::error_code ec; + auto pins = input_->get_pins(ec); + if (ec) { + logger_.error("Error reading input pins: {}", ec.message()); + can_read_gamepad_ = false; + return false; + } + + auto new_gamepad_state = input_->pins_to_gamepad_state(pins); + bool changed = false; + { + std::lock_guard lock(gamepad_state_mutex_); + changed = gamepad_state_ != new_gamepad_state; + gamepad_state_ = new_gamepad_state; + } + input_->handle_volume_pins(pins); + + return changed; +} + +void BoxEmu::keypad_read(bool *up, bool *down, bool *left, bool *right, bool *enter, bool *escape) { + std::lock_guard lock(gamepad_state_mutex_); + *up = gamepad_state_.up; + *down = gamepad_state_.down; + *left = gamepad_state_.left; + *right = gamepad_state_.right; + + *enter = gamepad_state_.a || gamepad_state_.start; + *escape = gamepad_state_.b || gamepad_state_.select; +} + +std::shared_ptr BoxEmu::keypad() const { + return keypad_; +} + +///////////////////////////////////////////////////////////////////////////// +// Battery +///////////////////////////////////////////////////////////////////////////// + +bool BoxEmu::initialize_battery() { + if (version_ == BoxEmu::Version::V0) { + logger_.warn("Battery not supported on version 0"); + return false; + } + + if (battery_) { + logger_.error("Battery already initialized!"); + return false; + } + + logger_.info("Initializing battery"); + + battery_comms_good_ = external_i2c_.probe_device(espp::Max1704x::DEFAULT_ADDRESS); + if (!battery_comms_good_) { + logger_.error("Could not communicate with battery!"); + return false; + } + + // now make the Max17048 that we'll use to get good state of charge, charge + // rate, etc. + battery_ = std::make_shared(espp::Max1704x::Config{ + .device_address = espp::Max1704x::DEFAULT_ADDRESS, + .write = std::bind(&espp::I2c::write, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + .read = std::bind(&espp::I2c::read, &external_i2c_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) + }); + + // // NOTE: we could also make an ADC for measuring battery voltage + // // make the adc channels + // channels.clear(); + // channels.push_back({ + // .unit = BATTERY_ADC_UNIT, + // .channel = BATTERY_ADC_CHANNEL, + // .attenuation = ADC_ATTEN_DB_12}); + // adc_ = std::make_shared(espp::OneshotAdc::Config{ + // .unit = BATTERY_ADC_UNIT, + // .channels = channels + // }); + + // NOTE: the MAX17048 is tied to the VBAT for its power supply (as you would + // imagine), this means that we cannnot communicate with it if the battery is + // not connected. Therefore, if we are unable to communicate with the battery + // we will just return and not start the battery task. + battery_task_ = std::make_shared(espp::HighResolutionTimer::Config{ + .name = "battery", + .callback = [this]() { + std::error_code ec; + // get the voltage (V) + auto voltage = battery_->get_battery_voltage(ec); + if (ec) { + fmt::print("Error getting battery voltage: {}\n", ec.message()); + fmt::print("Battery is probably not connected!\n"); + fmt::print("Stopping battery task...\n"); + battery_task_->stop(); + return; + } + // get the state of charge (%) + auto soc = battery_->get_battery_percentage(ec); + if (ec) { + fmt::print("Error getting battery percentage: {}\n", ec.message()); + fmt::print("Battery is probably not connected!\n"); + fmt::print("Stopping battery task...\n"); + battery_task_->stop(); + return; + } + // get the charge rate (+/- % per hour) + auto charge_rate = battery_->get_battery_charge_rate(ec); + if (ec) { + fmt::print("Error getting battery charge rate: {}\n", ec.message()); + fmt::print("Battery is probably not connected!\n"); + fmt::print("Stopping battery task...\n"); + battery_task_->stop(); + return; + } + + // NOTE: we could also get voltage from the adc for the battery if we + // wanted, but the MAX17048 gives us the same voltage anyway + // auto maybe_mv = adc_->read_mv(channels[0]); + // if (maybe_mv.has_value()) { + // // convert mv -> V and from the voltage divider (R1=R2) to real + // // battery volts + // voltage = maybe_mv.value() / 1000.0f * 2.0f; + // } + + // now publish a BatteryInfo struct to the battery_topic + auto battery_info = BatteryInfo{ + .voltage = voltage, + .level = soc, + .charge_rate = charge_rate, + }; + std::vector battery_info_data; + // fmt::print("Publishing battery info: {}\n", battery_info); + auto bytes_serialized = espp::serialize(battery_info, battery_info_data); + if (bytes_serialized == 0) { + return; + } + espp::EventManager::get().publish(battery_topic, battery_info_data); + return; + }}); + uint64_t battery_period_us = 500 * 1000; // 500ms + battery_task_->periodic(battery_period_us); + + return true; +} + +std::shared_ptr BoxEmu::battery() const { + return battery_; +} + +///////////////////////////////////////////////////////////////////////////// +// Video +///////////////////////////////////////////////////////////////////////////// + +bool BoxEmu::initialize_video() { + if (video_task_) { + logger_.error("Video task already initialized!"); + return false; + } + + logger_.info("initializing video task"); + + video_queue_ = xQueueCreate(1, sizeof(uint16_t*)); + video_task_ = std::make_shared(espp::Task::Config{ + .name = "video task", + .callback = std::bind(&BoxEmu::video_task_callback, this, std::placeholders::_1, std::placeholders::_2), + .stack_size_bytes = 4*1024, + .priority = 20, + .core_id = 1 + }); + video_task_->start(); + + return true; +} + +void BoxEmu::display_size(size_t width, size_t height) { + display_width_ = width; + display_height_ = height; +} + +void BoxEmu::native_size(size_t width, size_t height, int pitch) { + native_width_ = width; + native_height_ = height; + native_pitch_ = pitch == -1 ? width : pitch; +} + +void BoxEmu::palette(const uint16_t *palette, size_t size) { + palette_ = palette; + palette_size_ = size; +} + +void BoxEmu::push_frame(const void* frame) { + if (video_queue_ == nullptr) { + logger_.error("video queue is null, make sure to call initialize_video() first!"); + return; + } + xQueueSend(video_queue_, &frame, 10 / portTICK_PERIOD_MS); +} + +VideoSetting BoxEmu::video_setting() const { + return video_setting_; +} + +void BoxEmu::video_setting(const VideoSetting setting) { + video_setting_ = setting; +} + +///////////////////////////////////////////////////////////////////////////// +// USB +///////////////////////////////////////////////////////////////////////////// + +#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) + +enum { + ITF_NUM_MSC = 0, + ITF_NUM_TOTAL +}; + +enum { + EDPT_CTRL_OUT = 0x00, + EDPT_CTRL_IN = 0x80, + + EDPT_MSC_OUT = 0x01, + EDPT_MSC_IN = 0x81, +}; + +static uint8_t const desc_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), +}; + +static tusb_desc_device_t descriptor_config = { + .bLength = sizeof(descriptor_config), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers + .idProduct = 0x4002, + .bcdDevice = 0x100, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +static char const *string_desc_arr[] = { + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "Finger563", // 1: Manufacturer + "ESP-Box-Emu", // 2: Product + "123456", // 3: Serials + "Box-Emu uSD Card", // 4. MSC +}; + +bool BoxEmu::is_usb_enabled() const { + return usb_enabled_; +} + +bool BoxEmu::initialize_usb() { + if (usb_enabled_) { + logger_.error("USB MSC already initialized!"); + return false; + } + + logger_.info("USB MSC initialization"); + + // get the card from the filesystem initialization + auto card = sdcard(); + if (!card) { + logger_.error("No SD card found, skipping USB MSC initialization"); + return false; + } + + logger_.debug("Deleting JTAG PHY"); + usb_del_phy(jtag_phy_); + + fmt::print("USB MSC initialization\n"); + // register the callback for the storage mount changed event. + tinyusb_msc_sdmmc_config_t config_sdmmc = { + .card = card, + .callback_mount_changed = nullptr, + .callback_premount_changed = nullptr, + .mount_config = { + .format_if_mount_failed = false, + .max_files = 5, + .allocation_unit_size = 16 * 1024, // sector size is 512 bytes, this should be between sector size and (128 * sector size). Larger means higher read/write performance and higher overhead for small files. + .disk_status_check_enable = false, // true if you see issues or are unmounted properly; slows down I/O + }, + }; + ESP_ERROR_CHECK(tinyusb_msc_storage_init_sdmmc(&config_sdmmc)); + // ESP_ERROR_CHECK(tinyusb_msc_register_callback(TINYUSB_MSC_EVENT_MOUNT_CHANGED, storage_mount_changed_cb)); + + // initialize the tinyusb stack + fmt::print("USB MSC initialization\n"); + tinyusb_config_t tusb_cfg; + memset(&tusb_cfg, 0, sizeof(tusb_cfg)); + tusb_cfg.device_descriptor = &descriptor_config; + tusb_cfg.string_descriptor = string_desc_arr; + tusb_cfg.string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]); + tusb_cfg.external_phy = false; + tusb_cfg.configuration_descriptor = desc_configuration; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); + fmt::print("USB MSC initialization DONE\n"); + usb_enabled_ = true; + + return true; +} + +bool BoxEmu::deinitialize_usb() { + if (!usb_enabled_) { + logger_.warn("USB MSC not initialized"); + return false; + } + logger_.info("USB MSC deinitialization"); + auto err = tinyusb_driver_uninstall(); + if (err != ESP_OK) { + logger_.error("tinyusb_driver_uninstall failed: {}", esp_err_to_name(err)); + return false; + } + usb_enabled_ = false; + // and reconnect the CDC port, see: + // https://github.com/espressif/idf-extra-components/pull/229 + usb_phy_config_t phy_conf; + memset(&phy_conf, 0, sizeof(phy_conf)); + phy_conf.controller = USB_PHY_CTRL_SERIAL_JTAG; + usb_new_phy(&phy_conf, &jtag_phy_); + return true; +} + +///////////////////////////////////////////////////////////////////////////// +// Static Video Task: +///////////////////////////////////////////////////////////////////////////// + +bool BoxEmu::has_palette() const { + return palette_ != nullptr; +} + +bool BoxEmu::is_native() const { + return native_width_ == display_width_ && native_height_ == display_height_; +} + +int BoxEmu::x_offset() const { + return (espp::EspBox::lcd_width()-display_width_)/2; +} + +int BoxEmu::y_offset() const { + return (espp::EspBox::lcd_height()-display_height_)/2; +} + +const uint16_t* BoxEmu::palette() const { + return palette_; +} + +bool BoxEmu::video_task_callback(std::mutex &m, std::condition_variable& cv) { + const void *_frame_ptr; + if (xQueuePeek(video_queue_, &_frame_ptr, 100 / portTICK_PERIOD_MS) != pdTRUE) { + // we couldn't get anything from the queue, return + return false; + } + if (_frame_ptr == nullptr) { + // make sure we clear the queue + xQueueReceive(video_queue_, &_frame_ptr, 10 / portTICK_PERIOD_MS); + // we got a nullptr, return + return false; + } + static constexpr int num_lines_to_write = num_rows_in_framebuffer; + auto &box = espp::EspBox::get(); + static int vram_index = 0; // has to be static so that it persists between calls + const int _x_offset = x_offset(); + const int _y_offset = y_offset(); + const uint16_t* _palette = palette(); + if (is_native()) { + for (int y=0; y(num_lines_to_write, display_height_-y); + if (has_palette()) { + const uint8_t* _frame = (const uint8_t*)_frame_ptr; + for (int i=0; i(x_scale * native_width_, 0, espp::EspBox::lcd_width()); + for (int y=0; y= max_y) { + break; + } + int source_y = (float)_y * inv_y_scale; + // shoudl i put this around the outer loop or is this loop a good + // balance for perfomance of the check? + if (has_palette()) { + const uint8_t* _frame = (const uint8_t*)_frame_ptr; + // write two pixels (32 bits) at a time because it's faster + for (int x=0; x + +extern "C" uint16_t make_color(uint8_t r, uint8_t g, uint8_t b) { + return lv_color_make(r,g,b).full; +} diff --git a/components/codec/CMakeLists.txt b/components/codec/CMakeLists.txt deleted file mode 100644 index 57e760ff..00000000 --- a/components/codec/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -idf_component_register( - SRC_DIRS - "es7210" - "es8311" - "es8388" - INCLUDE_DIRS - "es7210" - "es8311" - "es8388" - "include" - REQUIRES - driver - ) diff --git a/components/codec/es7210/es7210.cpp b/components/codec/es7210/es7210.cpp deleted file mode 100644 index 478fda10..00000000 --- a/components/codec/es7210/es7210.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2021 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include "esp_log.h" -#include "es7210.hpp" - -static write_fn i2c_write_ = nullptr; -static read_register_fn i2c_read_register_ = nullptr; - -void set_es7210_write(write_fn fn) { - i2c_write_ = fn; -} -void set_es7210_read(read_register_fn fn) { - i2c_read_register_ = fn; -} - -#define I2S_DSP_MODE_A 0 -#define MCLK_DIV_FRE 256 - -/* ES7210 address*/ -#define ES7210_ADDR ES7210_AD1_AD0_00 -#define ES7210_MCLK_SOURCE FROM_CLOCK_DOUBLE_PIN /* In master mode, 0 : MCLK from pad 1 : MCLK from clock doubler */ -#define FROM_PAD_PIN 0 -#define FROM_CLOCK_DOUBLE_PIN 1 - -/* - * Clock coefficient structer - */ -struct _coeff_div { - uint32_t mclk; /* mclk frequency */ - uint32_t lrck; /* lrck */ - uint8_t ss_ds; - uint8_t adc_div; /* adcclk divider */ - uint8_t dll; /* dll_bypass */ - uint8_t doubler; /* doubler enable */ - uint8_t osr; /* adc osr */ - uint8_t mclk_src; /* select mclk source */ - uint32_t lrck_h; /* The high 4 bits of lrck */ - uint32_t lrck_l; /* The low 8 bits of lrck */ -}; - -static const char *TAG = "ES7210"; -static es7210_input_mics_t mic_select = (es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3 | ES7210_INPUT_MIC4); - -/* Codec hifi mclk clock divider coefficients - * MEMBER REG - * mclk: 0x03 - * lrck: standard - * ss_ds: -- - * adc_div: 0x02 - * dll: 0x06 - * doubler: 0x02 - * osr: 0x07 - * mclk_src: 0x03 - * lrckh: 0x04 - * lrckl: 0x05 -*/ -static const struct _coeff_div coeff_div[] = { - //mclk lrck ss_ds adc_div dll doubler osr mclk_src lrckh lrckl - /* 8k */ - {12288000, 8000 , 0x00, 0x03, 0x01, 0x00, 0x20, 0x00, 0x06, 0x00}, - {16384000, 8000 , 0x00, 0x04, 0x01, 0x00, 0x20, 0x00, 0x08, 0x00}, - {19200000, 8000 , 0x00, 0x1e, 0x00, 0x01, 0x28, 0x00, 0x09, 0x60}, - {4096000, 8000 , 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00}, - - /* 11.025k */ - {11289600, 11025, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00}, - - /* 12k */ - {12288000, 12000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00}, - {19200000, 12000, 0x00, 0x14, 0x00, 0x01, 0x28, 0x00, 0x06, 0x40}, - - /* 16k */ - {4096000, 16000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00}, - {19200000, 16000, 0x00, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x80}, - {16384000, 16000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00}, - {12288000, 16000, 0x00, 0x03, 0x01, 0x01, 0x20, 0x00, 0x03, 0x00}, - - /* 22.05k */ - {11289600, 22050, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00}, - - /* 24k */ - {12288000, 24000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00}, - {19200000, 24000, 0x00, 0x0a, 0x00, 0x01, 0x28, 0x00, 0x03, 0x20}, - - /* 32k */ - {12288000, 32000, 0x00, 0x03, 0x00, 0x00, 0x20, 0x00, 0x01, 0x80}, - {16384000, 32000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00}, - {19200000, 32000, 0x00, 0x05, 0x00, 0x00, 0x1e, 0x00, 0x02, 0x58}, - - /* 44.1k */ - {11289600, 44100, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00}, - - /* 48k */ - {12288000, 48000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00}, - {19200000, 48000, 0x00, 0x05, 0x00, 0x01, 0x28, 0x00, 0x01, 0x90}, - - /* 64k */ - {16384000, 64000, 0x01, 0x01, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00}, - {19200000, 64000, 0x00, 0x05, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x2c}, - - /* 88.2k */ - {11289600, 88200, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80}, - - /* 96k */ - {12288000, 96000, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80}, - {19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8}, -}; - -static esp_err_t es7210_write_reg(uint8_t reg_addr, uint8_t data) -{ - uint8_t write_buf[2] = {reg_addr, data}; - return i2c_write_(ES7210_ADDR, write_buf, sizeof(write_buf)) ? ESP_OK : ESP_FAIL; -} - -static esp_err_t es7210_update_reg_bit(uint8_t reg_addr, uint8_t update_bits, uint8_t data) -{ - uint8_t regv; - regv = es7210_read_reg(reg_addr); - regv = (regv & (~update_bits)) | (update_bits & data); - return es7210_write_reg(reg_addr, regv); -} - -static int get_coeff(uint32_t mclk, uint32_t lrck) -{ - for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) { - if (coeff_div[i].lrck == lrck && coeff_div[i].mclk == mclk) - return i; - } - return -1; -} - -int8_t get_es7210_mclk_src(void) -{ - return ES7210_MCLK_SOURCE; -} - -int es7210_read_reg(uint8_t reg_addr) -{ - uint8_t data; - i2c_read_register_(ES7210_ADDR, reg_addr, &data, 1); - return (int)data; -} - -esp_err_t es7210_config_sample(audio_hal_iface_samples_t sample) -{ - uint8_t regv; - int coeff; - int sample_fre = 0; - int mclk_fre = 0; - esp_err_t ret = ESP_OK; - switch (sample) { - case AUDIO_HAL_08K_SAMPLES: - sample_fre = 8000; - break; - case AUDIO_HAL_11K_SAMPLES: - sample_fre = 11025; - break; - case AUDIO_HAL_16K_SAMPLES: - sample_fre = 16000; - break; - case AUDIO_HAL_22K_SAMPLES: - sample_fre = 22050; - break; - case AUDIO_HAL_24K_SAMPLES: - sample_fre = 24000; - break; - case AUDIO_HAL_32K_SAMPLES: - sample_fre = 32000; - break; - case AUDIO_HAL_44K_SAMPLES: - sample_fre = 44100; - break; - case AUDIO_HAL_48K_SAMPLES: - sample_fre = 48000; - break; - default: - ESP_LOGE(TAG, "Unable to configure sample rate %dHz", sample_fre); - break; - } - mclk_fre = sample_fre * MCLK_DIV_FRE; - coeff = get_coeff(mclk_fre, sample_fre); - if (coeff < 0) { - ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK", sample_fre, mclk_fre); - return ESP_FAIL; - } - /* Set clock parammeters */ - if (coeff >= 0) { - /* Set adc_div & doubler & dll */ - regv = es7210_read_reg(ES7210_MAINCLK_REG02) & 0x00; - regv |= coeff_div[coeff].adc_div; - regv |= coeff_div[coeff].doubler << 6; - regv |= coeff_div[coeff].dll << 7; - ret |= es7210_write_reg(ES7210_MAINCLK_REG02, regv); - /* Set osr */ - regv = coeff_div[coeff].osr; - ret |= es7210_write_reg(ES7210_OSR_REG07, regv); - /* Set lrck */ - regv = coeff_div[coeff].lrck_h; - ret |= es7210_write_reg(ES7210_LRCK_DIVH_REG04, regv); - regv = coeff_div[coeff].lrck_l; - ret |= es7210_write_reg(ES7210_LRCK_DIVL_REG05, regv); - } - return ret; -} - -esp_err_t es7210_mic_select(es7210_input_mics_t mic) -{ - esp_err_t ret = ESP_OK; - mic_select = mic; - if (mic_select & (ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3 | ES7210_INPUT_MIC4)) { - for (int i = 0; i < 4; i++) { - ret |= es7210_update_reg_bit(ES7210_MIC1_GAIN_REG43 + i, 0x10, 0x00); - } - ret |= es7210_write_reg(ES7210_MIC12_POWER_REG4B, 0xff); - ret |= es7210_write_reg(ES7210_MIC34_POWER_REG4C, 0xff); - if (mic_select & ES7210_INPUT_MIC1) { - ESP_LOGI(TAG, "Enable ES7210_INPUT_MIC1"); - ret |= es7210_update_reg_bit(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00); - ret |= es7210_write_reg(ES7210_MIC12_POWER_REG4B, 0x00); - ret |= es7210_update_reg_bit(ES7210_MIC1_GAIN_REG43, 0x10, 0x10); - } - if (mic_select & ES7210_INPUT_MIC2) { - ESP_LOGI(TAG, "Enable ES7210_INPUT_MIC2"); - ret |= es7210_update_reg_bit(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00); - ret |= es7210_write_reg(ES7210_MIC12_POWER_REG4B, 0x00); - ret |= es7210_update_reg_bit(ES7210_MIC2_GAIN_REG44, 0x10, 0x10); - } - if (mic_select & ES7210_INPUT_MIC3) { - ESP_LOGI(TAG, "Enable ES7210_INPUT_MIC3"); - ret |= es7210_update_reg_bit(ES7210_CLOCK_OFF_REG01, 0x15, 0x00); - ret |= es7210_write_reg(ES7210_MIC34_POWER_REG4C, 0x00); - ret |= es7210_update_reg_bit(ES7210_MIC3_GAIN_REG45, 0x10, 0x10); - } - if (mic_select & ES7210_INPUT_MIC4) { - ESP_LOGI(TAG, "Enable ES7210_INPUT_MIC4"); - ret |= es7210_update_reg_bit(ES7210_CLOCK_OFF_REG01, 0x15, 0x00); - ret |= es7210_write_reg(ES7210_MIC34_POWER_REG4C, 0x00); - ret |= es7210_update_reg_bit(ES7210_MIC4_GAIN_REG46, 0x10, 0x10); - } - } else { - ESP_LOGE(TAG, "Microphone selection error"); - return ESP_FAIL; - } - return ret; -} - -esp_err_t es7210_adc_init(audio_hal_codec_config_t *codec_cfg) -{ - esp_err_t ret = ESP_OK; - - ret |= es7210_write_reg(ES7210_RESET_REG00, 0xff); - ret |= es7210_write_reg(ES7210_RESET_REG00, 0x41); - ret |= es7210_write_reg(ES7210_CLOCK_OFF_REG01, 0x1f); - ret |= es7210_write_reg(ES7210_TIME_CONTROL0_REG09, 0x30); /* Set chip state cycle */ - ret |= es7210_write_reg(ES7210_TIME_CONTROL1_REG0A, 0x30); /* Set power on state cycle */ - // ret |= es7210_write_reg(ES7210_ADC12_HPF2_REG23, 0x2a); /* Quick setup */ - // ret |= es7210_write_reg(ES7210_ADC12_HPF1_REG22, 0x0a); - // ret |= es7210_write_reg(ES7210_ADC34_HPF2_REG20, 0x0a); - // ret |= es7210_write_reg(ES7210_ADC34_HPF1_REG21, 0x2a); - /* Set master/slave audio interface */ - audio_hal_codec_i2s_iface_t *i2s_cfg = & (codec_cfg->i2s_iface); - switch (i2s_cfg->mode) { - case AUDIO_HAL_MODE_MASTER: /* MASTER MODE */ - ESP_LOGI(TAG, "ES7210 in Master mode"); - // ret |= es7210_update_reg_bit(ES7210_MODE_CONFIG_REG08, 0x01, 0x01); - ret |= es7210_write_reg(ES7210_MODE_CONFIG_REG08, 0x20); - /* Select clock source for internal mclk */ - switch (get_es7210_mclk_src()) { - case FROM_PAD_PIN: - ret |= es7210_update_reg_bit(ES7210_MASTER_CLK_REG03, 0x80, 0x00); - break; - case FROM_CLOCK_DOUBLE_PIN: - ret |= es7210_update_reg_bit(ES7210_MASTER_CLK_REG03, 0x80, 0x80); - break; - default: - ret |= es7210_update_reg_bit(ES7210_MASTER_CLK_REG03, 0x80, 0x00); - break; - } - break; - case AUDIO_HAL_MODE_SLAVE: /* SLAVE MODE */ - ESP_LOGI(TAG, "ES7210 in Slave mode"); - break; - default: - break; - } - ret |= es7210_write_reg(ES7210_ANALOG_REG40, 0xC3); /* Select power off analog, vdda = 3.3V, close vx20ff, VMID select 5KΩ start */ - ret |= es7210_write_reg(ES7210_MIC12_BIAS_REG41, 0x70); /* Select 2.87v */ - ret |= es7210_write_reg(ES7210_MIC34_BIAS_REG42, 0x70); /* Select 2.87v */ - ret |= es7210_write_reg(ES7210_OSR_REG07, 0x20); - ret |= es7210_write_reg(ES7210_MAINCLK_REG02, 0xc1); /* Set the frequency division coefficient and use dll except clock doubler, and need to set 0xc1 to clear the state */ - ret |= es7210_config_sample(i2s_cfg->samples); - ret |= es7210_mic_select(mic_select); - ret |= es7210_adc_set_gain_all(GAIN_0DB); - return ESP_OK; -} - -esp_err_t es7210_adc_deinit() -{ - return ESP_OK; -} - -esp_err_t es7210_config_fmt(audio_hal_iface_format_t fmt) -{ - esp_err_t ret = ESP_OK; - uint8_t adc_iface = 0; - adc_iface = es7210_read_reg(ES7210_SDP_INTERFACE1_REG11); - adc_iface &= 0xfc; - switch (fmt) { - case AUDIO_HAL_I2S_NORMAL: - ESP_LOGD(TAG, "ES7210 in I2S Format"); - adc_iface |= 0x00; - break; - case AUDIO_HAL_I2S_LEFT: - case AUDIO_HAL_I2S_RIGHT: - ESP_LOGD(TAG, "ES7210 in LJ Format"); - adc_iface |= 0x01; - break; - case AUDIO_HAL_I2S_DSP: - if (I2S_DSP_MODE_A) { - ESP_LOGD(TAG, "ES7210 in DSP-A Format"); - adc_iface |= 0x03; - } else { - ESP_LOGD(TAG, "ES7210 in DSP-B Format"); - adc_iface |= 0x13; - } - break; - default: - adc_iface &= 0xfc; - break; - } - ret |= es7210_write_reg(ES7210_SDP_INTERFACE1_REG11, adc_iface); - return ret; -} - -esp_err_t es7210_set_bits(audio_hal_iface_bits_t bits) -{ - esp_err_t ret = ESP_OK; - uint8_t adc_iface = 0; - adc_iface = es7210_read_reg(ES7210_SDP_INTERFACE1_REG11); - adc_iface &= 0x1f; - switch (bits) { - case AUDIO_HAL_BIT_LENGTH_16BITS: - adc_iface |= 0x60; - break; - case AUDIO_HAL_BIT_LENGTH_24BITS: - adc_iface |= 0x00; - break; - case AUDIO_HAL_BIT_LENGTH_32BITS: - adc_iface |= 0x80; - break; - default: - adc_iface |= 0x60; - break; - } - ret |= es7210_write_reg(ES7210_SDP_INTERFACE1_REG11, adc_iface); - return ret; -} - -esp_err_t es7210_adc_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface) -{ - esp_err_t ret = ESP_OK; - ret |= es7210_set_bits(iface->bits); - ret |= es7210_config_fmt(iface->fmt); - ret |= es7210_config_sample(iface->samples); - return ret; -} - -esp_err_t es7210_start(uint8_t clock_reg_value) -{ - esp_err_t ret = ESP_OK; - ret |= es7210_write_reg(ES7210_CLOCK_OFF_REG01, clock_reg_value); - ret |= es7210_write_reg(ES7210_POWER_DOWN_REG06, 0x00); - // ret |= es7210_write_reg(ES7210_ANALOG_REG40, 0x40); - ret |= es7210_write_reg(ES7210_MIC1_POWER_REG47, 0x00); - ret |= es7210_write_reg(ES7210_MIC2_POWER_REG48, 0x00); - ret |= es7210_write_reg(ES7210_MIC3_POWER_REG49, 0x00); - ret |= es7210_write_reg(ES7210_MIC4_POWER_REG4A, 0x00); - ret |= es7210_mic_select(mic_select); - return ret; -} - -esp_err_t es7210_stop(void) -{ - esp_err_t ret = ESP_OK; - ret |= es7210_write_reg(ES7210_MIC1_POWER_REG47, 0xff); - ret |= es7210_write_reg(ES7210_MIC2_POWER_REG48, 0xff); - ret |= es7210_write_reg(ES7210_MIC3_POWER_REG49, 0xff); - ret |= es7210_write_reg(ES7210_MIC4_POWER_REG4A, 0xff); - ret |= es7210_write_reg(ES7210_MIC12_POWER_REG4B,0xff); - ret |= es7210_write_reg(ES7210_MIC34_POWER_REG4C, 0xff); - // ret |= es7210_write_reg(ES7210_ANALOG_REG40, 0xc0); - ret |= es7210_write_reg(ES7210_CLOCK_OFF_REG01, 0x7f); - ret |= es7210_write_reg(ES7210_POWER_DOWN_REG06, 0x07); - return ret; -} - -esp_err_t es7210_adc_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) -{ - static uint8_t regv; - esp_err_t ret = ESP_OK; - // ESP_LOGW(TAG, "ES7210 only supports ADC mode"); - ret = es7210_read_reg(ES7210_CLOCK_OFF_REG01); - if ((ret != 0x7f) && (ret != 0xff)) { - regv = es7210_read_reg(ES7210_CLOCK_OFF_REG01); - } - if (ctrl_state == AUDIO_HAL_CTRL_START) { - ESP_LOGI(TAG, "The ES7210_CLOCK_OFF_REG01 value before stop is %x",regv); - ret |= es7210_start(regv); - } else { - ESP_LOGW(TAG, "The codec is about to stop"); - regv = es7210_read_reg(ES7210_CLOCK_OFF_REG01); - ret |= es7210_stop(); - } - return ESP_OK; -} - -esp_err_t es7210_adc_set_gain(es7210_input_mics_t mic_mask, es7210_gain_value_t gain) -{ - esp_err_t ret_val = ESP_OK; - - if (gain < GAIN_0DB) { - gain = GAIN_0DB; - } - - if (gain > GAIN_37_5DB) { - gain = GAIN_37_5DB; - } - - if (mic_mask & ES7210_INPUT_MIC1) { - ret_val |= es7210_update_reg_bit(ES7210_MIC1_GAIN_REG43, 0x0f, gain); - } - if (mic_mask & ES7210_INPUT_MIC2) { - ret_val |= es7210_update_reg_bit(ES7210_MIC2_GAIN_REG44, 0x0f, gain); - } - if (mic_mask & ES7210_INPUT_MIC3) { - ret_val |= es7210_update_reg_bit(ES7210_MIC3_GAIN_REG45, 0x0f, gain); - } - if (mic_mask & ES7210_INPUT_MIC4) { - ret_val |= es7210_update_reg_bit(ES7210_MIC4_GAIN_REG46, 0x0f, gain); - } - - return ret_val; -} - -esp_err_t es7210_adc_set_gain_all(es7210_gain_value_t gain) -{ - esp_err_t ret = ESP_OK; - uint32_t max_gain_vaule = 14; - if (gain < 0) { - gain = (es7210_gain_value_t)0; - } else if (gain > max_gain_vaule) { - gain = (es7210_gain_value_t)max_gain_vaule; - } - ESP_LOGD(TAG, "SET: gain:%d", gain); - if (mic_select & ES7210_INPUT_MIC1) { - ret |= es7210_update_reg_bit(ES7210_MIC1_GAIN_REG43, 0x0f, gain); - } - if (mic_select & ES7210_INPUT_MIC2) { - ret |= es7210_update_reg_bit(ES7210_MIC2_GAIN_REG44, 0x0f, gain); - } - if (mic_select & ES7210_INPUT_MIC3) { - ret |= es7210_update_reg_bit(ES7210_MIC3_GAIN_REG45, 0x0f, gain); - } - if (mic_select & ES7210_INPUT_MIC4) { - ret |= es7210_update_reg_bit(ES7210_MIC4_GAIN_REG46, 0x0f, gain); - } - return ret; -} - -esp_err_t es7210_adc_get_gain(es7210_input_mics_t mic_mask, es7210_gain_value_t *gain) -{ - int regv = 0; - uint8_t gain_value; - if (mic_mask & ES7210_INPUT_MIC1) { - regv = es7210_read_reg(ES7210_MIC1_GAIN_REG43); - } else if (mic_mask & ES7210_INPUT_MIC2) { - regv = es7210_read_reg(ES7210_MIC2_GAIN_REG44); - } else if (mic_mask & ES7210_INPUT_MIC3) { - regv = es7210_read_reg(ES7210_MIC3_GAIN_REG45); - } else if (mic_mask & ES7210_INPUT_MIC4) { - regv = es7210_read_reg(ES7210_MIC4_GAIN_REG46); - } else { - ESP_LOGE(TAG, "No MIC selected"); - return ESP_FAIL; - } - if (regv == ESP_FAIL) { - return regv; - } - gain_value = (regv & 0x0f); /* Retain the last four bits for gain */ - *gain = (es7210_gain_value_t)gain_value; - ESP_LOGI(TAG, "GET: gain_value:%d", gain_value); - return ESP_OK; -} - -esp_err_t es7210_adc_set_volume(int volume) -{ - esp_err_t ret = ESP_OK; - ESP_LOGD(TAG, "ADC can adjust gain"); - return ret; -} - -esp_err_t es7210_set_mute(uint8_t enable) -{ - ESP_LOGD(TAG, "ES7210 SetMute :%d", enable); - return ESP_OK; -} - -void es7210_read_all(void) -{ - for (int i = 0; i <= 0x4E; i++) { - uint8_t reg = es7210_read_reg(i); - printf("REG:%02x, %02x\n", reg, i); - } -} diff --git a/components/codec/es7210/es7210.hpp b/components/codec/es7210/es7210.hpp deleted file mode 100644 index f01b83cb..00000000 --- a/components/codec/es7210/es7210.hpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2021 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _ES7210_H -#define _ES7210_H - -#include - -#include "audio_hal.h" - -typedef std::function write_fn; -typedef std::function read_register_fn; - -void set_es7210_write(write_fn fn); -void set_es7210_read(read_register_fn fn); - -#ifdef __cplusplus -extern "C" { -#endif - -#define ES7210_RESET_REG00 0x00 /* Reset control */ -#define ES7210_CLOCK_OFF_REG01 0x01 /* Used to turn off the ADC clock */ -#define ES7210_MAINCLK_REG02 0x02 /* Set ADC clock frequency division */ -#define ES7210_MASTER_CLK_REG03 0x03 /* MCLK source $ SCLK division */ -#define ES7210_LRCK_DIVH_REG04 0x04 /* lrck_divh */ -#define ES7210_LRCK_DIVL_REG05 0x05 /* lrck_divl */ -#define ES7210_POWER_DOWN_REG06 0x06 /* power down */ -#define ES7210_OSR_REG07 0x07 -#define ES7210_MODE_CONFIG_REG08 0x08 /* Set master/slave & channels */ -#define ES7210_TIME_CONTROL0_REG09 0x09 /* Set Chip intial state period*/ -#define ES7210_TIME_CONTROL1_REG0A 0x0A /* Set Power up state period */ -#define ES7210_SDP_INTERFACE1_REG11 0x11 /* Set sample & fmt */ -#define ES7210_SDP_INTERFACE2_REG12 0x12 /* Pins state */ -#define ES7210_ADC_AUTOMUTE_REG13 0x13 /* Set mute */ -#define ES7210_ADC34_MUTERANGE_REG14 0x14 /* Set mute range */ -#define ES7210_ADC34_HPF2_REG20 0x20 /* HPF */ -#define ES7210_ADC34_HPF1_REG21 0x21 -#define ES7210_ADC12_HPF1_REG22 0x22 -#define ES7210_ADC12_HPF2_REG23 0x23 -#define ES7210_ANALOG_REG40 0x40 /* ANALOG Power */ -#define ES7210_MIC12_BIAS_REG41 0x41 -#define ES7210_MIC34_BIAS_REG42 0x42 -#define ES7210_MIC1_GAIN_REG43 0x43 -#define ES7210_MIC2_GAIN_REG44 0x44 -#define ES7210_MIC3_GAIN_REG45 0x45 -#define ES7210_MIC4_GAIN_REG46 0x46 -#define ES7210_MIC1_POWER_REG47 0x47 -#define ES7210_MIC2_POWER_REG48 0x48 -#define ES7210_MIC3_POWER_REG49 0x49 -#define ES7210_MIC4_POWER_REG4A 0x4A -#define ES7210_MIC12_POWER_REG4B 0x4B /* MICBias & ADC & PGA Power */ -#define ES7210_MIC34_POWER_REG4C 0x4C - -typedef enum { - ES7210_AD1_AD0_00 = 0x40, - ES7210_AD1_AD0_01 = 0x41, - ES7210_AD1_AD0_10 = 0x42, - ES7210_AD1_AD0_11 = 0x43, -} es7210_address_t; - -typedef enum { - ES7210_INPUT_MIC1 = 0x01, - ES7210_INPUT_MIC2 = 0x02, - ES7210_INPUT_MIC3 = 0x04, - ES7210_INPUT_MIC4 = 0x08 -} es7210_input_mics_t; - -typedef enum gain_value{ - GAIN_0DB = 0, - GAIN_3DB, - GAIN_6DB, - GAIN_9DB, - GAIN_12DB, - GAIN_15DB, - GAIN_18DB, - GAIN_21DB, - GAIN_24DB, - GAIN_27DB, - GAIN_30DB, - GAIN_33DB, - GAIN_34_5DB, - GAIN_36DB, - GAIN_37_5DB, -} es7210_gain_value_t; - -/* - * @brief Initialize ES7210 ADC chip - * - * @param[in] codec_cfg: configuration of ES7210 - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es7210_adc_init(audio_hal_codec_config_t *codec_cfg); - -/** - * @brief Deinitialize ES7210 ADC chip - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es7210_adc_deinit(); - -/** - * @brief Configure ES7210 ADC mode and I2S interface - * - * @param[in] mode: codec mode - * @param[in] iface: I2S config - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es7210_adc_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface); - -/** - * @brief Control ES7210 ADC chip - * - * @param[in] mode: codec mode - * @param[in] ctrl_state: start or stop progress - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es7210_adc_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state); - -/** - * @brief Set gain of given mask - * - * @param[in] mic_mask Mask of MIC channel - * - * @param[in] gain: gain - * - * gain : value - * GAIN_0DB : 1 - * GAIN_3DB : 2 - * GAIN_6DB : 3 - * · - * · - * · - * GAIN_30DB : 10 - * GAIN_33DB : 11 - * GAIN_34_5DB : 12 - * GAIN_36DB : 13 - * GAIN_37_5DB : 14 - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es7210_adc_set_gain(es7210_input_mics_t mic_mask, es7210_gain_value_t gain); - -/** - * @brief Set gain (Note: the enabled microphone sets the same gain) - * - * @param[in] gain: gain - * - * gain : value - * GAIN_0DB : 1 - * GAIN_3DB : 2 - * GAIN_6DB : 3 - * · - * · - * · - * GAIN_30DB : 10 - * GAIN_33DB : 11 - * GAIN_34_5DB : 12 - * GAIN_36DB : 13 - * GAIN_37_5DB : 14 - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es7210_adc_set_gain_all(es7210_gain_value_t gain); - -/** - * @brief Get MIC gain - * - * @param mic_mask Selected MIC - * @param gain Pointer to `es7210_gain_value_t` - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es7210_adc_get_gain(es7210_input_mics_t mic_mask, es7210_gain_value_t *gain); - -/** - * @brief Set volume - * - * @param[in] volume: volume - * - * @return - * - ESP_OK - */ -esp_err_t es7210_adc_set_volume(int volume); - -/** - * @brief Set ES7210 ADC mute status - * - * @return - * - ESP_FAIL - * - ESP_OK - */ -esp_err_t es7210_set_mute(uint8_t enable); - -/** - * @brief Select ES7210 mic - * - * @param[in] mic: mics - * - * @return - * - ESP_FAIL - * - ESP_OK - */ -esp_err_t es7210_mic_select(es7210_input_mics_t mic); - -/** - * @brief Read regs of ES7210 - * - * @param[in] reg_addr: reg_addr - * - * @return - * - ESP_FAIL - * - ESP_OK - */ -int es7210_read_reg(uint8_t reg_addr); - -/** - * @brief Read all regs of ES7210 - */ -void es7210_read_all(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _ES7210_H_ */ diff --git a/components/codec/es8311/es8311.cpp b/components/codec/es8311/es8311.cpp deleted file mode 100644 index 5470d7b0..00000000 --- a/components/codec/es8311/es8311.cpp +++ /dev/null @@ -1,682 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include "esp_log.h" -#include "es8311.hpp" - -static write_fn i2c_write_ = nullptr; -static read_register_fn i2c_read_register_ = nullptr; - -void set_es8311_write(write_fn fn) { - i2c_write_ = fn; -} -void set_es8311_read(read_register_fn fn) { - i2c_read_register_ = fn; -} - -#if !defined(BIT) -#define BIT(x) (1U << (x)) -#endif - -/* ES8311 address - * 0x32:CE=1;0x30:CE=0 - */ -#define ES8311_ADDR 0x18 - -/* - * to define the clock soure of MCLK - */ -#define FROM_MCLK_PIN 0 -#define FROM_SCLK_PIN 1 -#define ES8311_MCLK_SOURCE FROM_MCLK_PIN - -/* - * to define whether to reverse the clock - */ -#define INVERT_MCLK 0 // do not invert -#define INVERT_SCLK 0 - -#define IS_DMIC 0 // Is it a digital microphone - -#define MCLK_DIV_FRE 256 - -/* - * Clock coefficient structer - */ -struct _coeff_div { - uint32_t mclk; /* mclk frequency */ - uint32_t rate; /* sample rate */ - uint8_t pre_div; /* the pre divider with range from 1 to 8 */ - uint8_t pre_multi; /* the pre multiplier with x1, x2, x4 and x8 selection */ - uint8_t adc_div; /* adcclk divider */ - uint8_t dac_div; /* dacclk divider */ - uint8_t fs_mode; /* double speed or single speed, =0, ss, =1, ds */ - uint8_t lrck_h; /* adclrck divider and daclrck divider */ - uint8_t lrck_l; - uint8_t bclk_div; /* sclk divider */ - uint8_t adc_osr; /* adc osr */ - uint8_t dac_osr; /* dac osr */ -}; - -/* codec hifi mclk clock divider coefficients */ -static const struct _coeff_div coeff_div[] = { - //mclk rate pre_div mult adc_div dac_div fs_mode lrch lrcl bckdiv osr - /* 8k */ - {12288000, 8000 , 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 8000 , 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x10}, - {16384000, 8000 , 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 8000 , 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 8000 , 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 8000 , 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 8000 , 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1024000 , 8000 , 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 11.025k */ - {11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 12k */ - {12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 16k */ - {12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, - {16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1024000 , 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 22.05k */ - {11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 24k */ - {12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 32k */ - {12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, - {16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, - {1024000 , 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 44.1k */ - {11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 48k */ - {12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - - /* 64k */ - {12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {4096000 , 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {2048000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18}, - {1024000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, - - /* 88.2k */ - {11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, - - /* 96k */ - {12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, -}; - -static const char *TAG = "DRV8311"; - -#define ES_ASSERT(a, format, b, ...) \ - if ((a) != 0) { \ - ESP_LOGE(TAG, format, ##__VA_ARGS__); \ - return b;\ - } - -static esp_err_t es8311_write_reg(uint8_t reg_addr, uint8_t data) -{ - // return i2c_bus_write_byte(i2c_handle, reg_addr, data); - uint8_t write_buf[2] = {reg_addr, data}; - bool success = i2c_write_(ES8311_ADDR, write_buf, sizeof(write_buf)); - return success ? ESP_OK : ESP_FAIL; -} - -static int es8311_read_reg(uint8_t reg_addr) -{ - uint8_t data; - i2c_read_register_(ES8311_ADDR, reg_addr, &data, 1); - return (int)data; -} - -/* -* look for the coefficient in coeff_div[] table -*/ -static int get_coeff(uint32_t mclk, uint32_t rate) -{ - for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) { - if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) - return i; - } - return -1; -} - -/* -* set es8311 dac mute or not -* if mute = 0, dac un-mute -* if mute = 1, dac mute -*/ -static void es8311_mute(int mute) -{ - uint8_t regv; - regv = es8311_read_reg(ES8311_DAC_REG31) & 0x9f; - if (mute) { - es8311_write_reg(ES8311_SYSTEM_REG12, 0x02); - es8311_write_reg(ES8311_DAC_REG31, regv | 0x60); - es8311_write_reg(ES8311_DAC_REG32, 0x00); - es8311_write_reg(ES8311_DAC_REG37, 0x08); - } else { - es8311_write_reg(ES8311_DAC_REG31, regv); - es8311_write_reg(ES8311_SYSTEM_REG12, 0x00); - } -} - -/* -* set es8311 into suspend mode -*/ -static void es8311_suspend(void) -{ - ESP_LOGI(TAG, "Enter into es8311_suspend()"); - es8311_write_reg(ES8311_DAC_REG32, 0x00); - es8311_write_reg(ES8311_ADC_REG17, 0x00); - es8311_write_reg(ES8311_SYSTEM_REG0E, 0xFF); - es8311_write_reg(ES8311_SYSTEM_REG12, 0x02); - es8311_write_reg(ES8311_SYSTEM_REG14, 0x00); - es8311_write_reg(ES8311_SYSTEM_REG0D, 0xFA); - es8311_write_reg(ES8311_ADC_REG15, 0x00); - es8311_write_reg(ES8311_DAC_REG37, 0x08); - es8311_write_reg(ES8311_GP_REG45, 0x01); -} - -esp_err_t es8311_codec_init(audio_hal_codec_config_t *codec_cfg) -{ - uint8_t datmp, regv; - int coeff; - esp_err_t ret = ESP_OK; - - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x30); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG02, 0x00); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10); - ret |= es8311_write_reg(ES8311_ADC_REG16, 0x24); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00); - ret |= es8311_write_reg(ES8311_SYSTEM_REG0B, 0x00); - ret |= es8311_write_reg(ES8311_SYSTEM_REG0C, 0x00); - ret |= es8311_write_reg(ES8311_SYSTEM_REG10, 0x1F); - ret |= es8311_write_reg(ES8311_SYSTEM_REG11, 0x7F); - ret |= es8311_write_reg(ES8311_RESET_REG00, 0x80); - /* - * Set Codec into Master or Slave mode - */ - regv = es8311_read_reg(ES8311_RESET_REG00); - /* - * Set master/slave audio interface - */ - audio_hal_codec_i2s_iface_t *i2s_cfg = &(codec_cfg->i2s_iface); - switch (i2s_cfg->mode) { - case AUDIO_HAL_MODE_MASTER: /* MASTER MODE */ - ESP_LOGI(TAG, "ES8311 in Master mode"); - regv |= 0x40; - break; - case AUDIO_HAL_MODE_SLAVE: /* SLAVE MODE */ - ESP_LOGI(TAG, "ES8311 in Slave mode"); - regv &= 0xBF; - break; - default: - regv &= 0xBF; - } - ret |= es8311_write_reg(ES8311_RESET_REG00, regv); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x3F); - /* - * Select clock source for internal mclk - */ - - int es8311_mclk_src = ES8311_MCLK_SOURCE; - switch (es8311_mclk_src) { - case FROM_MCLK_PIN: - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG01); - regv &= 0x7F; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, regv); - break; - case FROM_SCLK_PIN: - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG01); - regv |= 0x80; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, regv); - break; - default: - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG01); - regv &= 0x7F; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, regv); - break; - } - int sample_fre = 0; - int mclk_fre = 0; - switch (i2s_cfg->samples) { - case AUDIO_HAL_08K_SAMPLES: - sample_fre = 8000; - break; - case AUDIO_HAL_11K_SAMPLES: - sample_fre = 11025; - break; - case AUDIO_HAL_16K_SAMPLES: - sample_fre = 16000; - break; - case AUDIO_HAL_22K_SAMPLES: - sample_fre = 22050; - break; - case AUDIO_HAL_24K_SAMPLES: - sample_fre = 24000; - break; - case AUDIO_HAL_32K_SAMPLES: - sample_fre = 32000; - break; - case AUDIO_HAL_44K_SAMPLES: - sample_fre = 44100; - break; - case AUDIO_HAL_48K_SAMPLES: - sample_fre = 48000; - break; - default: - ESP_LOGE(TAG, "Unable to configure sample rate %dHz", sample_fre); - break; - } - mclk_fre = sample_fre * MCLK_DIV_FRE; - coeff = get_coeff(mclk_fre, sample_fre); - if (coeff < 0) { - ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK", sample_fre, mclk_fre); - return ESP_FAIL; - } - /* - * Set clock parammeters - */ - if (coeff >= 0) { - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG02) & 0x07; - regv |= (coeff_div[coeff].pre_div - 1) << 5; - datmp = 0; - switch (coeff_div[coeff].pre_multi) { - case 1: - datmp = 0; - break; - case 2: - datmp = 1; - break; - case 4: - datmp = 2; - break; - case 8: - datmp = 3; - break; - default: - break; - } - - if (ES8311_MCLK_SOURCE == FROM_SCLK_PIN) { - datmp = 3; /* DIG_MCLK = LRCK * 256 = BCLK * 8 */ - } - regv |= (datmp) << 3; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG02, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG05) & 0x00; - regv |= (coeff_div[coeff].adc_div - 1) << 4; - regv |= (coeff_div[coeff].dac_div - 1) << 0; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG05, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG03) & 0x80; - regv |= coeff_div[coeff].fs_mode << 6; - regv |= coeff_div[coeff].adc_osr << 0; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG03, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG04) & 0x80; - regv |= coeff_div[coeff].dac_osr << 0; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG04, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG07) & 0xC0; - regv |= coeff_div[coeff].lrck_h << 0; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG07, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG08) & 0x00; - regv |= coeff_div[coeff].lrck_l << 0; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG08, regv); - - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG06) & 0xE0; - if (coeff_div[coeff].bclk_div < 19) { - regv |= (coeff_div[coeff].bclk_div - 1) << 0; - } else { - regv |= (coeff_div[coeff].bclk_div) << 0; - } - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG06, regv); - } - - /* - * mclk inverted or not - */ - if (INVERT_MCLK) { - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG01); - regv |= 0x40; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, regv); - } else { - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG01); - regv &= ~(0x40); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG01, regv); - } - /* - * sclk inverted or not - */ - if (INVERT_SCLK) { - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG06); - regv |= 0x20; - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG06, regv); - } else { - regv = es8311_read_reg(ES8311_CLK_MANAGER_REG06); - regv &= ~(0x20); - ret |= es8311_write_reg(ES8311_CLK_MANAGER_REG06, regv); - } - - ret |= es8311_write_reg(ES8311_SYSTEM_REG13, 0x10); - ret |= es8311_write_reg(ES8311_ADC_REG1B, 0x0A); - ret |= es8311_write_reg(ES8311_ADC_REG1C, 0x6A); - - return ESP_OK; -} - -esp_err_t es8311_codec_deinit() -{ - return ESP_OK; -} - -esp_err_t es8311_config_fmt(es_i2s_fmt_t fmt) -{ - esp_err_t ret = ESP_OK; - uint8_t adc_iface = 0, dac_iface = 0; - dac_iface = es8311_read_reg(ES8311_SDPIN_REG09); - adc_iface = es8311_read_reg(ES8311_SDPOUT_REG0A); - switch (fmt) { - case AUDIO_HAL_I2S_NORMAL: - ESP_LOGD(TAG, "ES8311 in I2S Format"); - dac_iface &= 0xFC; - adc_iface &= 0xFC; - break; - case AUDIO_HAL_I2S_LEFT: - case AUDIO_HAL_I2S_RIGHT: - ESP_LOGD(TAG, "ES8311 in LJ Format"); - adc_iface &= 0xFC; - dac_iface &= 0xFC; - adc_iface |= 0x01; - dac_iface |= 0x01; - break; - case AUDIO_HAL_I2S_DSP: - ESP_LOGD(TAG, "ES8311 in DSP-B Format"); - adc_iface &= 0xDC; - dac_iface &= 0xDC; - adc_iface |= 0x23; - dac_iface |= 0x23; - break; - default: - dac_iface &= 0xFC; - adc_iface &= 0xFC; - break; - } - ret |= es8311_write_reg(ES8311_SDPIN_REG09, dac_iface); - ret |= es8311_write_reg(ES8311_SDPOUT_REG0A, adc_iface); - - return ret; -} - -esp_err_t es8311_set_bits_per_sample(audio_hal_iface_bits_t bits) -{ - esp_err_t ret = ESP_OK; - uint8_t adc_iface = 0, dac_iface = 0; - dac_iface = es8311_read_reg(ES8311_SDPIN_REG09); - adc_iface = es8311_read_reg(ES8311_SDPOUT_REG0A); - switch (bits) { - case AUDIO_HAL_BIT_LENGTH_16BITS: - dac_iface |= 0x0c; - adc_iface |= 0x0c; - break; - case AUDIO_HAL_BIT_LENGTH_24BITS: - break; - case AUDIO_HAL_BIT_LENGTH_32BITS: - dac_iface |= 0x10; - adc_iface |= 0x10; - break; - default: - dac_iface |= 0x0c; - adc_iface |= 0x0c; - break; - - } - ret |= es8311_write_reg(ES8311_SDPIN_REG09, dac_iface); - ret |= es8311_write_reg(ES8311_SDPOUT_REG0A, adc_iface); - - return ret; -} - -esp_err_t es8311_codec_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface) -{ - int ret = ESP_OK; - ret |= es8311_set_bits_per_sample(iface->bits); - ret |= es8311_config_fmt((es_i2s_fmt_t)(iface->fmt)); - return ret; -} - -esp_err_t es8311_codec_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) -{ - esp_err_t ret = ESP_OK; - es_module_t es_mode = ES_MODULE_MIN; - - switch (mode) { - case AUDIO_HAL_CODEC_MODE_ENCODE: - es_mode = ES_MODULE_ADC; - break; - case AUDIO_HAL_CODEC_MODE_LINE_IN: - es_mode = ES_MODULE_LINE; - break; - case AUDIO_HAL_CODEC_MODE_DECODE: - es_mode = ES_MODULE_DAC; - break; - case AUDIO_HAL_CODEC_MODE_BOTH: - es_mode = ES_MODULE_ADC_DAC; - break; - default: - es_mode = ES_MODULE_DAC; - ESP_LOGW(TAG, "Codec mode not support, default is decode mode"); - break; - } - - if (ctrl_state == AUDIO_HAL_CTRL_START) { - ret |= es8311_start(es_mode); - } else { - ESP_LOGW(TAG, "The codec is about to stop"); - ret |= es8311_stop(es_mode); - } - - return ret; -} - -esp_err_t es8311_start(es_module_t mode) -{ - esp_err_t ret = ESP_OK; - uint8_t adc_iface = 0, dac_iface = 0; - - dac_iface = es8311_read_reg(ES8311_SDPIN_REG09) & 0xBF; - adc_iface = es8311_read_reg(ES8311_SDPOUT_REG0A) & 0xBF; - adc_iface |= BIT(6); - dac_iface |= BIT(6); - - if (mode == ES_MODULE_LINE) { - ESP_LOGE(TAG, "The codec es8311 doesn't support ES_MODULE_LINE mode"); - return ESP_FAIL; - } - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - adc_iface &= ~(BIT(6)); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - dac_iface &= ~(BIT(6)); - } - - ret |= es8311_write_reg(ES8311_SDPIN_REG09, dac_iface); - ret |= es8311_write_reg(ES8311_SDPOUT_REG0A, adc_iface); - - ret |= es8311_write_reg(ES8311_ADC_REG17, 0xBF); - ret |= es8311_write_reg(ES8311_SYSTEM_REG0E, 0x02); - ret |= es8311_write_reg(ES8311_SYSTEM_REG12, 0x00); - ret |= es8311_write_reg(ES8311_SYSTEM_REG14, 0x1A); - - /* - * pdm dmic enable or disable - */ - int regv = 0; - if (IS_DMIC) { - regv = es8311_read_reg(ES8311_SYSTEM_REG14); - regv |= 0x40; - ret |= es8311_write_reg(ES8311_SYSTEM_REG14, regv); - } else { - regv = es8311_read_reg(ES8311_SYSTEM_REG14); - regv &= ~(0x40); - ret |= es8311_write_reg(ES8311_SYSTEM_REG14, regv); - } - - ret |= es8311_write_reg(ES8311_SYSTEM_REG0D, 0x01); - ret |= es8311_write_reg(ES8311_ADC_REG15, 0x40); - ret |= es8311_write_reg(ES8311_DAC_REG37, 0x48); - ret |= es8311_write_reg(ES8311_GP_REG45, 0x00); - - return ret; -} - -esp_err_t es8311_stop(es_module_t mode) -{ - esp_err_t ret = ESP_OK; - es8311_suspend(); - return ret; -} - -esp_err_t es8311_codec_set_voice_volume(int volume) -{ - esp_err_t res = ESP_OK; - if (volume < 0) { - volume = 0; - } else if (volume > 100) { - volume = 100; - } - int vol = (volume) * 2550 / 1000; - ESP_LOGD(TAG, "SET: volume:%d", vol); - es8311_write_reg(ES8311_DAC_REG32, vol); - return res; -} - -esp_err_t es8311_codec_get_voice_volume(int *volume) -{ - esp_err_t res = ESP_OK; - int regv = 0; - regv = es8311_read_reg(ES8311_DAC_REG32); - if (regv == ESP_FAIL) { - *volume = 0; - res = ESP_FAIL; - } else { - *volume = regv * 100 / 256; - } - ESP_LOGD(TAG, "GET: res:%d, volume:%d", regv, *volume); - return res; -} - -esp_err_t es8311_set_voice_mute(bool enable) -{ - ESP_LOGD(TAG, "Es8311SetVoiceMute volume:%d", enable); - es8311_mute(enable); - return ESP_OK; -} - -esp_err_t es8311_get_voice_mute(int *mute) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - res = es8311_read_reg(ES8311_DAC_REG31); - if (res != ESP_FAIL) { - reg = (res & 0x20) >> 5; - } - *mute = reg; - return res; -} - -esp_err_t es8311_set_mic_gain(es8311_mic_gain_t gain_db) -{ - esp_err_t res = ESP_OK; - res = es8311_write_reg(ES8311_ADC_REG16, gain_db); // MIC gain scale - return res; -} - -void es8311_read_all() -{ - for (int i = 0; i < 0x4A; i++) { - uint8_t reg = es8311_read_reg(i); - printf("REG:%02x, %02x\n", reg, i); - } -} diff --git a/components/codec/es8311/es8311.hpp b/components/codec/es8311/es8311.hpp deleted file mode 100644 index 6b8043dc..00000000 --- a/components/codec/es8311/es8311.hpp +++ /dev/null @@ -1,281 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _ES8311_H -#define _ES8311_H - -#include - -typedef std::function write_fn; -typedef std::function read_register_fn; - -void set_es8311_write(write_fn fn); -void set_es8311_read(read_register_fn fn); - -#include "audio_hal.h" -#include "esp_types.h" -#include "esxxx_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * ES8311_REGISTER NAME_REG_REGISTER ADDRESS - */ -#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/ - -/* - * Clock Scheme Register definition - */ -#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */ -#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */ -#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */ -#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */ -#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */ -#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */ -#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */ -#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */ -/* - * SDP - */ -#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */ -#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */ -/* - * SYSTEM - */ -#define ES8311_SYSTEM_REG0B 0x0B /* system */ -#define ES8311_SYSTEM_REG0C 0x0C /* system */ -#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */ -#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */ -#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */ -#define ES8311_SYSTEM_REG10 0x10 /* system */ -#define ES8311_SYSTEM_REG11 0x11 /* system */ -#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */ -#define ES8311_SYSTEM_REG13 0x13 /* system */ -#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */ -/* - * ADC - */ -#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */ -#define ES8311_ADC_REG16 0x16 /* ADC */ -#define ES8311_ADC_REG17 0x17 /* ADC, volume */ -#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */ -#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */ -#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */ -#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */ -#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */ -/* - * DAC - */ -#define ES8311_DAC_REG31 0x31 /* DAC, mute */ -#define ES8311_DAC_REG32 0x32 /* DAC, volume */ -#define ES8311_DAC_REG33 0x33 /* DAC, offset */ -#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */ -#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */ -#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */ -/* - *GPIO - */ -#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */ -#define ES8311_GP_REG45 0x45 /* GP CONTROL */ -/* - * CHIP - */ -#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ -#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */ -#define ES8311_CHVER_REGFF 0xFF /* VERSION */ -#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ - -#define ES8311_MAX_REGISTER 0xFF - -typedef enum { - ES8311_MIC_GAIN_MIN = -1, - ES8311_MIC_GAIN_0DB, - ES8311_MIC_GAIN_6DB, - ES8311_MIC_GAIN_12DB, - ES8311_MIC_GAIN_18DB, - ES8311_MIC_GAIN_24DB, - ES8311_MIC_GAIN_30DB, - ES8311_MIC_GAIN_36DB, - ES8311_MIC_GAIN_42DB, - ES8311_MIC_GAIN_MAX -} es8311_mic_gain_t; - -/* - * @brief Initialize ES8311 codec chip - * - * @param codec_cfg configuration of ES8311 - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_codec_init(audio_hal_codec_config_t *codec_cfg); - -/** - * @brief Deinitialize ES8311 codec chip - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_codec_deinit(void); - -/** - * @brief Control ES8311 codec chip - * - * @param mode codec mode - * @param ctrl_state start or stop decode or encode progress - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8311_codec_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state); - -/** - * @brief Configure ES8311 codec mode and I2S interface - * - * @param mode codec mode - * @param iface I2S config - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8311_codec_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface); - -/** - * @brief Configure ES8311 DAC mute or not. Basically you can use this function to mute the output or unmute - * - * @param enable enable(1) or disable(0) - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8311_set_voice_mute(bool enable); - -/** - * @brief Set voice volume - * - * @param volume: voice volume (0~100) - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_codec_set_voice_volume(int volume); - -/** - * @brief Get voice volume - * - * @param[out] *volume: voice volume (0~100) - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_codec_get_voice_volume(int *volume); - -/** - * @brief Configure ES8311 I2S format - * - * @param mod: set ADC or DAC or both - * @param cfg: ES8388 I2S format - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_config_fmt(es_i2s_fmt_t fmt); - -/** - * @brief Configure ES8311 data sample bits - * - * @param mode: set ADC or DAC or both - * @param bit_per_sample: bit number of per sample - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_set_bits_per_sample(audio_hal_iface_bits_t bits); - -/** - * @brief Start ES8311 codec chip - * - * @param mode: set ADC or DAC or both - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_start(es_module_t mode); - -/** - * @brief Stop ES8311 codec chip - * - * @param mode: set ADC or DAC or both - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8311_stop(es_module_t mode); - -/** - * @brief Get ES8311 DAC mute status - * - * @return - * - ESP_FAIL - * - ESP_OK - */ -esp_err_t es8311_get_voice_mute(int *mute); - -/** - * @brief Set ES8311 mic gain - * - * @param gain db of mic gain - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8311_set_mic_gain(es8311_mic_gain_t gain_db); - -/** - * @brief Print all ES8311 registers - * - * @return - * - void - */ -void es8311_read_all(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/codec/es8388/es8388.c b/components/codec/es8388/es8388.c deleted file mode 100755 index faa60bbf..00000000 --- a/components/codec/es8388/es8388.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2018 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include "esp_log.h" -#include "es8388.h" -#include "driver/i2c.h" - -static const char *ES_TAG = "ES8388_DRIVER"; - -#define I2C_MASTER_NUM (I2C_NUM_0) -#define I2C_MASTER_TIMEOUT_MS (10) - -#define ES_ASSERT(a, format, b, ...) \ - if ((a) != 0) { \ - ESP_LOGE(ES_TAG, format, ##__VA_ARGS__); \ - return b;\ - } - -static esp_err_t es_write_reg(uint8_t slave_addr, uint8_t reg_add, uint8_t data) -{ - //return i2c_bus_write_byte(i2c_handle, reg_add, data); - uint8_t write_buf[2] = {reg_add, data}; - return i2c_master_write_to_device(I2C_MASTER_NUM, - slave_addr, - write_buf, - sizeof(write_buf), - I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); -} - -static esp_err_t es_read_reg(uint8_t reg_add, uint8_t *p_data) -{ - //return i2c_bus_read_byte(i2c_handle, reg_add, p_data); - return i2c_master_write_read_device(I2C_MASTER_NUM, - ES8388_ADDR, - ®_add, - 1, // size of addr - p_data, - 1, // amount of data to read - I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); -} - -void es8388_read_all() -{ - for (int i = 0; i < 50; i++) { - uint8_t reg = 0; - es_read_reg(i, ®); - printf("%x: %x\n", i, reg); - } -} - -esp_err_t es8388_write_reg(uint8_t reg_add, uint8_t data) -{ - return es_write_reg(ES8388_ADDR, reg_add, data); -} - -/** - * @brief Configure ES8388 ADC and DAC volume. Basicly you can consider this as ADC and DAC gain - * - * @param mode: set ADC or DAC or all - * @param volume: -96 ~ 0 for example Es8388SetAdcDacVolume(ES_MODULE_ADC, 30, 6); means set ADC volume -30.5db - * @param dot: whether include 0.5. for example Es8388SetAdcDacVolume(ES_MODULE_ADC, 30, 4); means set ADC volume -30db - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -static int es8388_set_adc_dac_volume(int mode, int volume, int dot) -{ - int res = 0; - if ( volume < -96 || volume > 0 ) { - ESP_LOGW(ES_TAG, "Warning: volume < -96! or > 0!\n"); - if (volume < -96) - volume = -96; - else - volume = 0; - } - dot = (dot >= 5 ? 1 : 0); - volume = (-volume << 1) + dot; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL8, volume); - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL9, volume); //ADC Right Volume=0db - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL5, volume); - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL4, volume); - } - return res; -} - - -/** - * @brief Power Management - * - * @param mod: if ES_POWER_CHIP, the whole chip including ADC and DAC is enabled - * @param enable: false to disable true to enable - * - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_start(es_module_t mode) -{ - esp_err_t res = ESP_OK; - uint8_t prev_data = 0, data = 0; - es_read_reg(ES8388_DACCONTROL21, &prev_data); - if (mode == ES_MODULE_LINE) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x09); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 by pass enable - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x50); // left DAC to left mixer enable and LIN signal to left mixer enable 0db : bupass enable - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x50); // right DAC to right mixer enable and LIN signal to right mixer enable 0db : bupass enable - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0xC0); //enable adc - } else { - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); //enable dac - } - es_read_reg(ES8388_DACCONTROL21, &data); - if (prev_data != data) { - res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0xF0); //start state machine - // res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x16); - // res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50); - res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00); //start state machine - } - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC || mode == ES_MODULE_LINE) { - res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x00); //power up adc and line in - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC || mode == ES_MODULE_LINE) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x3c); //power up dac and line out - res |= es8388_set_voice_mute(false); - ESP_LOGD(ES_TAG, "es8388_start default is mode:%d", mode); - } - - return res; -} - -/** - * @brief Power Management - * - * @param mod: if ES_POWER_CHIP, the whole chip including ADC and DAC is enabled - * @param enable: false to disable true to enable - * - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_stop(es_module_t mode) -{ - esp_err_t res = ESP_OK; - if (mode == ES_MODULE_LINE) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); //enable dac - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x00); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90); // only left DAC to left mixer enable 0db - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90); // only right DAC to right mixer enable 0db - return res; - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x00); - res |= es8388_set_voice_mute(true); //res |= Es8388SetAdcDacVolume(ES_MODULE_DAC, -96, 5); // 0db - //res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0xC0); //power down dac and line out - } - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - //res |= Es8388SetAdcDacVolume(ES_MODULE_ADC, -96, 5); // 0db - res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xFF); //power down adc and line in - } - if (mode == ES_MODULE_ADC_DAC) { - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x9C); //disable mclk -// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x00); -// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x58); -// res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0xF3); //stop state machine - } - - return res; -} - - -/** - * @brief Config I2s clock in MSATER mode - * - * @param cfg.sclkDiv: generate SCLK by dividing MCLK in MSATER mode - * @param cfg.lclkDiv: generate LCLK by dividing MCLK in MSATER mode - * - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_i2s_config_clock(es_i2s_clock_t cfg) -{ - esp_err_t res = ESP_OK; - res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg.sclk_div); - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, cfg.lclk_div); //ADCFsMode,singel SPEED,RATIO=256 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL2, cfg.lclk_div); //ADCFsMode,singel SPEED,RATIO=256 - return res; -} - -esp_err_t es8388_deinit(void) -{ - int res = 0; - res = es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0xFF); //reset and stop es8388 - // i2c_bus_delete(i2c_handle); - - return res; -} - -/** - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_init(audio_hal_codec_config_t *cfg) -{ - int res = 0; - - // bsp_i2c_add_device(&i2c_handle, ES8388_ADDR); - - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04); // 0x04 mute/0x00 unmute&ramp;DAC unmute and disabled digital volume control soft ramp - /* Chip Control and Power Management */ - res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50); - res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00); //normal all and power up all - res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg->i2s_iface.mode); //CODEC IN I2S SLAVE MODE - - /* dac */ - res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0xC0); //disable DAC and disable Lout/Rout/1/2 - res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x12); //Enfr=0,Play&Record Mode,(0x17-both of mic&paly) -// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0); //LPVrefBuf=0,Pdn_ana=0 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL1, 0x18);//1a 0x18:16bit iis , 0x00:24 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL2, 0x02); //DACFsMode,SINGLE SPEED; DACFsRatio,256 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x00); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90); // only left DAC to left mixer enable 0db - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90); // only right DAC to right mixer enable 0db - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); //set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00); //vroi=0 - res |= es8388_set_adc_dac_volume(ES_MODULE_DAC, 0, 0); // 0db - int tmp = 0; - if (AUDIO_HAL_DAC_OUTPUT_LINE2 == cfg->dac_output) { - tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_ROUT1; - } else if (AUDIO_HAL_DAC_OUTPUT_LINE1 == cfg->dac_output) { - tmp = DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT2; - } else { - tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2; - } - res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, tmp); //0x3c Enable DAC and Enable Lout/Rout/1/2 - /* adc */ - res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xFF); - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, 0xbb); // MIC Left and Right channel PGA gain - tmp = 0; - if (AUDIO_HAL_ADC_INPUT_LINE1 == cfg->adc_input) { - tmp = ADC_INPUT_LINPUT1_RINPUT1; - } else if (AUDIO_HAL_ADC_INPUT_LINE2 == cfg->adc_input) { - tmp = ADC_INPUT_LINPUT2_RINPUT2; - } else { - tmp = ADC_INPUT_DIFFERENCE; - } - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, tmp); //0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input; DSSEL,use one DS Reg11; DSR, LINPUT1-RINPUT1 - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL3, 0x02); - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, 0x0d); // Left/Right data, Left/Right justified mode, Bits length, I2S format - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, 0x02); //ADCFsMode,singel SPEED,RATIO=256 - //ALC for Microphone - res |= es8388_set_adc_dac_volume(ES_MODULE_ADC, 0, 0); // 0db - res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x09); //Power on ADC, Enable LIN&RIN, Power off MICBIAS, set int1lp to low power mode - - ESP_LOGI(ES_TAG, "init,out:%02x, in:%02x", cfg->dac_output, cfg->adc_input); - return res; -} - -/** - * @brief Configure ES8388 I2S format - * - * @param mode: set ADC or DAC or all - * @param bitPerSample: see Es8388I2sFmt - * - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_config_fmt(es_module_t mode, es_i2s_fmt_t fmt) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res = es_read_reg(ES8388_ADCCONTROL4, ®); - reg = reg & 0xfc; - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, reg | fmt); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res = es_read_reg(ES8388_DACCONTROL1, ®); - reg = reg & 0xf9; - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL1, reg | (fmt << 1)); - } - return res; -} - -/** - * @param volume: 0 ~ 100 - * - * @return - * - (-1) Error - * - (0) Success - */ -esp_err_t es8388_set_voice_volume(int volume) -{ - esp_err_t res = ESP_OK; - if (volume < 0) - volume = 0; - else if (volume > 100) - volume = 100; - volume /= 3; - res = es_write_reg(ES8388_ADDR, ES8388_DACCONTROL24, volume); - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL25, volume); - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0); - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0); - return res; -} - -/** - * - * @return - * volume - */ -esp_err_t es8388_get_voice_volume(int *volume) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - res = es_read_reg(ES8388_DACCONTROL24, ®); - if (res == ESP_FAIL) { - *volume = 0; - } else { - *volume = reg; - *volume *= 3; - if (*volume == 99) - *volume = 100; - } - return res; -} - -/** - * @brief Configure ES8388 data sample bits - * - * @param mode: set ADC or DAC or all - * @param bitPerSample: see BitsLength - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -esp_err_t es8388_set_bits_per_sample(es_module_t mode, es_bits_length_t bits_length) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - int bits = (int)bits_length; - - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res = es_read_reg(ES8388_ADCCONTROL4, ®); - reg = reg & 0xe3; - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, reg | (bits << 2)); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res = es_read_reg(ES8388_DACCONTROL1, ®); - reg = reg & 0xc7; - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL1, reg | (bits << 3)); - } - return res; -} - -/** - * @brief Configure ES8388 DAC mute or not. Basically you can use this function to mute the output or unmute - * - * @param enable: enable or disable - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -esp_err_t es8388_set_voice_mute(bool enable) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - res = es_read_reg(ES8388_DACCONTROL3, ®); - reg = reg & 0xFB; - res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL3, reg | (((int)enable) << 2)); - return res; -} - -esp_err_t es8388_get_voice_mute(void) -{ - esp_err_t res = ESP_OK; - uint8_t reg = 0; - res = es_read_reg(ES8388_DACCONTROL3, ®); - if (res == ESP_OK) { - reg = (reg & 0x04) >> 2; - } - return res == ESP_OK ? reg : res; -} - -/** - * @param gain: Config DAC Output - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -esp_err_t es8388_config_dac_output(es_dac_output_t output) -{ - esp_err_t res; - uint8_t reg = 0; - res = es_read_reg(ES8388_DACPOWER, ®); - reg = reg & 0xc3; - res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, reg | output); - return res; -} - -/** - * @param gain: Config ADC input - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -esp_err_t es8388_config_adc_input(es_adc_input_t input) -{ - esp_err_t res; - uint8_t reg = 0; - res = es_read_reg(ES8388_ADCCONTROL2, ®); - reg = reg & 0x0f; - res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, reg | input); - return res; -} - -/** - * @param gain: see es_mic_gain_t - * - * @return - * - (-1) Parameter error - * - (0) Success - */ -esp_err_t es8388_set_mic_gain(es_mic_gain_t gain) -{ - esp_err_t res, gain_n; - gain_n = (int)gain / 3; - gain_n = (gain_n << 4) + gain_n; - res = es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, gain_n); //MIC PGA - return res; -} - -int es8388_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) -{ - int res = 0; - int es_mode_t = 0; - switch (mode) { - case AUDIO_HAL_CODEC_MODE_ENCODE: - es_mode_t = ES_MODULE_ADC; - break; - case AUDIO_HAL_CODEC_MODE_LINE_IN: - es_mode_t = ES_MODULE_LINE; - break; - case AUDIO_HAL_CODEC_MODE_DECODE: - es_mode_t = ES_MODULE_DAC; - break; - case AUDIO_HAL_CODEC_MODE_BOTH: - es_mode_t = ES_MODULE_ADC_DAC; - break; - default: - es_mode_t = ES_MODULE_DAC; - ESP_LOGW(ES_TAG, "Codec mode not support, default is decode mode"); - break; - } - if (AUDIO_HAL_CTRL_STOP == ctrl_state) { - res = es8388_stop(es_mode_t); - } else { - res = es8388_start(es_mode_t); - ESP_LOGD(ES_TAG, "start default is decode mode:%d", es_mode_t); - } - return res; -} - -esp_err_t es8388_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface) -{ - esp_err_t res = ESP_OK; - int tmp = 0; - res |= es8388_config_fmt(ES_MODULE_ADC_DAC, iface->fmt); - if (iface->bits == AUDIO_HAL_BIT_LENGTH_16BITS) { - tmp = BIT_LENGTH_16BITS; - } else if (iface->bits == AUDIO_HAL_BIT_LENGTH_24BITS) { - tmp = BIT_LENGTH_24BITS; - } else { - tmp = BIT_LENGTH_32BITS; - } - res |= es8388_set_bits_per_sample(ES_MODULE_ADC_DAC, tmp); - return res; -} diff --git a/components/codec/es8388/es8388.h b/components/codec/es8388/es8388.h deleted file mode 100755 index 06d80829..00000000 --- a/components/codec/es8388/es8388.h +++ /dev/null @@ -1,303 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2018 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __ES8388_H__ -#define __ES8388_H__ - -#include "esp_types.h" -#include "esp_err.h" -#include "audio_hal.h" -#include "driver/i2c.h" -#include "esxxx_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* ES8388 address */ -#define ES8388_ADDR 0x20 /*!< 0x22:CE=1;0x20:CE=0*/ - -/* ES8388 register */ -#define ES8388_CONTROL1 0x00 -#define ES8388_CONTROL2 0x01 - -#define ES8388_CHIPPOWER 0x02 - -#define ES8388_ADCPOWER 0x03 -#define ES8388_DACPOWER 0x04 - -#define ES8388_CHIPLOPOW1 0x05 -#define ES8388_CHIPLOPOW2 0x06 - -#define ES8388_ANAVOLMANAG 0x07 - -#define ES8388_MASTERMODE 0x08 -/* ADC */ -#define ES8388_ADCCONTROL1 0x09 -#define ES8388_ADCCONTROL2 0x0a -#define ES8388_ADCCONTROL3 0x0b -#define ES8388_ADCCONTROL4 0x0c -#define ES8388_ADCCONTROL5 0x0d -#define ES8388_ADCCONTROL6 0x0e -#define ES8388_ADCCONTROL7 0x0f -#define ES8388_ADCCONTROL8 0x10 -#define ES8388_ADCCONTROL9 0x11 -#define ES8388_ADCCONTROL10 0x12 -#define ES8388_ADCCONTROL11 0x13 -#define ES8388_ADCCONTROL12 0x14 -#define ES8388_ADCCONTROL13 0x15 -#define ES8388_ADCCONTROL14 0x16 -/* DAC */ -#define ES8388_DACCONTROL1 0x17 -#define ES8388_DACCONTROL2 0x18 -#define ES8388_DACCONTROL3 0x19 -#define ES8388_DACCONTROL4 0x1a -#define ES8388_DACCONTROL5 0x1b -#define ES8388_DACCONTROL6 0x1c -#define ES8388_DACCONTROL7 0x1d -#define ES8388_DACCONTROL8 0x1e -#define ES8388_DACCONTROL9 0x1f -#define ES8388_DACCONTROL10 0x20 -#define ES8388_DACCONTROL11 0x21 -#define ES8388_DACCONTROL12 0x22 -#define ES8388_DACCONTROL13 0x23 -#define ES8388_DACCONTROL14 0x24 -#define ES8388_DACCONTROL15 0x25 -#define ES8388_DACCONTROL16 0x26 -#define ES8388_DACCONTROL17 0x27 -#define ES8388_DACCONTROL18 0x28 -#define ES8388_DACCONTROL19 0x29 -#define ES8388_DACCONTROL20 0x2a -#define ES8388_DACCONTROL21 0x2b -#define ES8388_DACCONTROL22 0x2c -#define ES8388_DACCONTROL23 0x2d -#define ES8388_DACCONTROL24 0x2e -#define ES8388_DACCONTROL25 0x2f -#define ES8388_DACCONTROL26 0x30 -#define ES8388_DACCONTROL27 0x31 -#define ES8388_DACCONTROL28 0x32 -#define ES8388_DACCONTROL29 0x33 -#define ES8388_DACCONTROL30 0x34 - -/** - * @brief Initialize ES8388 codec chip - * - * @param cfg configuration of ES8388 - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_init(audio_hal_codec_config_t *cfg); - -/** - * @brief Deinitialize ES8388 codec chip - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_deinit(void); - -/** - * @brief Configure ES8388 I2S format - * - * @param mod: set ADC or DAC or both - * @param cfg: ES8388 I2S format - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_config_fmt(es_module_t mod, es_i2s_fmt_t cfg); - -/** - * @brief Configure I2s clock in MSATER mode - * - * @param cfg: set bits clock and WS clock - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_i2s_config_clock(es_i2s_clock_t cfg); - -/** - * @brief Configure ES8388 data sample bits - * - * @param mode: set ADC or DAC or both - * @param bit_per_sample: bit number of per sample - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_set_bits_per_sample(es_module_t mode, es_bits_length_t bit_per_sample); - -/** - * @brief Start ES8388 codec chip - * - * @param mode: set ADC or DAC or both - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_start(es_module_t mode); - -/** - * @brief Stop ES8388 codec chip - * - * @param mode: set ADC or DAC or both - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_stop(es_module_t mode); - -/** - * @brief Set voice volume - * - * @param volume: voice volume (0~100) - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_set_voice_volume(int volume); - -/** - * @brief Get voice volume - * - * @param[out] *volume: voice volume (0~100) - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t es8388_get_voice_volume(int *volume); - -/** - * @brief Configure ES8388 DAC mute or not. Basically you can use this function to mute the output or unmute - * - * @param enable enable(1) or disable(0) - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_set_voice_mute(bool enable); - -/** - * @brief Get ES8388 DAC mute status - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_get_voice_mute(void); - -/** - * @brief Set ES8388 mic gain - * - * @param gain db of mic gain - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_set_mic_gain(es_mic_gain_t gain); - -/** - * @brief Set ES8388 adc input mode - * - * @param input adc input mode - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_config_adc_input(es_adc_input_t input); - -/** - * @brief Set ES8388 dac output mode - * - * @param output dac output mode - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_config_dac_output(es_dac_output_t output); - -/** - * @brief Write ES8388 register - * - * @param reg_add address of register - * @param data data of register - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_write_reg(uint8_t reg_add, uint8_t data); - -/** - * @brief Print all ES8388 registers - * - * @return - * - void - */ -void es8388_read_all(); - -/** - * @brief Configure ES8388 codec mode and I2S interface - * - * @param mode codec mode - * @param iface I2S config - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface); - -/** - * @brief Control ES8388 codec chip - * - * @param mode codec mode - * @param ctrl_state start or stop decode or encode progress - * - * @return - * - ESP_FAIL Parameter error - * - ESP_OK Success - */ -esp_err_t es8388_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state); - -#ifdef __cplusplus -} -#endif - -#endif //__ES8388_H__ diff --git a/components/codec/include/audio_hal.h b/components/codec/include/audio_hal.h deleted file mode 100755 index 16020efb..00000000 --- a/components/codec/include/audio_hal.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2018 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _AUDIO_HAL_H_ -#define _AUDIO_HAL_H_ - -#define AUDIO_HAL_VOL_DEFAULT 60 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Select media hal codec mode - */ -typedef enum { - AUDIO_HAL_CODEC_MODE_ENCODE = 1, /*!< select adc */ - AUDIO_HAL_CODEC_MODE_DECODE, /*!< select dac */ - AUDIO_HAL_CODEC_MODE_BOTH, /*!< select both adc and dac */ - AUDIO_HAL_CODEC_MODE_LINE_IN, /*!< set adc channel */ -} audio_hal_codec_mode_t; - -/** - * @brief Select adc channel for input mic signal - */ -typedef enum { - AUDIO_HAL_ADC_INPUT_LINE1 = 0x00, /*!< mic input to adc channel 1 */ - AUDIO_HAL_ADC_INPUT_LINE2, /*!< mic input to adc channel 2 */ - AUDIO_HAL_ADC_INPUT_ALL, /*!< mic input to both channels of adc */ - AUDIO_HAL_ADC_INPUT_DIFFERENCE, /*!< mic input to adc difference channel */ -} audio_hal_adc_input_t; - -/** - * @brief Select channel for dac output - */ -typedef enum { - AUDIO_HAL_DAC_OUTPUT_LINE1 = 0x00, /*!< dac output signal to channel 1 */ - AUDIO_HAL_DAC_OUTPUT_LINE2, /*!< dac output signal to channel 2 */ - AUDIO_HAL_DAC_OUTPUT_ALL, /*!< dac output signal to both channels */ -} audio_hal_dac_output_t; - -/** - * @brief Select operating mode i.e. start or stop for audio codec chip - */ -typedef enum { - AUDIO_HAL_CTRL_STOP = 0x00, /*!< set stop mode */ - AUDIO_HAL_CTRL_START = 0x01, /*!< set start mode */ -} audio_hal_ctrl_t; - -/** - * @brief Select I2S interface operating mode i.e. master or slave for audio codec chip - */ -typedef enum { - AUDIO_HAL_MODE_SLAVE = 0x00, /*!< set slave mode */ - AUDIO_HAL_MODE_MASTER = 0x01, /*!< set master mode */ -} audio_hal_iface_mode_t; - -/** - * @brief Select I2S interface samples per second - */ -typedef enum { - AUDIO_HAL_08K_SAMPLES, /*!< set to 8k samples per second */ - AUDIO_HAL_11K_SAMPLES, /*!< set to 11.025k samples per second */ - AUDIO_HAL_16K_SAMPLES, /*!< set to 16k samples in per second */ - AUDIO_HAL_22K_SAMPLES, /*!< set to 22.050k samples per second */ - AUDIO_HAL_24K_SAMPLES, /*!< set to 24k samples in per second */ - AUDIO_HAL_32K_SAMPLES, /*!< set to 32k samples in per second */ - AUDIO_HAL_44K_SAMPLES, /*!< set to 44.1k samples per second */ - AUDIO_HAL_48K_SAMPLES, /*!< set to 48k samples per second */ -} audio_hal_iface_samples_t; - -/** - * @brief Select I2S interface number of bits per sample - */ -typedef enum { - AUDIO_HAL_BIT_LENGTH_16BITS = 1, /*!< set 16 bits per sample */ - AUDIO_HAL_BIT_LENGTH_24BITS, /*!< set 24 bits per sample */ - AUDIO_HAL_BIT_LENGTH_32BITS, /*!< set 32 bits per sample */ -} audio_hal_iface_bits_t; - -/** - * @brief Select I2S interface format for audio codec chip - */ -typedef enum { - AUDIO_HAL_I2S_NORMAL = 0, /*!< set normal I2S format */ - AUDIO_HAL_I2S_LEFT, /*!< set all left format */ - AUDIO_HAL_I2S_RIGHT, /*!< set all right format */ - AUDIO_HAL_I2S_DSP, /*!< set dsp/pcm format */ -} audio_hal_iface_format_t; - -/** - * @brief I2s interface configuration for audio codec chip - */ -typedef struct { - audio_hal_iface_mode_t mode; /*!< audio codec chip mode */ - audio_hal_iface_format_t fmt; /*!< I2S interface format */ - audio_hal_iface_samples_t samples; /*!< I2S interface samples per second */ - audio_hal_iface_bits_t bits; /*!< i2s interface number of bits per sample */ -} audio_hal_codec_i2s_iface_t; - -/** - * @brief Configure media hal for initialization of audio codec chip - */ -typedef struct { - audio_hal_adc_input_t adc_input; /*!< set adc channel */ - audio_hal_dac_output_t dac_output; /*!< set dac channel */ - audio_hal_codec_mode_t codec_mode; /*!< select codec mode: adc, dac or both */ - audio_hal_codec_i2s_iface_t i2s_iface; /*!< set I2S interface configuration */ -} audio_hal_codec_config_t; - -#ifdef __cplusplus -} -#endif - -#endif //__AUDIO_HAL_H__ diff --git a/components/codec/include/esxxx_common.h b/components/codec/include/esxxx_common.h deleted file mode 100644 index bb650458..00000000 --- a/components/codec/include/esxxx_common.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _ESXXX_COMMON_H_ -#define _ESXXX_COMMON_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BIT_LENGTH_MIN = -1, - BIT_LENGTH_16BITS = 0x03, - BIT_LENGTH_18BITS = 0x02, - BIT_LENGTH_20BITS = 0x01, - BIT_LENGTH_24BITS = 0x00, - BIT_LENGTH_32BITS = 0x04, - BIT_LENGTH_MAX, -} es_bits_length_t; - -typedef enum { - MCLK_DIV_MIN = -1, - MCLK_DIV_1 = 1, - MCLK_DIV_2 = 2, - MCLK_DIV_3 = 3, - MCLK_DIV_4 = 4, - MCLK_DIV_6 = 5, - MCLK_DIV_8 = 6, - MCLK_DIV_9 = 7, - MCLK_DIV_11 = 8, - MCLK_DIV_12 = 9, - MCLK_DIV_16 = 10, - MCLK_DIV_18 = 11, - MCLK_DIV_22 = 12, - MCLK_DIV_24 = 13, - MCLK_DIV_33 = 14, - MCLK_DIV_36 = 15, - MCLK_DIV_44 = 16, - MCLK_DIV_48 = 17, - MCLK_DIV_66 = 18, - MCLK_DIV_72 = 19, - MCLK_DIV_5 = 20, - MCLK_DIV_10 = 21, - MCLK_DIV_15 = 22, - MCLK_DIV_17 = 23, - MCLK_DIV_20 = 24, - MCLK_DIV_25 = 25, - MCLK_DIV_30 = 26, - MCLK_DIV_32 = 27, - MCLK_DIV_34 = 28, - MCLK_DIV_7 = 29, - MCLK_DIV_13 = 30, - MCLK_DIV_14 = 31, - MCLK_DIV_MAX, -} es_sclk_div_t; - -typedef enum { - LCLK_DIV_MIN = -1, - LCLK_DIV_128 = 0, - LCLK_DIV_192 = 1, - LCLK_DIV_256 = 2, - LCLK_DIV_384 = 3, - LCLK_DIV_512 = 4, - LCLK_DIV_576 = 5, - LCLK_DIV_768 = 6, - LCLK_DIV_1024 = 7, - LCLK_DIV_1152 = 8, - LCLK_DIV_1408 = 9, - LCLK_DIV_1536 = 10, - LCLK_DIV_2112 = 11, - LCLK_DIV_2304 = 12, - - LCLK_DIV_125 = 16, - LCLK_DIV_136 = 17, - LCLK_DIV_250 = 18, - LCLK_DIV_272 = 19, - LCLK_DIV_375 = 20, - LCLK_DIV_500 = 21, - LCLK_DIV_544 = 22, - LCLK_DIV_750 = 23, - LCLK_DIV_1000 = 24, - LCLK_DIV_1088 = 25, - LCLK_DIV_1496 = 26, - LCLK_DIV_1500 = 27, - LCLK_DIV_MAX, -} es_lclk_div_t; - -typedef enum { - D2SE_PGA_GAIN_MIN = -1, - D2SE_PGA_GAIN_DIS = 0, - D2SE_PGA_GAIN_EN = 1, - D2SE_PGA_GAIN_MAX = 2, -} es_d2se_pga_t; - -typedef enum { - ADC_INPUT_MIN = -1, - ADC_INPUT_LINPUT1_RINPUT1 = 0x00, - ADC_INPUT_MIC1 = 0x05, - ADC_INPUT_MIC2 = 0x06, - ADC_INPUT_LINPUT2_RINPUT2 = 0x50, - ADC_INPUT_DIFFERENCE = 0xf0, - ADC_INPUT_MAX, -} es_adc_input_t; - -typedef enum { - DAC_OUTPUT_MIN = -1, - DAC_OUTPUT_LOUT1 = 0x04, - DAC_OUTPUT_LOUT2 = 0x08, - DAC_OUTPUT_SPK = 0x09, - DAC_OUTPUT_ROUT1 = 0x10, - DAC_OUTPUT_ROUT2 = 0x20, - DAC_OUTPUT_ALL = 0x3c, - DAC_OUTPUT_MAX, -} es_dac_output_t; - -typedef enum { - MIC_GAIN_MIN = -1, - MIC_GAIN_0DB = 0, - MIC_GAIN_3DB = 3, - MIC_GAIN_6DB = 6, - MIC_GAIN_9DB = 9, - MIC_GAIN_12DB = 12, - MIC_GAIN_15DB = 15, - MIC_GAIN_18DB = 18, - MIC_GAIN_21DB = 21, - MIC_GAIN_24DB = 24, - MIC_GAIN_MAX, -} es_mic_gain_t; - -typedef enum { - ES_MODULE_MIN = -1, - ES_MODULE_ADC = 0x01, - ES_MODULE_DAC = 0x02, - ES_MODULE_ADC_DAC = 0x03, - ES_MODULE_LINE = 0x04, - ES_MODULE_MAX -} es_module_t; - -typedef enum { - ES_MODE_MIN = -1, - ES_MODE_SLAVE = 0x00, - ES_MODE_MASTER = 0x01, - ES_MODE_MAX, -} es_mode_t; - -typedef enum { - ES_I2S_MIN = -1, - ES_I2S_NORMAL = 0, - ES_I2S_LEFT = 1, - ES_I2S_RIGHT = 2, - ES_I2S_DSP = 3, - ES_I2S_MAX -} es_i2s_fmt_t; - -/** - * @brief Configure ES8388 clock - */ -typedef struct { - es_sclk_div_t sclk_div; /*!< bits clock divide */ - es_lclk_div_t lclk_div; /*!< WS clock divide */ -} es_i2s_clock_t; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/espp b/components/espp index bfe9f281..0fe56d92 160000 --- a/components/espp +++ b/components/espp @@ -1 +1 @@ -Subproject commit bfe9f2815ca06b2df8e909dc21a2977d8c42025b +Subproject commit 0fe56d920dd94400724b70e08294b86e32b21709 diff --git a/components/events/CMakeLists.txt b/components/events/CMakeLists.txt new file mode 100644 index 00000000..71321e96 --- /dev/null +++ b/components/events/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + INCLUDE_DIRS "include" + REQUIRES "event_manager") diff --git a/components/box-emu-hal/include/hal_events.hpp b/components/events/include/events.hpp similarity index 91% rename from components/box-emu-hal/include/hal_events.hpp rename to components/events/include/events.hpp index ee8c691c..0d1bea0a 100644 --- a/components/box-emu-hal/include/hal_events.hpp +++ b/components/events/include/events.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "event_manager.hpp" static const std::string mute_button_topic = "mute"; diff --git a/components/gbc/CMakeLists.txt b/components/gbc/CMakeLists.txt index 38bca4ee..5266204c 100644 --- a/components/gbc/CMakeLists.txt +++ b/components/gbc/CMakeLists.txt @@ -2,7 +2,7 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" "gnuboy/src" PRIV_INCLUDE_DIRS "gnuboy/include" - REQUIRES box-emu-hal + REQUIRES "box-emu" "statistics" ) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-misleading-indentation -Wno-implicit-fallthrough -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers) diff --git a/components/gbc/src/gameboy.cpp b/components/gbc/src/gameboy.cpp index cb6d9885..4e31133e 100644 --- a/components/gbc/src/gameboy.cpp +++ b/components/gbc/src/gameboy.cpp @@ -4,7 +4,8 @@ #include -#include "box_emu_hal.hpp" +#include "box-emu.hpp" +#include "statistics.hpp" static const size_t GAMEBOY_SCREEN_WIDTH = 160; static const size_t GAMEBOY_SCREEN_HEIGHT = 144; @@ -56,7 +57,7 @@ void run_to_vblank() { /* VBLANK BEGIN */ if ((frame % 2) == 0) { - hal::push_frame(framebuffer); + BoxEmu::get().push_frame(framebuffer); // swap buffers currentBuffer = currentBuffer ? 0 : 1; @@ -71,7 +72,7 @@ void run_to_vblank() { if (pcm.pos > 100) { auto audio_sample_count = pcm.pos; auto audio_buffer = (uint8_t*)pcm.buf; - hal::play_audio(audio_buffer, audio_sample_count * sizeof(int16_t)); + espp::EspBox::get().play_audio(audio_buffer, audio_sample_count * sizeof(int16_t)); pcm.pos = 0; } @@ -115,11 +116,11 @@ void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_ } // set native size - hal::set_native_size(GAMEBOY_SCREEN_WIDTH, GAMEBOY_SCREEN_HEIGHT); - hal::set_palette(nullptr); + BoxEmu::get().native_size(GAMEBOY_SCREEN_WIDTH, GAMEBOY_SCREEN_HEIGHT); + BoxEmu::get().palette(nullptr); - displayBuffer[0] = (uint16_t*)hal::get_frame_buffer0(); - displayBuffer[1] = (uint16_t*)hal::get_frame_buffer1(); + displayBuffer[0] = (uint16_t*)espp::EspBox::get().frame_buffer0(); + displayBuffer[1] = (uint16_t*)espp::EspBox::get().frame_buffer1(); memset(&fb, 0, sizeof(fb)); fb.w = GAMEBOY_SCREEN_WIDTH; @@ -132,7 +133,7 @@ void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_ fb.dirty = 0; framebuffer = displayBuffer[0]; - hal::set_audio_sample_rate(GAMEBOY_AUDIO_SAMPLE_RATE); + espp::EspBox::get().audio_sample_rate(GAMEBOY_AUDIO_SAMPLE_RATE); // save the audio buffer auto buf = pcm.buf; auto len = pcm.len; @@ -157,8 +158,7 @@ void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_ void run_gameboy_rom() { auto start = esp_timer_get_time(); // GET INPUT - InputState state; - hal::get_input_state(&state); + auto state = BoxEmu::get().gamepad_state(); pad_set(PAD_UP, state.up); pad_set(PAD_DOWN, state.down); pad_set(PAD_LEFT, state.left); @@ -206,7 +206,7 @@ void save_gameboy(std::string_view save_path) { } std::vector get_gameboy_video_buffer() { - const uint8_t* frame_buffer = hal::get_frame_buffer0(); + const uint8_t* frame_buffer = espp::EspBox::get().frame_buffer0(); // copy the frame buffer to a new buffer auto width = GAMEBOY_SCREEN_WIDTH; auto height = GAMEBOY_SCREEN_HEIGHT; @@ -220,5 +220,5 @@ std::vector get_gameboy_video_buffer() { void deinit_gameboy() { // now unload everything loader_unload(); - hal::set_audio_sample_rate(48000); + espp::EspBox::get().audio_sample_rate(48000); } diff --git a/components/genesis/CMakeLists.txt b/components/genesis/CMakeLists.txt index 19c59115..229d7d57 100644 --- a/components/genesis/CMakeLists.txt +++ b/components/genesis/CMakeLists.txt @@ -2,7 +2,7 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" "gwenesis/src/bus" "gwenesis/src/cpus/M68K" "gwenesis/src/cpus/Z80" "gwenesis/src/io" "gwenesis/src/savestate" "gwenesis/src/sound" "gwenesis/src/vdp" PRIV_INCLUDE_DIRS "." "gwenesis/src/bus" "gwenesis/src/cpus/M68K" "gwenesis/src/cpus/Z80" "gwenesis/src/io" "gwenesis/src/savestate" "gwenesis/src/sound" "gwenesis/src/vdp" - REQUIRES box-emu-hal + REQUIRES box-emu statistics ) # target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-char-subscripts -Wno-attributes -Wno-implicit-fallthrough -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable -Wno-unused-value -O3) diff --git a/components/genesis/src/genesis.cpp b/components/genesis/src/genesis.cpp index 34d59556..cfcf1027 100644 --- a/components/genesis/src/genesis.cpp +++ b/components/genesis/src/genesis.cpp @@ -16,7 +16,8 @@ extern "C" { #include -#include "box_emu_hal.hpp" +#include "box-emu.hpp" +#include "statistics.hpp" static constexpr int AUDIO_BUFFER_LENGTH = std::max(GWENESIS_AUDIO_BUFFER_LENGTH_NTSC, GWENESIS_AUDIO_BUFFER_LENGTH_PAL); @@ -162,11 +163,11 @@ static void init(uint8_t *romdata, size_t rom_data_size) { frame_counter = 0; muteFrameCount = 0; - hal::set_audio_sample_rate(REG1_PAL ? GWENESIS_AUDIO_FREQ_PAL/2 : GWENESIS_AUDIO_FREQ_NTSC/2); + espp::EspBox::get().audio_sample_rate(REG1_PAL ? GWENESIS_AUDIO_FREQ_PAL/2 : GWENESIS_AUDIO_FREQ_NTSC/2); frame_buffer = frame_buffer_index - ? hal::get_frame_buffer1() - : hal::get_frame_buffer0(); + ? espp::EspBox::get().frame_buffer1() + : espp::EspBox::get().frame_buffer0(); gwenesis_vdp_set_buffer(frame_buffer); initialized = true; @@ -174,16 +175,15 @@ static void init(uint8_t *romdata, size_t rom_data_size) { } void init_genesis(uint8_t *romdata, size_t rom_data_size) { - hal::set_native_size(GENESIS_SCREEN_WIDTH, GENESIS_VISIBLE_HEIGHT, GENESIS_SCREEN_WIDTH); + BoxEmu::get().native_size(GENESIS_SCREEN_WIDTH, GENESIS_VISIBLE_HEIGHT, GENESIS_SCREEN_WIDTH); init(romdata, rom_data_size); } void IRAM_ATTR run_genesis_rom() { auto start = esp_timer_get_time(); // handle input here (see system.h and use input.pad and input.system) - static InputState previous_state = {}; - InputState state = {}; - hal::get_input_state(&state); + static GamepadState previous_state = {}; + auto state = BoxEmu::get().gamepad_state(); // set frameskip to be 3 if muted, 60 otherwise frameskip = 3; // hal::is_muted() ? 3 : 60; @@ -224,7 +224,7 @@ void IRAM_ATTR run_genesis_rom() { gwenesis_vdp_render_config(); - bool sound_enabled = !hal::is_muted(); + bool sound_enabled = !espp::EspBox::get().is_muted(); /* Reset the difference clocks and audio index */ system_clock = 0; @@ -311,21 +311,21 @@ void IRAM_ATTR run_genesis_rom() { // copy the palette memcpy(palette, CRAM565, PALETTE_SIZE * sizeof(uint16_t)); // set the palette - hal::set_palette(palette, PALETTE_SIZE); + BoxEmu::get().palette(palette, PALETTE_SIZE); // push the frame buffer to the display task - hal::push_frame(frame_buffer); + BoxEmu::get().push_frame(frame_buffer); // ping pong the frame buffer frame_buffer_index = !frame_buffer_index; frame_buffer = frame_buffer_index - ? hal::get_frame_buffer1() - : hal::get_frame_buffer0(); + ? espp::EspBox::get().frame_buffer1() + : espp::EspBox::get().frame_buffer0(); gwenesis_vdp_set_buffer(frame_buffer); } if (sound_enabled) { // push the audio buffer to the audio task int audio_len = REG1_PAL ? GWENESIS_AUDIO_BUFFER_LENGTH_PAL : GWENESIS_AUDIO_BUFFER_LENGTH_NTSC; - hal::play_audio((uint8_t*)gwenesis_ym2612_buffer, audio_len); + espp::EspBox::get().play_audio((uint8_t*)gwenesis_ym2612_buffer, audio_len); } // manage statistics @@ -370,5 +370,5 @@ std::vector get_genesis_video_buffer() { } void deinit_genesis() { - hal::set_audio_sample_rate(48000); + espp::EspBox::get().audio_sample_rate(48000); } diff --git a/components/gui/CMakeLists.txt b/components/gui/CMakeLists.txt index d1390720..b309fd79 100644 --- a/components/gui/CMakeLists.txt +++ b/components/gui/CMakeLists.txt @@ -2,4 +2,4 @@ idf_component_register( SRC_DIRS "src" "generated" "generated/screens" "generated/components" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "generated" - REQUIRES lvgl task display logger jpeg rom_info box-emu-hal) + REQUIRES lvgl task display logger jpeg rom_info box-emu) diff --git a/components/gui/include/gui.hpp b/components/gui/include/gui.hpp index a46f2a86..f68a9e5c 100644 --- a/components/gui/include/gui.hpp +++ b/components/gui/include/gui.hpp @@ -11,7 +11,7 @@ #include "task.hpp" #include "logger.hpp" -#include "box_emu_hal.hpp" +#include "box-emu.hpp" #include "rom_info.hpp" class Gui { @@ -80,7 +80,7 @@ class Gui { void set_mute(bool muted); void toggle_mute() { - set_mute(!hal::is_muted()); + set_mute(!espp::EspBox::get().is_muted()); } void set_audio_level(int new_audio_level); @@ -147,10 +147,11 @@ class Gui { void toggle_usb(); void update_shared_state() { - set_mute(hal::is_muted()); - set_audio_level(hal::get_audio_volume()); - set_brightness(hal::get_display_brightness() * 100.0f); - set_video_setting(hal::get_video_setting()); + auto &box = espp::EspBox::get(); + set_mute(box.is_muted()); + set_audio_level(box.volume()); + set_brightness(box.brightness()); + set_video_setting(BoxEmu::get().video_setting()); } VideoSetting get_video_setting(); @@ -158,7 +159,7 @@ class Gui { void on_rom_focused(lv_obj_t *new_focus); void on_mute_button_pressed(const std::vector& data) { - set_mute(hal::is_muted()); + set_mute(espp::EspBox::get().is_muted()); } void on_battery(const std::vector& data); diff --git a/components/gui/src/gui.cpp b/components/gui/src/gui.cpp index dc2ac1a7..ef2de6a2 100644 --- a/components/gui/src/gui.cpp +++ b/components/gui/src/gui.cpp @@ -7,7 +7,7 @@ extern "C" { } void Gui::set_mute(bool muted) { - hal::set_muted(muted); + espp::EspBox::get().mute(muted); if (muted) { lv_obj_add_state(ui_mutebutton, LV_STATE_CHECKED); } else { @@ -18,17 +18,17 @@ void Gui::set_mute(bool muted) { void Gui::set_audio_level(int new_audio_level) { new_audio_level = std::clamp(new_audio_level, 0, 100); lv_bar_set_value(ui_volumebar, new_audio_level, LV_ANIM_ON); - hal::set_audio_volume(new_audio_level); + espp::EspBox::get().volume(new_audio_level); } void Gui::set_brightness(int new_brightness) { new_brightness = std::clamp(new_brightness, 10, 100); lv_bar_set_value(ui_brightnessbar, new_brightness, LV_ANIM_ON); - hal::set_display_brightness((float)new_brightness / 100.0f); + espp::EspBox::get().brightness((float)new_brightness); } void Gui::set_video_setting(VideoSetting setting) { - hal::set_video_setting(setting); + BoxEmu::get().video_setting(setting); lv_dropdown_set_selected(ui_videosettingdropdown, (int)setting); } @@ -51,7 +51,7 @@ void Gui::clear_rom_list() { void Gui::update_rom_list() { // only do this if the metadata has changed since the last time we updated. We // do this by checking the last modified time of the metadata file. - std::filesystem::path metadata_path(std::string(MOUNT_POINT) + "/" + metadata_filename_); + std::filesystem::path metadata_path(std::string(BoxEmu::mount_point) + "/" + metadata_filename_); std::error_code ec; auto metadata_last_modified = std::filesystem::last_write_time(metadata_path, ec); if (ec) { @@ -169,7 +169,7 @@ void Gui::init_ui() { settings_screen_group_ = lv_group_create(); // get the KEYPAD indev - auto keypad = get_keypad_input_device(); + auto keypad = BoxEmu::get().keypad()->get_input_device(); if (keypad) lv_indev_set_group(keypad, rom_screen_group_); @@ -188,7 +188,7 @@ void Gui::init_ui() { lv_obj_set_flex_flow(ui_rompanel, LV_FLEX_FLOW_COLUMN); lv_obj_set_scroll_snap_y(ui_rompanel, LV_SCROLL_SNAP_CENTER); - lv_bar_set_value(ui_volumebar, hal::get_audio_volume(), LV_ANIM_OFF); + lv_bar_set_value(ui_volumebar, espp::EspBox::get().volume(), LV_ANIM_OFF); // rom screen navigation lv_obj_add_event_cb(ui_settingsbutton, &Gui::event_callback, LV_EVENT_PRESSED, static_cast(this)); @@ -306,12 +306,12 @@ void Gui::on_pressed(lv_event_t *e) { // volume controls bool is_volume_up_button = (target == ui_volumeupbutton); if (is_volume_up_button) { - set_audio_level(hal::get_audio_volume() + 10); + set_audio_level(espp::EspBox::get().volume() + 10); return; } bool is_volume_down_button = (target == ui_volumedownbutton); if (is_volume_down_button) { - set_audio_level(hal::get_audio_volume() - 10); + set_audio_level(espp::EspBox::get().volume() - 10); return; } bool is_mute_button = (target == ui_mutebutton); @@ -322,13 +322,13 @@ void Gui::on_pressed(lv_event_t *e) { // brightness controlsn bool is_brightness_up_button = (target == ui_brightnessupbutton); if (is_brightness_up_button) { - int brightness = hal::get_display_brightness() * 100.0f; + int brightness = espp::EspBox::get().brightness(); set_brightness(brightness + 10); return; } bool is_brightness_down_button = (target == ui_brightnessdownbutton); if (is_brightness_down_button) { - int brightness = hal::get_display_brightness() * 100.0f; + int brightness = espp::EspBox::get().brightness(); set_brightness(brightness - 10); return; } @@ -375,7 +375,7 @@ void Gui::on_pressed(lv_event_t *e) { void Gui::on_volume(const std::vector& data) { // the volume was changed, update our display of the volume - lv_bar_set_value(ui_volumebar, hal::get_audio_volume(), LV_ANIM_ON); + lv_bar_set_value(ui_volumebar, espp::EspBox::get().volume(), LV_ANIM_ON); } void Gui::on_battery(const std::vector& data) { @@ -417,14 +417,15 @@ void Gui::on_battery(const std::vector& data) { void Gui::toggle_usb() { fmt::print("Toggling USB\n"); + auto &emu = BoxEmu::get(); // toggle the usb - if (usb_is_enabled()) { - usb_deinit(); + if (emu.is_usb_enabled()) { + emu.deinitialize_usb(); } else { - usb_init(); + emu.initialize_usb(); } // update the label - if (usb_is_enabled()) { + if (emu.is_usb_enabled()) { lv_label_set_text(ui_usb_label, "Enabled"); } else { lv_label_set_text(ui_usb_label, "Disabled"); @@ -445,7 +446,7 @@ void Gui::focus_rommenu() { // focus the rom screen group logger_.debug("Focusing rom screen group"); lv_group_focus_freeze(rom_screen_group_, false); - auto keypad = get_keypad_input_device(); + auto keypad = BoxEmu::get().keypad()->get_input_device(); if (keypad) lv_indev_set_group(keypad, rom_screen_group_); } @@ -456,7 +457,7 @@ void Gui::focus_settings() { logger_.debug("Focusing settings screen group"); lv_group_focus_freeze(settings_screen_group_, false); // NOTE: we don't set editing here since we use it to manage the dropdown - auto keypad = get_keypad_input_device(); + auto keypad = BoxEmu::get().keypad()->get_input_device(); if (keypad) lv_indev_set_group(keypad, settings_screen_group_); } diff --git a/components/menu/CMakeLists.txt b/components/menu/CMakeLists.txt index 0641fa75..49418c5a 100644 --- a/components/menu/CMakeLists.txt +++ b/components/menu/CMakeLists.txt @@ -2,4 +2,4 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" "generated" "generated/screens" "generated/components" PRIV_INCLUDE_DIRS "generated" - REQUIRES lvgl timer display logger jpeg box-emu-hal) + REQUIRES lvgl timer display logger jpeg box-emu statistics) diff --git a/components/menu/include/menu.hpp b/components/menu/include/menu.hpp index 79cb9341..f54a4624 100644 --- a/components/menu/include/menu.hpp +++ b/components/menu/include/menu.hpp @@ -9,7 +9,8 @@ #include "high_resolution_timer.hpp" #include "logger.hpp" -#include "box_emu_hal.hpp" +#include "box-emu.hpp" +#include "statistics.hpp" class Menu { public: @@ -90,7 +91,7 @@ class Menu { void set_mute(bool muted); void toggle_mute() { - set_mute(!hal::is_muted()); + set_mute(!espp::EspBox::get().is_muted()); } void set_audio_level(int new_audio_level); @@ -123,16 +124,17 @@ class Menu { void update_fps_label(float fps); void update_shared_state() { - set_mute(hal::is_muted()); - set_audio_level(hal::get_audio_volume()); - set_brightness(hal::get_display_brightness() * 100.0f); - set_video_setting(hal::get_video_setting()); + auto &box = espp::EspBox::get(); + set_mute(box.is_muted()); + set_audio_level(box.volume()); + set_brightness(box.brightness()); + set_video_setting(BoxEmu::get().video_setting()); } VideoSetting get_video_setting(); void on_mute_button_pressed(const std::vector& data) { - set_mute(hal::is_muted()); + set_mute(espp::EspBox::get().is_muted()); } void update() { diff --git a/components/menu/src/menu.cpp b/components/menu/src/menu.cpp index 518897c7..44d42e3d 100644 --- a/components/menu/src/menu.cpp +++ b/components/menu/src/menu.cpp @@ -15,7 +15,7 @@ void Menu::init_ui() { lv_group_set_default(group_); // get the KEYPAD indev - auto keypad = get_keypad_input_device(); + auto keypad = BoxEmu::get().keypad()->get_input_device(); if (keypad) lv_indev_set_group(keypad, group_); @@ -218,7 +218,7 @@ void Menu::update_fps_label(float fps) { } void Menu::set_mute(bool muted) { - hal::set_muted(muted); + espp::EspBox::get().mute(muted); if (muted) { lv_obj_add_state(ui_volume_mute_btn, LV_STATE_CHECKED); } else { @@ -229,17 +229,17 @@ void Menu::set_mute(bool muted) { void Menu::set_audio_level(int new_audio_level) { new_audio_level = std::clamp(new_audio_level, 0, 100); lv_bar_set_value(ui_Bar2, new_audio_level, LV_ANIM_ON); - hal::set_audio_volume(new_audio_level); + espp::EspBox::get().volume(new_audio_level); } void Menu::set_brightness(int new_brightness) { new_brightness = std::clamp(new_brightness, 10, 100); lv_bar_set_value(ui_brightness_bar, new_brightness, LV_ANIM_ON); - hal::set_display_brightness((float)new_brightness / 100.0f); + espp::EspBox::get().brightness((float)new_brightness); } void Menu::set_video_setting(VideoSetting setting) { - hal::set_video_setting(setting); + BoxEmu::get().video_setting(setting); lv_dropdown_set_selected(ui_Dropdown2, (int)setting); } @@ -307,12 +307,12 @@ void Menu::on_pressed(lv_event_t *e) { // volume controls bool is_volume_up_button = (target == ui_volume_inc_btn); if (is_volume_up_button) { - set_audio_level(hal::get_audio_volume() + 10); + set_audio_level(espp::EspBox::get().volume() + 10); return; } bool is_volume_down_button = (target == ui_volume_dec_btn); if (is_volume_down_button) { - set_audio_level(hal::get_audio_volume() - 10); + set_audio_level(espp::EspBox::get().volume() - 10); return; } bool is_mute_button = (target == ui_volume_mute_btn); @@ -323,19 +323,19 @@ void Menu::on_pressed(lv_event_t *e) { // brightness controls bool is_brightness_up_button = (target == ui_brightness_inc_btn); if (is_brightness_up_button) { - set_brightness(hal::get_display_brightness() * 100.0f + 10); + set_brightness(espp::EspBox::get().brightness() + 10); return; } bool is_brightness_down_button = (target == ui_brightness_dec_btn); if (is_brightness_down_button) { - set_brightness(hal::get_display_brightness() * 100.0f - 10); + set_brightness(espp::EspBox::get().brightness() - 10); return; } } void Menu::on_volume(const std::vector& data) { // the volume was changed, update our display of the volume - lv_bar_set_value(ui_Bar2, hal::get_audio_volume(), LV_ANIM_ON); + lv_bar_set_value(ui_Bar2, espp::EspBox::get().volume(), LV_ANIM_ON); } void Menu::on_battery(const std::vector& data) { diff --git a/components/nes/CMakeLists.txt b/components/nes/CMakeLists.txt index d1125ccc..aebdd686 100644 --- a/components/nes/CMakeLists.txt +++ b/components/nes/CMakeLists.txt @@ -2,6 +2,6 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" "nofrendo/cpu" "nofrendo/libsnss" "nofrendo/nes" "nofrendo/sndhrdw" "nofrendo/mappers" "nofrendo" PRIV_INCLUDE_DIRS "nofrendo/cpu" "nofrendo/libsnss" "nofrendo/nes" "nofrendo/sndhrdw" "nofrendo" - REQUIRES box-emu-hal + REQUIRES "box-emu" "statistics" ) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-char-subscripts -Wno-attributes -Wno-implicit-fallthrough -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers) diff --git a/components/nes/src/nes.cpp b/components/nes/src/nes.cpp index 4f9779ae..128bf77d 100644 --- a/components/nes/src/nes.cpp +++ b/components/nes/src/nes.cpp @@ -10,7 +10,8 @@ static nes_t* console_nes; #include -#include "box_emu_hal.hpp" +#include "box-emu.hpp" +#include "statistics.hpp" void reset_nes() { nes_reset(SOFT_RESET); @@ -38,10 +39,10 @@ void init_nes(const std::string& rom_filename, uint8_t *romdata, size_t rom_data unlock = false; // set native size - hal::set_native_size(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); - hal::set_palette(get_nes_palette()); + BoxEmu::get().native_size(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); + BoxEmu::get().palette(get_nes_palette()); - hal::set_audio_sample_rate(44100 / 2); + espp::EspBox::get().audio_sample_rate(44100 / 2); nes_insertcart(rom_filename.c_str(), console_nes); vid_setmode(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); @@ -64,8 +65,7 @@ void run_nes_rom() { auto end = esp_timer_get_time(); // update unlock based on x button - InputState state; - hal::get_input_state(&state); + auto state = BoxEmu::get().gamepad_state(); static bool last_x = false; if (state.x && !last_x) { unlock = !unlock; @@ -94,7 +94,7 @@ std::vector get_nes_video_buffer() { std::vector frame(NES_SCREEN_WIDTH * NES_VISIBLE_HEIGHT * 2); // the frame data for the NES is stored in frame_buffer0 as a 8 bit index into the palette // we need to convert this to a 16 bit RGB565 value - const uint8_t *frame_buffer0 = hal::get_frame_buffer0(); + const uint8_t *frame_buffer0 = espp::EspBox::get().frame_buffer0(); const uint16_t *palette = get_nes_palette(); for (int i = 0; i < NES_SCREEN_WIDTH * NES_VISIBLE_HEIGHT; i++) { uint8_t index = frame_buffer0[i]; @@ -107,5 +107,5 @@ std::vector get_nes_video_buffer() { void deinit_nes() { nes_poweroff(); - hal::set_audio_sample_rate(48000); + espp::EspBox::get().audio_sample_rate(48000); } diff --git a/components/nes/src/video_audio.cpp b/components/nes/src/video_audio.cpp index 9ce0aea0..26d77983 100644 --- a/components/nes/src/video_audio.cpp +++ b/components/nes/src/video_audio.cpp @@ -22,8 +22,7 @@ extern "C" { #include } -// from box-emu-hal -#include "box_emu_hal.hpp" +#include "box-emu.hpp" #define DEFAULT_WIDTH 256 #define DEFAULT_HEIGHT NES_VISIBLE_HEIGHT @@ -42,11 +41,11 @@ static void (*audio_callback)(void *buffer, int length) = NULL; extern "C" void do_audio_frame() { if (audio_callback == NULL) return; static int num_channels = 2; - static int num_samples = hal::get_audio_sample_rate() * num_channels / NES_REFRESH_RATE; + static int num_samples = espp::EspBox::get().audio_sample_rate() * num_channels / NES_REFRESH_RATE; static int num_bytes = num_samples * sizeof(int16_t); static int16_t *audio_frame = (int16_t*)heap_caps_malloc(num_bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); audio_callback(audio_frame, num_samples); - hal::play_audio((uint8_t*)audio_frame, num_bytes); + espp::EspBox::get().play_audio((uint8_t*)audio_frame, num_bytes); } extern "C" void osd_setsound(void (*playfunc)(void *buffer, int length)) @@ -62,14 +61,13 @@ static void osd_stopsound(void) static int osd_init_sound(void) { - hal::audio_init(); audio_callback = NULL; return 0; } extern "C" void osd_getsoundinfo(sndinfo_t *info) { - info->sample_rate = hal::get_audio_sample_rate(); + info->sample_rate = espp::EspBox::get().audio_sample_rate(); info->bps = 16; } @@ -142,7 +140,7 @@ static void set_palette(rgb_t *pal) printf("set palette!\n"); for (i = 0; i < 256; i++) { - c = make_color(pal[i].r, pal[i].g, pal[i].b); + c = BoxEmu::make_color(pal[i].r, pal[i].g, pal[i].b); myPalette[i]= c; } @@ -161,7 +159,7 @@ static void clear(uint8 color) static bitmap_t *lock_write(void) { // SDL_LockSurface(mySurface); - myBitmap = bmp_createhw((uint8*)hal::get_frame_buffer1(), DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_WIDTH*2); + myBitmap = bmp_createhw((uint8*)espp::EspBox::get().frame_buffer1(), DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_WIDTH*2); // make sure they don't try to delete the frame buffer lol myBitmap->hardware = true; return myBitmap; @@ -174,13 +172,13 @@ static void free_write(int num_dirties, rect_t *dirty_rects) } static void custom_blit(const bitmap_t *bmp, int num_dirties, rect_t *dirty_rects) { - uint8_t *lcdfb = hal::get_frame_buffer0(); + uint8_t *lcdfb = espp::EspBox::get().frame_buffer0(); if (bmp->line[0] != NULL) { memcpy(lcdfb, bmp->line[0], 256 * 224); void* arg = (void*)lcdfb; - hal::push_frame(arg); + BoxEmu::get().push_frame(arg); } } @@ -192,8 +190,7 @@ static int ConvertJoystickInput() { int result = 0; - static struct InputState state; - hal::get_input_state(&state); + auto state = BoxEmu::get().gamepad_state(); if (!state.a) result |= (1<<13); diff --git a/components/rom_info/CMakeLists.txt b/components/rom_info/CMakeLists.txt index 39c6a407..52d20fb3 100644 --- a/components/rom_info/CMakeLists.txt +++ b/components/rom_info/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" - REQUIRES logger box-emu-hal) + REQUIRES logger box-emu) diff --git a/components/rom_info/include/rom_info.hpp b/components/rom_info/include/rom_info.hpp index 5928bbac..6b515573 100644 --- a/components/rom_info/include/rom_info.hpp +++ b/components/rom_info/include/rom_info.hpp @@ -4,7 +4,7 @@ #include #include -#include "fs_init.hpp" +#include "box-emu.hpp" #include "format.hpp" #include "string_utils.hpp" @@ -31,10 +31,10 @@ std::vector parse_metadata(const std::string& metadata_path); // for easy printing of Emulator using libfmt template <> struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + constexpr auto parse(format_parse_context& ctx) const { return ctx.begin(); } template - auto format(const Emulator& platform, FormatContext& ctx) { + auto format(const Emulator& platform, FormatContext& ctx) const { switch (platform) { case Emulator::UNKNOWN: return fmt::format_to(ctx.out(), "UNKNOWN"); @@ -67,10 +67,10 @@ struct fmt::formatter { // for easy printing of RomInfo using libfmt template <> struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + constexpr auto parse(format_parse_context& ctx) const { return ctx.begin(); } template - auto format(const RomInfo& info, FormatContext& ctx) { + auto format(const RomInfo& info, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "RomInfo {{ name: {}, boxart_path: {}, rom_path: {}, platform: {} }}\n", info.name, info.boxart_path, info.rom_path, info.platform); } diff --git a/components/rom_info/src/rom_info.cpp b/components/rom_info/src/rom_info.cpp index 19ff4a96..62023469 100644 --- a/components/rom_info/src/rom_info.cpp +++ b/components/rom_info/src/rom_info.cpp @@ -1,7 +1,7 @@ #include "rom_info.hpp" std::vector parse_metadata(const std::string& metadata_path) { - const std::string fs_prefix = std::string(MOUNT_POINT) + "/"; + const std::string fs_prefix = std::string(BoxEmu::mount_point) + "/"; std::vector infos; // load metadata path std::ifstream metadata(fs_prefix + metadata_path, std::ios::in); diff --git a/components/sms/CMakeLists.txt b/components/sms/CMakeLists.txt index 34d16b48..996c745d 100644 --- a/components/sms/CMakeLists.txt +++ b/components/sms/CMakeLists.txt @@ -2,7 +2,7 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" "smsplus" "smsplus/cpu" "smsplus/sound" PRIV_INCLUDE_DIRS "." "smsplus" "smsplus/cpu" "smsplus/sound" - REQUIRES box-emu-hal + REQUIRES box-emu statistics ) # target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-char-subscripts -Wno-attributes -Wno-implicit-fallthrough -Wno-unused-function -Wno-unused-variable -Wno-discarded-qualifiers) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable) diff --git a/components/sms/src/sms.cpp b/components/sms/src/sms.cpp index 5e37e690..038249bc 100644 --- a/components/sms/src/sms.cpp +++ b/components/sms/src/sms.cpp @@ -6,7 +6,8 @@ extern "C" { #include -#include "box_emu_hal.hpp" +#include "box-emu.hpp" +#include "statistics.hpp" static constexpr size_t SMS_SCREEN_WIDTH = 256; static constexpr size_t SMS_VISIBLE_HEIGHT = 192; @@ -57,7 +58,7 @@ static void init(uint8_t *romdata, size_t rom_data_size) { bitmap.width = SMS_SCREEN_WIDTH; bitmap.height = SMS_VISIBLE_HEIGHT; bitmap.pitch = bitmap.width; - bitmap.data = hal::get_frame_buffer0(); + bitmap.data = espp::EspBox::get().frame_buffer0(); cart.sram = sms_sram; sms.wram = sms_ram; @@ -66,7 +67,7 @@ static void init(uint8_t *romdata, size_t rom_data_size) { set_option_defaults(); - option.sndrate = hal::get_audio_sample_rate(); + option.sndrate = espp::EspBox::get().audio_sample_rate(); option.overscan = 0; option.extra_gg = 0; @@ -85,7 +86,7 @@ static void init(uint8_t *romdata, size_t rom_data_size) { void init_sms(uint8_t *romdata, size_t rom_data_size) { is_gg = false; - hal::set_native_size(SMS_SCREEN_WIDTH, SMS_VISIBLE_HEIGHT, SMS_SCREEN_WIDTH); + BoxEmu::get().native_size(SMS_SCREEN_WIDTH, SMS_VISIBLE_HEIGHT, SMS_SCREEN_WIDTH); load_rom_data(romdata, rom_data_size); sms.console = CONSOLE_SMS; sms.display = DISPLAY_NTSC; @@ -98,7 +99,7 @@ void init_sms(uint8_t *romdata, size_t rom_data_size) { void init_gg(uint8_t *romdata, size_t rom_data_size) { is_gg = true; - hal::set_native_size(GG_SCREEN_WIDTH, GG_VISIBLE_HEIGHT, SMS_SCREEN_WIDTH); + BoxEmu::get().native_size(GG_SCREEN_WIDTH, GG_VISIBLE_HEIGHT, SMS_SCREEN_WIDTH); load_rom_data(romdata, rom_data_size); sms.console = CONSOLE_GG; sms.display = DISPLAY_NTSC; @@ -112,8 +113,7 @@ void init_gg(uint8_t *romdata, size_t rom_data_size) { void run_sms_rom() { auto start = esp_timer_get_time(); // handle input here (see system.h and use input.pad and input.system) - InputState state; - hal::get_input_state(&state); + auto state = BoxEmu::get().gamepad_state(); // pad[0] is player 0 input.pad[0] = 0; @@ -145,15 +145,15 @@ void run_sms_rom() { palette[i] = (rgb565 >> 8) | (rgb565 << 8); } // set the palette - hal::set_palette(palette, PALETTE_SIZE); + BoxEmu::get().palette(palette, PALETTE_SIZE); // render the frame - hal::push_frame((uint8_t*)bitmap.data + frame_buffer_offset); + BoxEmu::get().push_frame((uint8_t*)bitmap.data + frame_buffer_offset); // ping pong the frame buffer frame_buffer_index = !frame_buffer_index; bitmap.data = frame_buffer_index - ? (uint8_t*)hal::get_frame_buffer1() - : (uint8_t*)hal::get_frame_buffer0(); + ? (uint8_t*)espp::EspBox::get().frame_buffer1() + : (uint8_t*)espp::EspBox::get().frame_buffer0(); } else { system_frame(1); } @@ -178,7 +178,7 @@ void run_sms_rom() { auto sms_audio_buffer_len = sms_snd.sample_count - 1; // push the audio buffer to the audio task - hal::play_audio((uint8_t*)sms_audio_buffer, sms_audio_buffer_len * 2 * 2); // 2 channels, 2 bytes per sample + espp::EspBox::get().play_audio((uint8_t*)sms_audio_buffer, sms_audio_buffer_len * 2 * 2); // 2 channels, 2 bytes per sample // update unlock based on x button static bool last_x = false; diff --git a/components/statistics/CMakeLists.txt b/components/statistics/CMakeLists.txt new file mode 100644 index 00000000..851fca28 --- /dev/null +++ b/components/statistics/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register( + INCLUDE_DIRS "include" + SRC_DIRS "src" + REQUIRES "format") diff --git a/components/box-emu-hal/include/statistics.hpp b/components/statistics/include/statistics.hpp similarity index 100% rename from components/box-emu-hal/include/statistics.hpp rename to components/statistics/include/statistics.hpp diff --git a/components/box-emu-hal/src/statistics.cpp b/components/statistics/src/statistics.cpp similarity index 100% rename from components/box-emu-hal/src/statistics.cpp rename to components/statistics/src/statistics.cpp diff --git a/main/cart.hpp b/main/cart.hpp index b9397293..934702d9 100644 --- a/main/cart.hpp +++ b/main/cart.hpp @@ -7,7 +7,7 @@ #include "display.hpp" #include "logger.hpp" -#include "box_emu_hal.hpp" +#include "box-emu.hpp" #include "rom_info.hpp" #include "menu.hpp" @@ -39,8 +39,8 @@ class Cart { // clear the screen espp::St7789::clear(0,0,320,240); // copy the romdata - rom_size_bytes_ = copy_romdata_to_cart_partition(get_rom_filename()); - romdata_ = get_mmapped_romdata(); + rom_size_bytes_ = BoxEmu::get().copy_file_to_romdata(get_rom_filename()); + romdata_ = BoxEmu::get().romdata(); // create the menu menu_ = std::make_unique(Menu::Config{ .display = display_, @@ -156,16 +156,14 @@ class Cart { virtual bool run() { running_ = true; // handle touchpad so we can know if the user presses the menu - uint8_t _num_touches = 0, _btn_state = false; - uint16_t _x = 0 ,_y = 0; - touchpad_read(&_num_touches, &_x, &_y, &_btn_state); + auto touch = espp::EspBox::get().touchpad_data(); + bool btn_state = touch.btn_state; // also get the gamepad input state so we can know if the user presses the // start/select buttons together to bring up the menu - InputState state; - hal::get_input_state(&state); + auto state = BoxEmu::get().gamepad_state(); // if the user presses the menu button or the start/select buttons, then // pause the game and show the menu - bool show_menu = _btn_state || (state.start && state.select); + bool show_menu = btn_state || (state.start && state.select); if (show_menu) { logger_.info("Menu pressed!"); pre_menu(); @@ -193,7 +191,7 @@ class Cart { protected: static constexpr size_t SCREEN_WIDTH = 320; static constexpr size_t SCREEN_HEIGHT = 240; - static constexpr std::string FS_PREFIX = MOUNT_POINT; + static constexpr std::string FS_PREFIX = BoxEmu::mount_point; static constexpr std::string SAVE_DIR = "/saves/"; virtual void on_menu_action(Menu::Action action) { @@ -258,7 +256,7 @@ class Cart { virtual void handle_video_setting() { logger_.info("Base handling video setting..."); - switch (hal::get_video_setting()) { + switch (BoxEmu::get().video_setting()) { case VideoSetting::ORIGINAL: set_original_video_setting(); break; diff --git a/main/gbc_cart.hpp b/main/gbc_cart.hpp index 7458dbe8..3630b5ae 100644 --- a/main/gbc_cart.hpp +++ b/main/gbc_cart.hpp @@ -86,7 +86,7 @@ class GbcCart : public Cart { virtual void set_original_video_setting() override { #if defined(ENABLE_GBC) logger_.info("gbc::video: original"); - hal::set_display_size(GAMEBOY_WIDTH, GAMEBOY_HEIGHT); + BoxEmu::get().display_size(GAMEBOY_WIDTH, GAMEBOY_HEIGHT); #endif } @@ -108,14 +108,14 @@ class GbcCart : public Cart { logger_.info("gbc::video: fit"); float x_scale = static_cast(SCREEN_HEIGHT) / static_cast(GAMEBOY_HEIGHT); int new_width = static_cast(static_cast(GAMEBOY_WIDTH) * x_scale); - hal::set_display_size(new_width, SCREEN_HEIGHT); + BoxEmu::get().display_size(new_width, SCREEN_HEIGHT); #endif } virtual void set_fill_video_setting() override { #if defined(ENABLE_GBC) logger_.info("gbc::video: fill"); - hal::set_display_size(SCREEN_WIDTH, SCREEN_HEIGHT); + BoxEmu::get().display_size(SCREEN_WIDTH, SCREEN_HEIGHT); #endif } diff --git a/main/genesis_cart.hpp b/main/genesis_cart.hpp index e50f4aa3..cded9a47 100644 --- a/main/genesis_cart.hpp +++ b/main/genesis_cart.hpp @@ -97,7 +97,7 @@ class GenesisCart : public Cart { #if defined(ENABLE_GENESIS) auto height = GENESIS_HEIGHT; auto width = GENESIS_WIDTH; - hal::set_display_size(width, height); + BoxEmu::get().display_size(width, height); #endif } @@ -120,14 +120,14 @@ class GenesisCart : public Cart { #if defined(ENABLE_GENESIS) logger_.info("genesis::video: fit"); // the genesis is already 320 px wide, don't do anything - hal::set_display_size(GENESIS_WIDTH, GENESIS_HEIGHT); + BoxEmu::get().display_size(GENESIS_WIDTH, GENESIS_HEIGHT); #endif } virtual void set_fill_video_setting() override { #if defined(ENABLE_GENESIS) logger_.info("genesis::video: fill"); - hal::set_display_size(SCREEN_WIDTH, SCREEN_HEIGHT); + BoxEmu::get().display_size(SCREEN_WIDTH, SCREEN_HEIGHT); #endif } diff --git a/main/main.cpp b/main/main.cpp index a7da375b..e7117fd6 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -11,11 +11,12 @@ #include "task_monitor.hpp" #include "timer.hpp" -#include "box_emu_hal.hpp" +#include "box-emu.hpp" #include "carts.hpp" #include "gui.hpp" #include "heap_utils.hpp" #include "rom_info.hpp" +#include "statistics.hpp" using namespace std::chrono_literals; @@ -23,15 +24,51 @@ extern "C" void app_main(void) { espp::Logger logger({.tag = "esp-box-emu", .level = espp::Logger::Verbosity::DEBUG}); logger.info("Bootup"); - hal::init(); + // initialize the hardware abstraction layer + BoxEmu &emu = BoxEmu::get(); + emu.set_log_level(espp::Logger::Verbosity::INFO); + espp::EspBox &box = espp::EspBox::get(); + logger.info("Running on {}", box.box_type()); + logger.info("Box Emu version: {}", emu.version()); + + // initialize + if (!emu.initialize_box()) { + logger.error("Failed to initialize box!"); + return; + } + + if (!emu.initialize_sdcard()) { + logger.warn("Failed to initialize SD card!"); + logger.warn("This may happen if the SD card is not inserted."); + } + + if (!emu.initialize_memory()) { + logger.error("Failed to initialize memory!"); + return; + } + + if (!emu.initialize_gamepad()) { + logger.warn("Failed to initialize gamepad!"); + logger.warn("This may happen if the gamepad is not connected."); + } + + if (!emu.initialize_battery()) { + logger.warn("Failed to initialize battery!"); + logger.warn("This may happen if the battery is not connected."); + } + + if (!emu.initialize_video()) { + logger.error("Failed to initialize video!"); + return; + } std::error_code ec; - auto external_i2c = hal::get_external_i2c(); + auto &external_i2c = emu.external_i2c(); espp::Drv2605 haptic_motor(espp::Drv2605::Config{ .device_address = espp::Drv2605::DEFAULT_ADDRESS, - .write = std::bind(&espp::I2c::write, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), - .read_register = std::bind(&espp::I2c::read_at_register, external_i2c.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), + .write = std::bind(&espp::I2c::write, &external_i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + .read_register = std::bind(&espp::I2c::read_at_register, &external_i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), .motor_type = espp::Drv2605::MotorType::LRA }); // we're using an LRA motor, so select th LRA library. @@ -49,7 +86,7 @@ extern "C" void app_main(void) { logger.info("initializing gui..."); - auto display = hal::get_display(); + auto display = box.display(); // initialize the gui Gui gui({ diff --git a/main/nes_cart.hpp b/main/nes_cart.hpp index 51f294fe..299ff93f 100644 --- a/main/nes_cart.hpp +++ b/main/nes_cart.hpp @@ -97,7 +97,7 @@ class NesCart : public Cart { virtual void set_original_video_setting() override { #if defined(ENABLE_NES) - hal::set_display_size(NES_WIDTH, NES_HEIGHT); + BoxEmu::get().display_size(NES_WIDTH, NES_HEIGHT); #endif } @@ -105,13 +105,13 @@ class NesCart : public Cart { #if defined(ENABLE_NES) float x_scale = static_cast(SCREEN_HEIGHT) / static_cast(NES_HEIGHT); int new_width = static_cast(static_cast(NES_WIDTH) * x_scale); - hal::set_display_size(new_width, SCREEN_HEIGHT); + BoxEmu::get().display_size(new_width, SCREEN_HEIGHT); #endif } virtual void set_fill_video_setting() override { #if defined(ENABLE_NES) - hal::set_display_size(SCREEN_WIDTH, SCREEN_HEIGHT); + BoxEmu::get().display_size(SCREEN_WIDTH, SCREEN_HEIGHT); #endif } diff --git a/main/sms_cart.hpp b/main/sms_cart.hpp index 8747f5d5..49ea7d7b 100644 --- a/main/sms_cart.hpp +++ b/main/sms_cart.hpp @@ -102,7 +102,7 @@ class SmsCart : public Cart { #if defined(ENABLE_SMS) auto height = info_.platform == Emulator::SEGA_MASTER_SYSTEM ? SMS_HEIGHT : GG_HEIGHT; auto width = info_.platform == Emulator::SEGA_MASTER_SYSTEM ? SMS_WIDTH : GG_WIDTH; - hal::set_display_size(width, height); + BoxEmu::get().display_size(width, height); #endif } @@ -128,14 +128,14 @@ class SmsCart : public Cart { float width = info_.platform == Emulator::SEGA_MASTER_SYSTEM ? SMS_WIDTH : GG_WIDTH; float x_scale = static_cast(SCREEN_HEIGHT) / height; int new_width = static_cast(width * x_scale); - hal::set_display_size(new_width, SCREEN_HEIGHT); + BoxEmu::get().display_size(new_width, SCREEN_HEIGHT); #endif } virtual void set_fill_video_setting() override { #if defined(ENABLE_SMS) logger_.info("sms::video: fill"); - hal::set_display_size(SCREEN_WIDTH, SCREEN_HEIGHT); + BoxEmu::get().display_size(SCREEN_WIDTH, SCREEN_HEIGHT); #endif }