add gui system and demo screen with handled keyboard input
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/adc.h>
|
||||
#include "app_io.h"
|
||||
#include "pinout.h"
|
||||
|
||||
|
||||
void set_relays(bool one, bool two, bool three, bool four) {
|
||||
gpio_put(PIN_RE1, one);
|
||||
gpio_put(PIN_RE2, two);
|
||||
gpio_put(PIN_RE3, three);
|
||||
gpio_put(PIN_RE1, four);
|
||||
}
|
||||
|
||||
void open_valve(uint8_t num) {
|
||||
gpio_put(PIN_RE1, num == 1);
|
||||
gpio_put(PIN_RE2, num == 2);
|
||||
gpio_put(PIN_RE3, num == 3);
|
||||
gpio_put(PIN_RE4, num == 4);
|
||||
}
|
||||
|
||||
uint16_t moisture_read() {
|
||||
adc_select_input(ADC_NUM_MOISTURE);
|
||||
return adc_read();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*/
|
||||
|
||||
#ifndef ZAVLAHA_APP_IO_H
|
||||
#define ZAVLAHA_APP_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void set_relays(bool one, bool two, bool three, bool four);
|
||||
|
||||
void open_valve(uint8_t num);
|
||||
|
||||
uint16_t moisture_read();
|
||||
|
||||
#endif //ZAVLAHA_APP_IO_H
|
||||
+46
-35
@@ -4,11 +4,13 @@
|
||||
#include <hardware/i2c.h>
|
||||
#include <hardware/adc.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <hardware/sync.h>
|
||||
#include "pinout.h"
|
||||
#include "lcd.h"
|
||||
#include "ds_rtc.h"
|
||||
#include "ee.h"
|
||||
#include "lcd/lcdbuf.h"
|
||||
#include "screens/app_gui.h"
|
||||
|
||||
/*
|
||||
|
||||
@@ -49,37 +51,26 @@ void setup_output(uint num)
|
||||
gpio_set_function(num, GPIO_FUNC_SIO);
|
||||
}
|
||||
|
||||
#define KEYPAD_BUFFER_LEN 10
|
||||
static uint8_t keypad_buffer[KEYPAD_BUFFER_LEN];
|
||||
static uint8_t keypad_buffer_wp = 0;
|
||||
static uint8_t keypad_buffer_rp = 0;
|
||||
|
||||
// RX interrupt handler
|
||||
void irq_uart() {
|
||||
while (uart_is_readable(uart0)) {
|
||||
uint8_t ch = uart_getc(uart0);
|
||||
|
||||
// TODO do something useful
|
||||
if (uart_is_writable(uart0)) {
|
||||
uart_putc(uart0, ch);
|
||||
if (keypad_buffer[keypad_buffer_wp] == 0) {
|
||||
keypad_buffer[keypad_buffer_wp] = ch;
|
||||
keypad_buffer_wp++;
|
||||
if (keypad_buffer_wp >= KEYPAD_BUFFER_LEN) {
|
||||
keypad_buffer_wp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_relays(bool one, bool two, bool three, bool four) {
|
||||
gpio_put(PIN_RE1, one);
|
||||
gpio_put(PIN_RE2, two);
|
||||
gpio_put(PIN_RE3, three);
|
||||
gpio_put(PIN_RE1, four);
|
||||
}
|
||||
|
||||
void open_valve(uint num) {
|
||||
gpio_put(PIN_RE1, num == 1);
|
||||
gpio_put(PIN_RE2, num == 2);
|
||||
gpio_put(PIN_RE3, num == 3);
|
||||
gpio_put(PIN_RE4, num == 4);
|
||||
}
|
||||
|
||||
uint16_t moisture_read() {
|
||||
adc_select_input(ADC_NUM_MOISTURE);
|
||||
return adc_read();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// picotool binary info
|
||||
@@ -134,24 +125,44 @@ int main()
|
||||
|
||||
lcd_init();
|
||||
|
||||
struct LcdBuffer lcd;
|
||||
LcdBuffer_Init(&lcd, CGROM_A00, CGRAM_CZ);
|
||||
gui_init();
|
||||
|
||||
LcdBuffer_Write(&lcd, 0, 0, "ěščřŽÝÁÍ pyčo!");
|
||||
LcdBuffer_Flush(&lcd);
|
||||
|
||||
char buf[100];
|
||||
while (1) {
|
||||
struct rtc_time time;
|
||||
if (0 == rtc_get_time(&time)) {
|
||||
sprintf(buf, "čas: %02d:%02d:%02d", time.hour, time.minute, time.second);
|
||||
LcdBuffer_Write(&lcd, 2, 2, buf);
|
||||
for(;;) {
|
||||
uint32_t interrupts = save_and_disable_interrupts();
|
||||
GuiEvent event = GUI_EVENT_NONE;
|
||||
if (keypad_buffer[keypad_buffer_rp] != 0) {
|
||||
char ch = keypad_buffer[keypad_buffer_rp];
|
||||
keypad_buffer[keypad_buffer_rp] = 0;
|
||||
keypad_buffer_rp++;
|
||||
if (keypad_buffer_rp >= KEYPAD_BUFFER_LEN) {
|
||||
keypad_buffer_rp = 0;
|
||||
}
|
||||
event = ch; // there is 1:1 mapping for keypad ASCII
|
||||
}
|
||||
LcdBuffer_Flush(&lcd);
|
||||
restore_interrupts(interrupts);
|
||||
|
||||
sleep_ms(1000);
|
||||
gui_loop_iter(event);
|
||||
}
|
||||
|
||||
//
|
||||
// struct LcdBuffer lcd;
|
||||
// LcdBuffer_Init(&lcd, CGROM_A00, CGRAM_CZ);
|
||||
//
|
||||
// LcdBuffer_Write(&lcd, 0, 0, "ěščřŽÝÁÍ pyčo!");
|
||||
// LcdBuffer_Flush(&lcd);
|
||||
//
|
||||
// char buf[100];
|
||||
// while (1) {
|
||||
// struct rtc_time time;
|
||||
// if (0 == rtc_get_time(&time)) {
|
||||
// sprintf(buf, "čas: %02d:%02d:%02d", time.hour, time.minute, time.second);
|
||||
// LcdBuffer_Write(&lcd, 2, 2, buf);
|
||||
// }
|
||||
// LcdBuffer_Flush(&lcd);
|
||||
//
|
||||
// sleep_ms(1000);
|
||||
// }
|
||||
|
||||
#if 0
|
||||
|
||||
// while (1) {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "app_gui.h"
|
||||
#include "../lcd/lcdbuf.h"
|
||||
|
||||
struct State s_app = {};
|
||||
|
||||
struct LcdBuffer lcd = {};
|
||||
|
||||
/** Schedule paint (the screen func will be called with the PAINT event argument */
|
||||
void request_paint() {
|
||||
s_app.paint_needed = true;
|
||||
}
|
||||
|
||||
/** Draw the common overlay / HUD (with temperatures and heater status) */
|
||||
static void draw_common_overlay();
|
||||
|
||||
char stmp[100];
|
||||
|
||||
/** Main loop */
|
||||
void gui_init()
|
||||
{
|
||||
switch_screen(screen_home, true);
|
||||
s_app.last_tick_time = timestamp();
|
||||
|
||||
LcdBuffer_Init(&lcd, CGROM_A00, CGRAM_CZ);
|
||||
}
|
||||
|
||||
void gui_loop_iter(GuiEvent message) {
|
||||
uint32_t tickNow = timestamp();
|
||||
|
||||
// 10ms tick event
|
||||
if (tickNow - s_app.last_tick_time > 10) {
|
||||
s_app.screen(GUI_EVENT_SCREEN_TICK);
|
||||
s_app.last_tick_time = tickNow;
|
||||
}
|
||||
|
||||
if (message != GUI_EVENT_NONE) {
|
||||
s_app.screen(message);
|
||||
}
|
||||
|
||||
if (message >= 32) { // lazy shortcut so we dont have to list all of them
|
||||
// key was pressed
|
||||
input_sound_effect();
|
||||
}
|
||||
|
||||
if (s_app.paint_needed) {
|
||||
s_app.paint_needed = false;
|
||||
|
||||
draw_common_overlay();
|
||||
s_app.screen(GUI_EVENT_PAINT);
|
||||
|
||||
// If there is anything to print, do it
|
||||
LcdBuffer_Flush(&lcd);
|
||||
}
|
||||
}
|
||||
|
||||
/** Switch to a different screen handler.
|
||||
* If "init" is true, immediately call it with the init event. */
|
||||
void switch_screen(screen_t pScreen, bool init) {
|
||||
s_app.screen = pScreen;
|
||||
|
||||
LcdBuffer_Clear(&lcd);
|
||||
request_paint();
|
||||
|
||||
if (init) {
|
||||
pScreen(GUI_EVENT_SCREEN_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw GUI common to all screens */
|
||||
static void draw_common_overlay() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/** Play input sound effect if this is an input event */
|
||||
void input_sound_effect() {
|
||||
// TODO
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*/
|
||||
|
||||
#ifndef ZAVLAHA_APP_GUI_H
|
||||
#define ZAVLAHA_APP_GUI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <pico/time.h>
|
||||
#include "gui_event.h"
|
||||
#include "lcd/lcdbuf.h"
|
||||
|
||||
/// Temporary scratch buffer
|
||||
extern char stmp[100];
|
||||
|
||||
extern struct LcdBuffer lcd;
|
||||
|
||||
/**
|
||||
* Screen callback type. The event is either INIT, PAINT, or one of the input events.
|
||||
*/
|
||||
typedef void (*screen_t)(GuiEvent event);
|
||||
|
||||
|
||||
static inline uint32_t timestamp() {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
/** Input beep (push or knob turn) */
|
||||
void input_sound_effect();
|
||||
|
||||
|
||||
void gui_loop_iter(GuiEvent message);
|
||||
void gui_init();
|
||||
|
||||
/** Switch to a different screen. Handles initial push state handling (so release
|
||||
* does not cause a "click" event).
|
||||
*
|
||||
* @param pScreen - screen to switch to
|
||||
* @param init - call the INIT event immediately after
|
||||
*/
|
||||
void switch_screen(screen_t pScreen, bool init);
|
||||
|
||||
void request_paint();
|
||||
|
||||
// prototypes for screen handlers
|
||||
|
||||
void screen_home(GuiEvent event);
|
||||
// XXX other prototypes
|
||||
|
||||
struct State {
|
||||
/// Repaint was requested from the screen code
|
||||
bool paint_needed;
|
||||
|
||||
/// Pointer to the currently active screen func
|
||||
screen_t screen;
|
||||
|
||||
uint32_t last_tick_time;
|
||||
};
|
||||
|
||||
extern struct State s_app;
|
||||
|
||||
#endif //ZAVLAHA_APP_GUI_H
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by MightyPork on 2023/04/09.
|
||||
//
|
||||
|
||||
#ifndef ZAVLAHA_GUI_EVENT_H
|
||||
#define ZAVLAHA_GUI_EVENT_H
|
||||
|
||||
// sent through the notify queue
|
||||
typedef enum GuiEvent {
|
||||
/// No event, zero; This is a default value.
|
||||
GUI_EVENT_NONE = 0,
|
||||
/// Cause redraw
|
||||
GUI_EVENT_PAINT = 0,
|
||||
/// Used as the argument when initing a screen
|
||||
GUI_EVENT_SCREEN_INIT = 1,
|
||||
/// Time tick, used to carry timing to the screen functions.
|
||||
/// This tick has 10ms interval
|
||||
GUI_EVENT_SCREEN_TICK = 2,
|
||||
/// Keypad
|
||||
GUI_EVENT_KEY_0 = '0',
|
||||
GUI_EVENT_KEY_1,
|
||||
GUI_EVENT_KEY_2,
|
||||
GUI_EVENT_KEY_3,
|
||||
GUI_EVENT_KEY_4,
|
||||
GUI_EVENT_KEY_5,
|
||||
GUI_EVENT_KEY_6,
|
||||
GUI_EVENT_KEY_7,
|
||||
GUI_EVENT_KEY_8,
|
||||
GUI_EVENT_KEY_9,
|
||||
GUI_EVENT_KEY_A = 'A',
|
||||
GUI_EVENT_KEY_B,
|
||||
GUI_EVENT_KEY_C,
|
||||
GUI_EVENT_KEY_D,
|
||||
GUI_EVENT_KEY_STAR = '*',
|
||||
GUI_EVENT_KEY_HASH = '#',
|
||||
} GuiEvent;
|
||||
|
||||
#endif //ZAVLAHA_GUI_EVENT_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*/
|
||||
//
|
||||
// Created by MightyPork on 2023/04/09.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "app_gui.h"
|
||||
#include "gui_event.h"
|
||||
#include "ds_rtc.h"
|
||||
#include "app_io.h"
|
||||
|
||||
static uint32_t last_time = 0;
|
||||
static struct rtc_time rtc_time = {};
|
||||
static uint16_t moisture = 0;
|
||||
|
||||
static char showbuf[20];
|
||||
static uint8_t showbuf_wp = 0;
|
||||
|
||||
void screen_home(GuiEvent event)
|
||||
{
|
||||
uint32_t now = timestamp();
|
||||
uint32_t elapsed = now - last_time;
|
||||
|
||||
switch (event) {
|
||||
case GUI_EVENT_SCREEN_INIT:
|
||||
memset(showbuf, ' ', sizeof(showbuf));
|
||||
// pass
|
||||
case GUI_EVENT_SCREEN_TICK:
|
||||
if (elapsed >= 100) {
|
||||
last_time = now;
|
||||
rtc_get_time(&rtc_time);
|
||||
moisture = moisture_read();
|
||||
request_paint();
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_EVENT_PAINT:;
|
||||
LcdBuffer_Write(&lcd, 0, 0, showbuf);
|
||||
|
||||
sprintf(stmp, "Čas: %02d:%02d:%02d", rtc_time.hour, rtc_time.minute, rtc_time.second);
|
||||
LcdBuffer_Write(&lcd, 1, 0, stmp);
|
||||
|
||||
sprintf(stmp, "Vlhkost: %4d", moisture);
|
||||
LcdBuffer_Write(&lcd, 2, 0, stmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event >= 32) {
|
||||
showbuf[showbuf_wp++] = event;
|
||||
if (showbuf_wp == 20) {
|
||||
showbuf_wp = 0;
|
||||
}
|
||||
request_paint();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user