291 lines
10 KiB
C++
291 lines
10 KiB
C++
#include "display.h"
|
|
|
|
#include <array>
|
|
|
|
#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 <cmath>
|
|
#include <cstring>
|
|
#include <stdio.h>
|
|
|
|
#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<uint16_t *>(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<int16_t>(static_cast<float>(r) *
|
|
sin((180.0 + i / 2.0) * M_TWOPI / 360.0));
|
|
uint8_t y = y_center +
|
|
static_cast<int16_t>(static_cast<float>(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<uint16_t, 2> 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<uint16_t, 2> 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<bool, 7> 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_event_t>(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());
|
|
rearm_alarm_timers();
|
|
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<bool, 7> 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<uint8_t>(static_cast<float>(get_knob_percentage())/100.0f*static_cast<float>(item_index)),static_cast<uint8_t>(item_index-1));} else {
|
|
switch (selected_item) {
|
|
case 0:
|
|
alarm->set_hours(std::min(static_cast<uint8_t>(static_cast<float>(get_knob_percentage())/100.0f*static_cast<float>(24)),static_cast<uint8_t>(23)));
|
|
break;
|
|
case 1:
|
|
alarm->set_minutes(std::min(static_cast<uint8_t>(static_cast<float>(get_knob_percentage())/100.0f*static_cast<float>(60)),static_cast<uint8_t>(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);
|
|
}
|