363 lines
8.5 KiB
C
363 lines
8.5 KiB
C
|
/*
|
||
|
* Copyright (C) 2023 Daniele Lacamera <root@danielinux.net>
|
||
|
*
|
||
|
* 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#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);
|
||
|
}
|
||
|
|