#include "display.h" #include #include "GC9A01/VGA1_16x32.h" #include "gc9a01.h" #include "hardware/gpio.h" #include "hardware/spi.h" #include "hardware/structs/io_bank0.h" #include "pico/time.h" #include "spi.h" #include #include #include #include "Font5x7FixedMono.h" #include "alarm.h" #include "control.h" #include "macros.h" #include "multicore_events.h" #include "hardware/rtc.h" #include "pico/multicore.h" int32_t t_fine; uint16_t dig_T1; int16_t dig_T2, dig_T3; // LCD config gc9a01_GC9A01_obj_t create_lcd() { spi_init(SPI_PORT, SPI_CLOCK_HZ); // Use your defined SPI port and clock speed // Initialize GPIO pins for SPI communication using your definitions gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); // SCK = 18 gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI); // MOSI = 19 // Note: MISO not needed for display, but if you had one it would be on a // separate pin // Configure Chip Select gpio_init(PIN_CS); // CS = 17 gpio_set_dir(PIN_CS, GPIO_OUT); gpio_put(PIN_CS, 1); // Set CS High // Configure Reset pin gpio_init(PIN_RST); // Reset = 20 gpio_set_dir(PIN_RST, GPIO_OUT); gpio_put(PIN_RST, 0); // Configure DC pin gpio_init(PIN_DC); // DC = 16 gpio_set_dir(PIN_DC, GPIO_OUT); gpio_put(PIN_DC, 0); // Note: You don't have a backlight pin defined in spi.h // If you have a backlight control, define PIN_BL in spi.h // For now, commenting out backlight control: /* gpio_init(PIN_BL); gpio_set_dir(PIN_BL, GPIO_OUT); gpio_put(PIN_BL, 0); */ gc9a01_GC9A01_obj_t lcd; lcd.spi_obj = SPI_PORT; lcd.reset = PIN_RST; lcd.dc = PIN_DC; lcd.cs = PIN_CS; lcd.backlight = -1; // Set to -1 if no backlight control, or define PIN_BL in spi.h lcd.xstart = 0; lcd.ystart = 0; lcd.display_width = 240; lcd.display_height = 240; lcd.rotation = 0; lcd.buffer_size = 2048; lcd.i2c_buffer = static_cast(malloc(2048)); return lcd; } gc9a01_GC9A01_obj_t display; void draw_circle(int16_t x_center, int16_t y_center, int16_t r, uint16_t color) { for (uint16_t i = 720; i > 0; i--) { uint8_t x = x_center + static_cast(static_cast(r) * sin((180.0 + i / 2.0) * M_TWOPI / 360.0)); uint8_t y = y_center + static_cast(static_cast(r) * cos((180.0 + i / 2.0) * M_TWOPI / 360.0)); gc9a01_draw_pixel(&display, x, y, color); } } void draw_ui_circle(uint16_t color) { draw_circle(120, 120, 119, color); } std::array get_ui_circle_vertical_pos(uint16_t x, uint16_t center_x, uint16_t center_y, uint16_t radius) { // Ctalculate horizontal distance from point to center uint16_t dx = x - center_x; uint16_t dx_squared = dx * dx; uint16_t radius_squared = radius * radius; // Check if point's x-coordinate is within circle bounds if (dx_squared >= radius_squared) { return {0, 0}; // Outside circle - no vertical space } // Calculate vertical distance from center to circle edge at this x float vertical_offset = sqrt(radius_squared - dx_squared); // Find y-coordinates where vertical line intersects circle uint16_t y_top = center_y - (uint16_t)vertical_offset; uint16_t y_bottom = center_y + (uint16_t)vertical_offset; std::array positions = {y_top, y_bottom}; return positions; } void clear_display() { gc9a01_fill(&display, BLACK); } void display_start() { char buf[10]; display = create_lcd(); gc9a01_init(&display); sleep_ms(100); clear_display(); draw_ui_circle(MAGENTA); } void print_time(const bool force_refresh) { datetime_t t; if (rtc_get_datetime(&t)) { const GFXfont *font = &VGA1_16x32; char buf[11]; sprintf(buf, "%02d:%02d:%02d", t.hour, t.min, t.sec); gc9a01_text(&display, font, buf, 120 - ((16 * 8) / 2), 120 - 16, WHITE, BLACK); static uint8_t last_day = UINT8_MAX; if (last_day != t.day || force_refresh) { font = &Font5x7FixedMono; sprintf(buf, "%02d.%02d.%04d", t.day, t.month, t.year); gc9a01_text_gfx_buffered(&display, font, buf, 120 - ((6 * 10) / 2), ((120 - 16) + 32) + 7, WHITE, BLACK); last_day = t.day; } } else { const char *rtc_fail = "NO SYNC!"; const GFXfont *font = &Font5x7FixedMono; gc9a01_text_gfx_buffered(&display, font, rtc_fail, 120 - ((5 * 8) / 2), 120 - ((7 * 1) / 2), RED, BLACK); } } void print_alarm(alarm *alarm, selected_t selected, uint8_t x, u_int8_t y) { bool setting_sub = false; uint8_t selected_item = UINT8_MAX; do { uint8_t item_index = 0; gc9a01_rect(&display, x, y, ALARM_BOX_WIDTH, ALARM_BOX_HEIGHT, selected); char buf[3]; sprintf(buf, "%02d", alarm->hours()); if (selected_item == item_index) { gc9a01_fill_rect(&display,((x + ALARM_BOX_WIDTH / 2) - ((strlen(buf) * 5) / 2)) - 2,y + 3,(5*2)+1,7,BLACK); } gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono, buf,((x + ALARM_BOX_WIDTH / 2) - ((strlen(buf) * 5) / 2)) - 2, y + 10, selected_item == item_index ? setting_sub ? SETTING : SELECTED : WHITE,BLACK); item_index++; sprintf(buf, ":"); gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono, buf,(((x + ALARM_BOX_WIDTH / 2) - ((strlen(buf) * 5) / 2)) - 2)+(5*2)-(5/2), y + 10, WHITE,BLACK); sprintf(buf, "%02d", alarm->minutes()); if (selected_item == item_index) { gc9a01_fill_rect(&display,(((x + ALARM_BOX_WIDTH / 2) - ((strlen(buf) * 5) / 2)) - 2)+5*3,y + 3,(5*2)+1,7,BLACK); } gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono, buf,(((x + ALARM_BOX_WIDTH / 2) - ((strlen(buf) * 5) / 2)) - 2)+5*3, y + 10, selected_item == item_index ? setting_sub ? SETTING : SELECTED : WHITE,BLACK); item_index++; gc9a01_fill_rect(&display, x+ALARM_BOX_WIDTH-7, y+2,5,7,alarm->enabled() ? GREEN : RED); if (selected_item == item_index) { gc9a01_rect(&display, x+ALARM_BOX_WIDTH-7, y+2,5,7,alarm->enabled() ? RED : GREEN); } item_index++; u_int8_t x_text_abrivs = x + (5 / 2); { std::array days_enabled = alarm->days_enabled(); for (uint8_t i = 0; i < days_enabled.size(); i++) { gc9a01_fill_rect(&display, x_text_abrivs, (y + ALARM_BOX_HEIGHT) - 10,5,7,days_enabled[i] ? GREEN : RED); if (selected_item == item_index) { gc9a01_rect(&display, x_text_abrivs, (y + ALARM_BOX_HEIGHT) - 10,5,7,days_enabled[i] ? RED : GREEN); } item_index++; x_text_abrivs += 5 + 5 / 2; } } if (alarm->every_other_week()) { char c = '='; if (selected_item == item_index) { gc9a01_fill_rect(&display, x_text_abrivs,(y + ALARM_BOX_HEIGHT) - 7, 5, 1, BLACK); } gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono,&c,x_text_abrivs,(y + ALARM_BOX_HEIGHT) - 3,selected_item == item_index ? SELECTED : MAGENTA,BLACK); item_index++; x_text_abrivs += 5 + 5 / 2; c = alarm->even_week() ? '2' : '1'; if (selected_item == item_index && c == '1') { gc9a01_fill_rect(&display, x_text_abrivs+4,(y + ALARM_BOX_HEIGHT) - 9,1,2,BLACK); } gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono,&c,x_text_abrivs,(y + ALARM_BOX_HEIGHT) - 3,selected_item == item_index ? SELECTED : alarm->even_week() ? MAGENTA : CYAN,BLACK); item_index++; } else { constexpr char c = '-'; if (selected_item == item_index) { gc9a01_fill_rect(&display, x_text_abrivs,(y + ALARM_BOX_HEIGHT) - 8, 5, 3, BLACK); } gc9a01_text_gfx_buffered(&display, &Font5x7FixedMono,&c,x_text_abrivs,(y + ALARM_BOX_HEIGHT) - 3,selected_item == item_index ? SELECTED : CYAN,BLACK); item_index++; } if (selected == selected_t::SETTING) { switch (static_cast(multicore_fifo_pop_blocking())) { case PRIMARY_BUTTON_PRESSED: if (setting_sub) { setting_sub = false; break; } switch (selected_item) { case 0: // hours case 1: // minutes setting_sub = true; break; case 2: // enable/disable alarm->set_state(!alarm->enabled()); break; case 10: // every other week alarm->set_every_other_week(!alarm->every_other_week()); break; case 11: // even week alarm->set_even_week(!alarm->even_week()); break; default: // days of the week std::array days_enabled = alarm->days_enabled(); days_enabled[selected_item-3] = !days_enabled[selected_item-3]; alarm->set_days_enabled(days_enabled); } break; case SECONDARY_BUTTON_PRESSED: goto exit_print_alarm; case KNOB_CHANGE: { if (!setting_sub) {selected_item = std::min(static_cast(static_cast(get_knob_percentage())/100.0f*static_cast(item_index)),static_cast(item_index-1));} else { switch (selected_item) { case 0: alarm->set_hours(std::min(static_cast(static_cast(get_knob_percentage())/100.0f*static_cast(24)),static_cast(23))); break; case 1: alarm->set_minutes(std::min(static_cast(static_cast(get_knob_percentage())/100.0f*static_cast(60)),static_cast(59))); break; default: printf("ERROR: invalid option selected!!!\n"); }} } break; } } } while (selected == selected_t::SETTING); exit_print_alarm: return; // fix waring about C23 extension } void print_add_button(uint8_t center_x, uint8_t center_y, uint8_t w, uint16_t color) { draw_circle(center_x, center_y, w/2, color); const uint8_t plus_length = w - 7; const uint8_t half_length = plus_length / 2; gc9a01_hline(&display, center_x - half_length, center_y, plus_length, color); gc9a01_vline(&display, center_x, center_y - half_length, plus_length, color); }