/* * Copyright (C) 2023 Daniele Lacamera * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include #include "stm32f7_ltdc.h" #include "ui.h" #include "systick.h" #include "button.h" static uint8_t menu_on = 0; uint8_t ui_menu_is_on(void) { return menu_on; } void ui_menu(uint8_t onoff) { menu_on = onoff; } #define BUTTON_RIGHT 1 #define BUTTON_LEFT 2 #define BUTTON_UP 0 #define BUTTON_DOWN 3 #define BUTTON_IN 7 #define BUTTON_OUT 6 #define BUTTON_FIRE 5 #define NO_CHANNEL (-1) enum control_mode_e { CTL_RUN, CTL_STOP, CTL_PAUSE, CTL_TRIGGER, CTL_MAX }; int res[] = { 1000000 , 500000 , 200000 , 100000 , 50000 , 20000 , 10000 , 5000 , 2000 , 1000 , 500 , 200 , 100 , 50 , 20 , 0 }; #define FONT_HEIGHT 8 #define FONT_WIDTH 8 extern const unsigned char fb_font[256][FONT_WIDTH]; uint8_t *ui_get_screen(int layer) { if (layer == 0) return (uint8_t *)Screen_address; else return (uint8_t *)Overlay_address; } void ui_draw_h_segment(int layer, uint8_t color, uint32_t row, uint32_t start, uint32_t len) { uint32_t i; uint32_t pos = row * xres + start; uint8_t *screen = ui_get_screen(layer); for (i = 0; i < len; i++) { screen[pos + i] = color; } } void ui_draw_v_segment(int layer, uint8_t color, uint32_t col, uint32_t start, uint32_t len) { uint32_t i; uint32_t pos = start * xres + col; uint8_t *screen = ui_get_screen(layer); for (i = 0; i < len; i++) { screen[pos + i * xres] = color; } } void ui_fill_area(int layer, uint8_t color, uint32_t x, uint32_t y, uint32_t x1, uint32_t y1) { int i; for (i = y; i < y1; i++) { ui_draw_h_segment(layer, color, i, x, x1 - x); } } void ui_text_at(int layer, uint8_t color, uint32_t x, uint32_t y, char *text) { uint32_t i, j; char fc; const uint8_t *render; uint32_t pos = y * xres + x; uint8_t *screen = ui_get_screen(layer); while(text[0]) { uint32_t cur = pos; fc = text[0]; render = fb_font[(int)fc]; for (i = 0; i < FONT_HEIGHT; i++) { for (j = 0; j < FONT_WIDTH; j++) { int right_shift = (FONT_HEIGHT - 1) - j; cur = pos + i * xres + j; if (render[i] & (1 << (7 - j))) { screen[cur] = color; } } } pos += FONT_WIDTH; text++; } } void ui_selected_text_at(int layer, uint8_t color, uint8_t highlight, uint32_t x, uint32_t y, char *text) { ui_fill_area(layer, highlight, x, y, x + (FONT_WIDTH * strlen(text)), y + FONT_HEIGHT); ui_text_at(layer, color, x, y, text); } void image_at(int layer, const uint8_t *img, uint32_t x, uint32_t y, uint32_t size_x, uint32_t size_y) { uint32_t i, j; uint32_t pos = y * xres + x; uint8_t *screen = ui_get_screen(layer); for (i = 0; i < size_y; i++) { for (j = 0; j < size_x; j++) { screen[pos + i * xres + j] = img[i * size_x + j]; } } } /**** ****/ static char _ui_printn_res[20]; char *ui_printn(uint32_t n) { int i = 0; uint32_t div = 1000000000; int started = 0; while (div >= 10) { if ((n >= div) || started) { _ui_printn_res[i++] = '0' + n / div; n = n % div; started++; } div /= 10; } _ui_printn_res[i++] = '0' + n; _ui_printn_res[i] = '\0'; return (char *)(&_ui_printn_res[0]); } char *ui_printn2(uint32_t n) { _ui_printn_res[0] = '`'; _ui_printn_res[1] = '0' + (n % 10); if (n > 9) _ui_printn_res[0] = '0' + (n / 10); _ui_printn_res[2] = 0; return _ui_printn_res; } char *ui_printhex(uint8_t n) { uint8_t a = (n & 0xF0) >> 4; uint8_t b = (n & 0x0F); if (a < 10) _ui_printn_res[0] = a + '0'; else _ui_printn_res[0] = (a - 0xa) + 'A'; if (b < 10) _ui_printn_res[1] = b + '0'; else _ui_printn_res[1] = (b - 0xa) + 'A'; _ui_printn_res[2] = '\0'; return _ui_printn_res; } char *ui_printhex1(uint8_t n) { uint8_t a = (n & 0x0F); if (a < 10) _ui_printn_res[0] = a + '0'; else _ui_printn_res[0] = (a - 0xa) + 'A'; _ui_printn_res[1] = '\0'; return _ui_printn_res; } static void ui_switch_screen(int newscreen); static void force_redraw(void) { struct screen *s = screen_get_focus(); if (s && s->draw) s->draw(); } int ui_process_button_pressed(void) { int i; for (i = 0; i < N_BUTTONS; i++) { if (Input_status.b[i].pressed == 1) { Input_status.b[i].pressed = 0; return i; } } return -1; } void ui_draw_blocks(void) { ui_fill_area(0, BLACK, 420, 90, 440, 120); ui_fill_area(0, DARKRED, 420, 100, 440, 110); } struct point { int x, y; }; const struct point pot[] = { {-9, 17}, {-10, 17}, {-11, 16}, {-12, 16}, {-13, 15}, {-14, 14}, {-15, 13}, {-16, 12}, {-17, 10}, {-18, 8}, {-19, 6}, {-20, 0}, {-19, -6}, {-18, -8}, {-16, -12}, {-15, -13}, {-14, -14}, {-13, -15}, {-12, -16}, {-11, -16}, {-10, -17}, {-9, -17}, {-8, -18}, {-7, -18}, {-6, -19}, {-5, -19}, {-4, -19}, {-3, -19}, {-2, -19}, {-1, -19}, {0, -20}, {1, -19}, {2, -19}, {3, -19}, {4, -19}, {5, -19}, {6, -19}, {7, -18}, {8, -18}, {9, -17}, {10, -17}, {11, -16}, {12, -16}, {13, -15}, {14, -14}, {15, -13}, {16, -12}, {17, -10}, {18, -8}, {19, -6}, {20, 0}, {19, 6}, {18, 8}, {17, 10}, {16, 12}, {15, 13}, {14, 14}, {13, 15}, {12, 16}, {11, 16}, {10, 17}, {9, 17}, }; static void ui_run(uint16_t event) { if (event & EV_BUTTON) { int button = ui_process_button_pressed(); switch(button) { case 7: if (menu_on) { menu_on = 0; force_redraw(); } else { menu_on = 1; ui_redraw(EV_NONE); } break; } clear_event(EV_BUTTON); } } static struct screen *ui_get_screen_by_id(int id) { struct screen *s = screens(); while(s) { if (id == s->id) { return s; } s = s->next; } return NULL; } void ui_switch_screen(int newscreen) { struct screen *s = ui_get_screen_by_id(newscreen); if (s) screen_set_focus(s); } void ui_menu_redraw(uint16_t event) { static int selected; int button; int i; int n; n = screen_n_screens(); if (event & EV_BUTTON) { button = ui_process_button_pressed(); switch(button) { case 1: selected--; if (selected < 0) selected = n - 1; ui_redraw(EV_NONE); break; case 3: selected++; if (selected > n - 1) selected = 0; ui_redraw(EV_NONE); break; case 7: menu_on = 0; force_redraw(); break; default: menu_on = 0; ui_switch_screen(selected); } return; } ui_fill_area(0, BLACK, 400, 200, 480, 240); for (i = 0; i < n; i++) { if (i == selected) { ui_fill_area(0, WHITE, 400, 200 + i * 10, 480, 210 + i * 10); ui_text_at(0, PURPLE, 400, 200 + i*10, ui_get_screen_by_id(i)->name); } else { ui_text_at(0, WHITE, 400, 200 + i*10, ui_get_screen_by_id(i)->name); } } } void ui_redraw(uint16_t event) { struct screen *sc; if (menu_on) { ui_menu_redraw(event); } else { sc = screen_get_focus(); if (sc && sc->draw) sc->draw(); } } void ui_init(void) { int i; force_redraw(); } struct task task_ui = { .init = ui_init, .run = ui_run, .events = EV_BUTTON, .name = "ui" }; void ui_setup(void) { register_task(&task_ui); }