diff --git a/main/drivers/CMakeLists.txt b/main/drivers/CMakeLists.txt index 8f76bb6..9378bbb 100644 --- a/main/drivers/CMakeLists.txt +++ b/main/drivers/CMakeLists.txt @@ -2,8 +2,13 @@ set(SOURCES "TM1640/TM16xx.cpp" "TM1640/TM1640.cpp" "bottom_half.cpp" - "wires.cpp" + "char_lcd.cpp" + "game_timer.cpp" "leds.cpp" + "sd.cpp" + "speaker.cpp" + "sseg.cpp" + "wires.cpp" ) target_sources(${COMPONENT_LIB} PRIVATE ${SOURCES}) diff --git a/main/drivers/char_lcd.cpp b/main/drivers/char_lcd.cpp new file mode 100644 index 0000000..af0fa4b --- /dev/null +++ b/main/drivers/char_lcd.cpp @@ -0,0 +1,18 @@ +#include "char_lcd.h" + +#define CHAR_LCD_I2C_NUM I2C_NUM_0 + +#define LCD_ADDR 0x27 +#define LCD_COLS 20 +#define LCD_ROWS 4 + +static const char *TAG = "char_lcd"; + +void init_char_lcd(void) { + lcd_init(&lcd, LCD_ADDR, CHAR_LCD_I2C_NUM); + lcd_begin(&lcd, LCD_COLS, LCD_ROWS); + + lcd_set_backlight(&lcd, 255); + + ESP_LOGI(TAG, "LCD initialized"); +} diff --git a/main/drivers/char_lcd.h b/main/drivers/char_lcd.h new file mode 100644 index 0000000..d4003dc --- /dev/null +++ b/main/drivers/char_lcd.h @@ -0,0 +1,18 @@ +#ifndef CHAR_LCD_H +#define CHAR_LCD_H + +#include "i2c_lcd_pcf8574.h" + +#define CHAR_LCD_I2C_NUM I2C_NUM_0 + +#define LCD_ADDR 0x27 +#define LCD_COLS 20 +#define LCD_ROWS 4 + +i2c_lcd_pcf8574_handle_t lcd; + +static const char *CHAR_LCD_TAG = "char_lcd"; + +void init_char_lcd(void); + +#endif /* CHAR_LCD_H */ \ No newline at end of file diff --git a/main/drivers/char_lcd.hpp b/main/drivers/char_lcd.hpp deleted file mode 100644 index ff625c8..0000000 --- a/main/drivers/char_lcd.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CHAR_LCD_HPP -#define CHAR_LCD_HPP - -#include "i2c_lcd_pcf8574.h" - -#define CHAR_LCD_I2C_NUM I2C_NUM_0 - -#define LCD_ADDR 0x27 -#define LCD_COLS 20 -#define LCD_ROWS 4 - -i2c_lcd_pcf8574_handle_t lcd; - -static const char *CHAR_LCD_TAG = "char_lcd"; - -void init_char_lcd(void) { - - lcd_init(&lcd, LCD_ADDR, CHAR_LCD_I2C_NUM); - lcd_begin(&lcd, LCD_COLS, LCD_ROWS); - - // Turn on the backlight - lcd_set_backlight(&lcd, 255); - - ESP_LOGI(CHAR_LCD_TAG, "LCD initialized"); -} - -void example_lcd(void) { - // Print a message - lcd_set_cursor(&lcd, 0, 0); - lcd_print(&lcd, "Hello, ESP32!"); - lcd_set_cursor(&lcd, 0, 1); - lcd_print(&lcd, "LCD Test"); - - int counter = 0; - while (1) { - vTaskDelay(20 / portTICK_PERIOD_MS); // Wait for 1 second - - // Update the counter on the LCD - lcd_set_cursor(&lcd, 10, 1); - char buffer[14]; - snprintf(buffer, sizeof(buffer), "%5d", counter); - lcd_print(&lcd, buffer); - - counter++; - - // Reset counter to avoid display overflow - if (counter > 99999) counter = 0; - - } -} - -#endif /* CHAR_LCD_HPP */ \ No newline at end of file diff --git a/main/drivers/game_timer.cpp b/main/drivers/game_timer.cpp new file mode 100644 index 0000000..67b5590 --- /dev/null +++ b/main/drivers/game_timer.cpp @@ -0,0 +1,79 @@ +#ifndef GAME_TIMER_HPP +#define GAME_TIMER_HPP + +#include "game_timer.h" + +static bool is_module_playing; +static bool is_game_playing; + +// in ms +static uint32_t game_time_left; +static uint32_t module_time_left; + +static void game_timer_task(void *arg); +static uint32_t sat_sub(uint32_t x, uint32_t y); + +void init_game_module_timer(void) { + xTaskCreate(game_timer_task, "game_module_timer", 4096, NULL, 10, NULL); +} + +void start_game_timer(void) { + is_game_playing = true; +} + +void stop_game_timer(void) { + is_game_playing = false; +} + +void start_module_timer(void) { + is_module_playing = true; +} + +void stop_module_timer(void) { + is_module_playing = false; +} + +void set_game_time(uint32_t new_time) { + time_left = new_time; +} + +uint32_t get_game_time() { + return time_left; +} + +void set_module_time(uint32_t new_time) { + time_left = new_time; +} + +uint32_t get_module_time() { + return time_left; +} + +static void game_timer_task(void *arg) +{ + TickType_t lastWakeTime = xTaskGetTickCount(); + + const uint32_t frequency = 100; + while (1) { + vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(frequency)); + if (is_game_playing) { + game_time_left = sat_sub(game_time_left, frequency); + set_game_sseg_num(game_time_left / 100, 1); + } + if (is_module_playing) { + module_time_left = sat_sub(module_time_left, frequency); + set_module_sseg_num(module_time_left / 100, 1); + } + } + + vTaskDelete(NULL); +} + +static uint32_t sat_sub(uint32_t x, uint32_t y) +{ + uint32_t res = x - y; + res &= -(res <= x); + return res; +} + +#endif /* GAME_TIMER_HPP */ \ No newline at end of file diff --git a/main/drivers/game_timer.h b/main/drivers/game_timer.h new file mode 100644 index 0000000..a5eb25d --- /dev/null +++ b/main/drivers/game_timer.h @@ -0,0 +1,30 @@ +#ifndef GAME_TIMER_H +#define GAME_TIMER_H + +#include "freertos/FreeRTOS.h" +#include "sseg.hpp" + +/// Initializes the game and module timers. +void init_game_module_timer(void); + +/// Starts the game timer +void start_game_timer(void); +/// Stops the game timer +void stop_game_timer(void); + +/// Starts the module timer +void start_module_timer(void); +/// Stops the module timer +void stop_module_timer(void); + +/// Sets the game time in ms +void set_game_time(uint32_t new_time); +/// Gets the current game time in ms +uint32_t get_game_time(); + +/// Sets the module time in ms +void set_module_time(uint32_t new_time); +/// Gets the current module time in ms +uint32_t get_module_time(); + +#endif /* GAME_TIMER_H */ \ No newline at end of file diff --git a/main/drivers/game_timer.hpp b/main/drivers/game_timer.hpp deleted file mode 100644 index 1d7c36b..0000000 --- a/main/drivers/game_timer.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef GAME_TIMER_HPP -#define GAME_TIMER_HPP - -#include "freertos/FreeRTOS.h" - -#include "sseg.hpp" - -static bool playing; -static uint32_t time_left; - -static void game_timer_task(void *arg); -uint32_t sat_sub(uint32_t x, uint32_t y); - -void start_timer(void) { - playing = true; -} - -void stop_timer(void) { - playing = false; -} - -void init_game_timer(void) { - xTaskCreate(game_timer_task, "game_timer", 4096, NULL, 10, NULL); -} - -void set_game_time(uint32_t new_time) { - time_left = new_time; -} - -uint32_t get_game_time() { - return time_left; -} - -static void game_timer_task(void *arg) -{ - TickType_t lastWakeTime = xTaskGetTickCount(); - - const uint32_t frequency = 100; - while (1) { - vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(frequency)); - if (playing) { - time_left = sat_sub(time_left, frequency); - set_game_timer(time_left / 100, 1); - } - } - - vTaskDelete(NULL); -} - -uint32_t sat_sub(uint32_t x, uint32_t y) -{ - uint32_t res = x - y; - res &= -(res <= x); - return res; -} - -#endif /* GAME_TIMER_HPP */ \ No newline at end of file diff --git a/main/drivers/leds.cpp b/main/drivers/leds.cpp index 9e1983e..b0bc4cb 100644 --- a/main/drivers/leds.cpp +++ b/main/drivers/leds.cpp @@ -1,6 +1,5 @@ #include "leds.h" -#define TAG "leds" #define PIXEL_COUNT 21 #define NEOPIXEL_PIN GPIO_NUM_7 diff --git a/main/drivers/leds.h b/main/drivers/leds.h index ad3f991..439381b 100644 --- a/main/drivers/leds.h +++ b/main/drivers/leds.h @@ -1,6 +1,5 @@ #ifndef LEDS_H #define LEDS_H -#include "neopixel.h" #endif /* LEDS_H */ \ No newline at end of file diff --git a/main/drivers/sd.hpp b/main/drivers/sd.cpp similarity index 83% rename from main/drivers/sd.hpp rename to main/drivers/sd.cpp index 0092b18..2e51882 100644 --- a/main/drivers/sd.hpp +++ b/main/drivers/sd.cpp @@ -1,26 +1,4 @@ -#ifndef SD_HPP -#define SD_HPP - -#include -#include -#include -#include "esp_vfs_fat.h" -#include "sdmmc_cmd.h" -#include "driver/sdmmc_host.h" - -static const char *SD_TAG = "sd_driver"; - -#define MOUNT_POINT "/sdcard" - -const char mount_point[] = MOUNT_POINT; -sdmmc_card_t *card; - -#define SD_PIN_CLK GPIO_NUM_48 -#define SD_PIN_CMD GPIO_NUM_45 -#define SD_PIN_D0 GPIO_NUM_47 -#define SD_PIN_D1 GPIO_NUM_21 -#define SD_PIN_D2 GPIO_NUM_39 -#define SD_PIN_D3 GPIO_NUM_38 +#include "sd.h" void init_sd() { esp_err_t ret; @@ -89,5 +67,3 @@ void deinit_sd() { esp_vfs_fat_sdcard_unmount(mount_point, card); ESP_LOGI(SD_TAG, "Card unmounted"); } - -#endif /* SD_HPP */ \ No newline at end of file diff --git a/main/drivers/sd.h b/main/drivers/sd.h new file mode 100644 index 0000000..8ddb57d --- /dev/null +++ b/main/drivers/sd.h @@ -0,0 +1,27 @@ +#ifndef SD_H +#define SD_H + +#include +#include +#include +#include "esp_vfs_fat.h" +#include "sdmmc_cmd.h" +#include "driver/sdmmc_host.h" + +#define MOUNT_POINT "/sdcard" + +const char mount_point[] = MOUNT_POINT; + +sdmmc_card_t *card; + +#define SD_PIN_CLK GPIO_NUM_48 +#define SD_PIN_CMD GPIO_NUM_45 +#define SD_PIN_D0 GPIO_NUM_47 +#define SD_PIN_D1 GPIO_NUM_21 +#define SD_PIN_D2 GPIO_NUM_39 +#define SD_PIN_D3 GPIO_NUM_38 + +void init_sd(); +void deinit_sd(); + +#endif /* SD_H */ \ No newline at end of file diff --git a/main/drivers/speaker.hpp b/main/drivers/speaker.cpp similarity index 76% rename from main/drivers/speaker.hpp rename to main/drivers/speaker.cpp index 9db7301..8c01abc 100644 --- a/main/drivers/speaker.hpp +++ b/main/drivers/speaker.cpp @@ -1,31 +1,14 @@ -#ifndef SPEAKER_HPP -#define SPEAKER_HPP - -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/i2s_std.h" -#include "driver/gpio.h" -#include "esp_check.h" -#include "sdkconfig.h" -#include "sd.hpp" - -#define SPEAKER_PIN_BCLK GPIO_NUM_46 -#define SPEAKER_PIN_WS GPIO_NUM_9 -#define SPEAKER_PIN_DOUT GPIO_NUM_3 -#define SAMPLE_RATE 44100 -#define AUDIO_BUFFER 2048 +#include "speaker.h" static i2s_chan_handle_t tx_chan; -static const char *SPEAKER_TAG = "speaker_driver"; +static const char *TAG = "speaker_driver"; esp_err_t play_raw(const char *fp) { FILE *fh = fopen(fp, "rb"); if (fh == NULL) { - ESP_LOGE(SPEAKER_TAG, "Failed to open file"); + ESP_LOGE(TAG, "Failed to open file"); return ESP_ERR_INVALID_ARG; } @@ -56,7 +39,7 @@ esp_err_t play_raw(const char *fp) { for (int i = 0; i < bytes_read; i++) { write_buf[i] = read_buf[i] << 4; } - ESP_LOGV(SPEAKER_TAG, "Bytes read: %d", bytes_read); + ESP_LOGV(TAG, "Bytes read: %d", bytes_read); } i2s_channel_disable(tx_chan); @@ -66,7 +49,7 @@ esp_err_t play_raw(const char *fp) { return ESP_OK; } -static void init_speaker(void) { +void init_speaker(void) { i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL)); @@ -92,5 +75,3 @@ static void init_speaker(void) { void play_example() { ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/o.pcm")); } - -#endif /* SPEAKER_HPP */ \ No newline at end of file diff --git a/main/drivers/speaker.h b/main/drivers/speaker.h new file mode 100644 index 0000000..8c3b1c3 --- /dev/null +++ b/main/drivers/speaker.h @@ -0,0 +1,28 @@ +#ifndef SPEAKER_H +#define SPEAKER_H + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s_std.h" +#include "driver/gpio.h" +#include "esp_check.h" +#include "sdkconfig.h" +#include "sd.hpp" + +#define SPEAKER_PIN_BCLK GPIO_NUM_46 +#define SPEAKER_PIN_WS GPIO_NUM_9 +#define SPEAKER_PIN_DOUT GPIO_NUM_3 +#define SAMPLE_RATE 44100 +#define AUDIO_BUFFER 2048 + +static i2s_chan_handle_t tx_chan; + +static const char *SPEAKER_TAG = "speaker_driver"; + +esp_err_t play_raw(const char *fp); +void init_speaker(void) +void play_example(); + +#endif /* SPEAKER_H */ \ No newline at end of file diff --git a/main/drivers/sseg.cpp b/main/drivers/sseg.cpp new file mode 100644 index 0000000..3f11807 --- /dev/null +++ b/main/drivers/sseg.cpp @@ -0,0 +1,37 @@ +#include "sseg.h" + +static const char *TAG = "sseg_driver"; + +void init_sseg() { + sseg = new TM1640(SSEG_PIN_DATA, SSEG_PIN_CLK, 8); +} + +void set_game_sseg_raw(uint8_t* digits) { + sseg->setSegments(0, digits[0]); + sseg->setSegments(1, digits[1]); + sseg->setSegments(2, digits[2]); + sseg->setSegments(3, digits[3]); +} + +void set_module_sseg_raw(uint8_t* digits) { + sseg->setSegments(4, digits[0]); + sseg->setSegments(5, digits[1]); + sseg->setSegments(6, digits[2]); + sseg->setSegments(7, digits[3]); +} + +void set_game_sseg_num(unsigned int value, int dot_pos) { + for (int i = 0; i < 4; i++) { + auto idx = value % 10; + sseg->sendChar(3-i, TM16XX_NUMBER_FONT[idx], i == dot_pos); + value = value / 10; + } +} + +void set_module_sseg_num(unsigned int value, int dot_pos) { + for (int i = 0; i < 4; i++) { + auto idx = value % 10; + sseg->sendChar(7-i, TM16XX_NUMBER_FONT[idx], i == dot_pos); + value = value / 10; + } +} diff --git a/main/drivers/sseg.h b/main/drivers/sseg.h new file mode 100644 index 0000000..c4e9c39 --- /dev/null +++ b/main/drivers/sseg.h @@ -0,0 +1,35 @@ +#ifndef SSEG_H +#define SSEG_H + +#include "TM1640/TM1640.h" +#include + +#define SSEG_PIN_DATA GPIO_NUM_10 +#define SSEG_PIN_CLK GPIO_NUM_11 + +TM1640* sseg = nullptr; + +/// Initializes the seven segment driver +void init_sseg(); + +/// sets the game seven segment to the value of the digits +/// +/// the bits 0-6 map to segments A-G, and bit 7 is DP. +/// +/// `digits` must have len >= 4. +void set_game_sseg_raw(uint8_t* digits); + +/// sets the module seven segment to the value of the digits +/// +/// the bits 0-6 map to segments A-G, and bit 7 is DP. +/// +/// `digits` must have len >= 4. +void set_module_sseg_raw(uint8_t* digits); + +/// sets the game timer to the given number, with the dot at position `dot_pos` from the right (0 => right-most digit). +void set_game_sseg_num(unsigned int value, int dot_pos); + +/// sets the module timer to the given number, with the dot at position `dot_pos` from the right (0 => right-most digit). +void set_module_sseg_num(unsigned int value, int dot_pos); + +#endif /* SSEG_H */ \ No newline at end of file diff --git a/main/drivers/sseg.hpp b/main/drivers/sseg.hpp deleted file mode 100644 index 72e98c2..0000000 --- a/main/drivers/sseg.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SSEG_HPP -#define SSEG_HPP - -#include "TM1640/TM1640.h" -#include - -#define SSEG_PIN_DATA GPIO_NUM_10 -#define SSEG_PIN_CLK GPIO_NUM_11 - -static const char *SSEG_TAG = "sseg_driver"; - -TM1640* sseg = nullptr; - -void init_sseg() { - sseg = new TM1640(SSEG_PIN_DATA, SSEG_PIN_CLK, 8); -} - -void set_game_timer(unsigned int value, int dot_pos) { - if (sseg == nullptr) { - ESP_LOGE(SSEG_TAG, "SSEG display not initialized"); - } - for (int i = 0; i < 4; i++) { - auto idx = value % 10; - sseg->sendChar(3-i, TM16XX_NUMBER_FONT[idx], i == dot_pos); - value = value / 10; - } -} - -void set_module_timer(unsigned int value, int dot_pos) { - if (sseg == nullptr) { - ESP_LOGE(SSEG_TAG, "SSEG display not initialized"); - } - for (int i = 0; i < 4; i++) { - auto idx = value % 10; - sseg->sendChar(7-i, TM16XX_NUMBER_FONT[idx], i == dot_pos); - value = value / 10; - } -} - -#endif /* SSEG_HPP */ \ No newline at end of file diff --git a/main/drivers/wires.cpp b/main/drivers/wires.cpp index 12b88a6..c504144 100644 --- a/main/drivers/wires.cpp +++ b/main/drivers/wires.cpp @@ -1,12 +1,5 @@ #include "wires.h" -#define WIRES_PIN_DELTA GPIO_NUM_2 -#define WIRES_I2C_NUM I2C_NUM_1 -#define WIRES_I2C_ADDR 125 - -#define DELTA_BIT_WIRES 0 -#define DELTA_BIT_BUTTON 1 - static const char *TAG = "wires"; static bool button_state; diff --git a/main/idf_component.yml b/main/idf_component.yml index ec497b4..1fd0084 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - zorxx/neopixel: "*" - # iamflinks/i2c_lcd_pcf8574: "^1.0.1" + iamflinks/i2c_lcd_pcf8574: "^1.0.1" + espressif/led_strip: "^2.5.4" lvgl/lvgl: "^8.1" atanisoft/esp_lcd_ili9488: "^1.0.9" ## Required IDF version