Advanced Distributed Systems module at HSLU
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

455 lines
15 KiB

/*
* Copyright (c) 2019, Erich Styger
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "platform.h"
#if PL_CONFIG_USE_GUI
#include "lv.h"
#include "LittlevGL/lvgl/lvgl.h"
#include "McuGDisplaySSD1306.h"
#include "McuSSD1306.h"
#include "McuRB.h"
#include <string.h> /* for memset() */
#include "McuShell.h"
#include "McuRTOS.h"
#include "lcd.h"
#if PL_CONFIG_USE_TOASTER
#include "toaster.h"
#endif
#if PL_CONFIG_USE_GUI_SCREENSAVER
static TimerHandle_t timerHndlLcdTimeout;
#endif
static McuRB_Handle_t ringBufferHndl;
#if PL_CONFIG_USE_GUI_SCREENSAVER
static void vTimerCallbackLCDExpired(TimerHandle_t pxTimer) {
/* timer callback to turn off LCD backlight */
(void)pxTimer; /* not used */
#if PL_CONFIG_USE_TOASTER
TOASTER_Show();
#else
McuSSD1306_DisplayOn(false);
#endif
}
#endif
static void KeyPressForLCD(void) {
#if PL_CONFIG_USE_GUI_SCREENSAVER
/* called for each key press. It turns on the LCD if it is dormant or resets the LCD backlight timeout timer */
if (xTimerIsTimerActive(timerHndlLcdTimeout)==pdFALSE) {
/* timer is not active: start it */
if (xTimerStart(timerHndlLcdTimeout, 0)!=pdPASS) {
for(;;); /* failure!?! */
}
#if PL_CONFIG_USE_TOASTER
TOASTER_StopScreenSaver();
/* and turn LCD on */
#else
McuSSD1306_DisplayOn(true);
#endif
} else {
if (xTimerReset(timerHndlLcdTimeout, 0)!=pdPASS) { /* reset timer, e.g. after key press or user input */
for(;;); /* failure?!? */
}
}
#endif
}
static lv_indev_t *inputDevicePtr;
lv_indev_t *LV_GetInputDevice(void) {
return inputDevicePtr;
}
/* Flush the content of the internal buffer the specific area on the display
* You can use DMA or any hardware acceleration to do this operation in the background but
* 'lv_flush_ready()' has to be called when finished
* This function is required only when LV_VDB_SIZE != 0 in lv_conf.h*/
static void myDispFlush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
int32_t x, y;
int32_t x1, y1, x2, y2;
x1 = area->x1;
y1 = area->y1;
x2 = area->x2;
y2 = area->y2;
for(y = y1; y <= y2; y++) {
for(x = x1; x <= x2; x++) {
/* Put a pixel to the display. */
LCD_SetPixel(x, y, color_p->full);
color_p++;
}
}
LCD_UpdateRegion(x1, y1, x2-x1+1, y2-y1+1);
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
#if 0
/* Read the touchpad and store it in 'data'
* Return false if no more data read; true for ready again */
static bool ex_tp_read(lv_indev_data_t * data) {
/* Read the touchpad */
int x=0, y=0, res;
bool pressed;
res = TOUCH_Poll(&pressed, &x, &y);
if (res==1 && pressed) {
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
data->point.x = x;
data->point.y = y;
return false; /*false: no more data to read because we are no buffering*/
}
#endif
void LV_Task(void) {
/* Periodically call this function.
* The timing is not critical but should be between 1..10 ms */
lv_task_handler();
}
/* called for push button events from Events.c */
void LV_ButtonEvent(uint8_t keys, uint16_t eventMask) {
uint16_t buttonInfo;
if (keys&LV_BTN_MASK_CENTER) {
buttonInfo = LV_BTN_MASK_CENTER | eventMask;
McuRB_Put(ringBufferHndl, &buttonInfo);
} else if (keys&LV_BTN_MASK_RIGHT) {
buttonInfo = LV_BTN_MASK_RIGHT | eventMask;
McuRB_Put(ringBufferHndl, &buttonInfo);
} else if (keys&LV_BTN_MASK_DOWN) {
buttonInfo = LV_BTN_MASK_DOWN | eventMask;
McuRB_Put(ringBufferHndl, &buttonInfo);
} else if (keys&LV_BTN_MASK_UP) {
buttonInfo = LV_BTN_MASK_UP | eventMask;
McuRB_Put(ringBufferHndl, &buttonInfo);
} else if (keys&LV_BTN_MASK_LEFT) {
buttonInfo = LV_BTN_MASK_LEFT | eventMask;
McuRB_Put(ringBufferHndl, &buttonInfo);
}
}
static uint8_t MapKeyOrientation(uint8_t key) {
switch(McuGDisplaySSD1306_GetDisplayOrientation()) {
case McuSSD1306_CONFIG_ORIENTATION_PORTRAIT:
switch(key) {
case LV_BTN_MASK_LEFT:
key = LV_BTN_MASK_UP;
break;
case LV_BTN_MASK_RIGHT:
key = LV_BTN_MASK_DOWN;
break;
case LV_BTN_MASK_UP:
key = LV_BTN_MASK_RIGHT;
break;
case LV_BTN_MASK_DOWN:
key = LV_BTN_MASK_LEFT;
break;
case LV_BTN_MASK_CENTER:
key = LV_BTN_MASK_CENTER;
break;
default:
key = 0; /* error case? */
break;
} /* switch */
break;
case McuSSD1306_CONFIG_ORIENTATION_PORTRAIT180:
switch(key) {
case LV_BTN_MASK_LEFT:
key = LV_BTN_MASK_DOWN;
break;
case LV_BTN_MASK_RIGHT:
key = LV_BTN_MASK_UP;
break;
case LV_BTN_MASK_UP:
key = LV_BTN_MASK_LEFT;
break;
case LV_BTN_MASK_DOWN:
key = LV_BTN_MASK_RIGHT;
break;
case LV_BTN_MASK_CENTER:
key = LV_BTN_MASK_CENTER;
break;
default:
key = 0; /* error case? */
break;
} /* switch */
break;
case McuSSD1306_CONFIG_ORIENTATION_LANDSCAPE180:
switch(key) {
case LV_BTN_MASK_LEFT:
key = LV_BTN_MASK_RIGHT;
break;
case LV_BTN_MASK_RIGHT:
key = LV_BTN_MASK_LEFT;
break;
case LV_BTN_MASK_UP:
key = LV_BTN_MASK_DOWN;
break;
case LV_BTN_MASK_DOWN:
key = LV_BTN_MASK_UP;
break;
case LV_BTN_MASK_CENTER:
key = LV_BTN_MASK_CENTER;
break;
default:
key = 0; /* error case? */
break;
} /* switch */
break;
case McuSSD1306_CONFIG_ORIENTATION_LANDSCAPE:
switch(key) {
case LV_BTN_MASK_LEFT:
key = LV_BTN_MASK_LEFT;
break;
case LV_BTN_MASK_RIGHT:
key = LV_BTN_MASK_RIGHT;
break;
case LV_BTN_MASK_UP:
key = LV_BTN_MASK_UP;
break;
case LV_BTN_MASK_DOWN:
key = LV_BTN_MASK_DOWN;
break;
case LV_BTN_MASK_CENTER:
key = LV_BTN_MASK_CENTER;
break;
default:
key = 0; /* error case? */
break;
} /* switch */
break;
default:
key = 0; /* error case? */
break;
} /* switch */
return key;
}
#if 0
/*
* To use a keyboard:
USE_LV_GROUP has to be enabled in lv_conf.h
An object group has to be created: lv_group_create() and objects have to be added: lv_group_add_obj()
The created group has to be assigned to an input device: lv_indev_set_group(my_indev, group1);
Use LV_GROUP_KEY_... to navigate among the objects in the group
*/
static bool keyboard_read(lv_indev_data_t *data) {
uint16_t keyData;
memset(data, 0, sizeof(lv_indev_data_t)); /* initialize all fields */
data->state = LV_INDEV_STATE_REL; /* by default, not pressed */
if (McuRB_NofElements(ringBufferHndl)==0) {
return false; /* no data present */
}
if (McuRB_Get(ringBufferHndl, &keyData)!=ERR_OK) {
return false; /* we had data in the buffer, but now not anymore? something went wrong! */
}
KeyPressForLCD();
if (keyData&(LV_MASK_PRESSED|LV_MASK_PRESSED_LONG)) {
data->state = LV_INDEV_STATE_PR;
} else if (keyData&(LV_MASK_RELEASED|LV_MASK_RELEASED_LONG)) {
data->state = LV_INDEV_STATE_REL;
}
data->key = MapKeyOrientation(keyData&0xff);
return McuRB_NofElements(ringBufferHndl)!=0; /* return true if we have more data */
}
#endif
static bool encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
uint16_t keyData;
(void)indev_drv; /* not used */
memset(data, 0, sizeof(lv_indev_data_t)); /* initialize all fields */
data->state = LV_INDEV_STATE_REL; /* by default, not pressed */
if (McuRB_NofElements(ringBufferHndl)==0) {
return false; /* no data present */
}
if (McuRB_Get(ringBufferHndl, &keyData)!=ERR_OK) {
return false; /* we had data in the buffer, but now not anymore? something went wrong! */
}
KeyPressForLCD(); /* inform LCD timer that there is a user action */
data->state = LV_INDEV_STATE_REL; /* default state */
keyData = (keyData&0xff00) | MapKeyOrientation(keyData&0xff);
/* keys are changing only enc_diff, except ENTER/CENTER/PUSH which sets the LV_INDEV_STATE_PR state */
switch(keyData&0xff) {
case LV_BTN_MASK_LEFT:
if (keyData&(LV_MASK_PRESSED)) {
data->enc_diff = -1;
McuShell_SendStr((uint8_t*)"left pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->enc_diff = -1;
McuShell_SendStr((uint8_t*)"left long pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED_LONG)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"left long released\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"left released\r\n", McuShell_GetStdio()->stdOut);
}
break;
case LV_BTN_MASK_RIGHT:
if (keyData&(LV_MASK_PRESSED)) {
data->enc_diff = 1;
McuShell_SendStr((uint8_t*)"right pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->enc_diff = 1;
McuShell_SendStr((uint8_t*)"right long pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED_LONG)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"right long released\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"right released\r\n", McuShell_GetStdio()->stdOut);
}
break;
case LV_BTN_MASK_UP:
if (keyData&(LV_MASK_PRESSED)) {
data->enc_diff = -1;
McuShell_SendStr((uint8_t*)"up pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->enc_diff = -1;
McuShell_SendStr((uint8_t*)"up long pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED_LONG)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"up long released\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"up released\r\n", McuShell_GetStdio()->stdOut);
}
break;
case LV_BTN_MASK_DOWN:
if (keyData&(LV_MASK_PRESSED)) {
data->enc_diff = 1;
McuShell_SendStr((uint8_t*)"down pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->enc_diff = 1;
McuShell_SendStr((uint8_t*)"down long pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED_LONG)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"down long released\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED)) {
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"down released\r\n", McuShell_GetStdio()->stdOut);
}
break;
case LV_BTN_MASK_CENTER:
if (keyData&(LV_MASK_PRESSED)) {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"center pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->state = LV_INDEV_STATE_PR;
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"center long pressed\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED_LONG)) {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"center long released\r\n", McuShell_GetStdio()->stdOut);
} else if (keyData&(LV_MASK_RELEASED)) {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = 0;
McuShell_SendStr((uint8_t*)"center released\r\n", McuShell_GetStdio()->stdOut);
}
break;
#if 0
case LV_BTN_MASK_NEXT:
if (keyData&(LV_MASK_PRESSED)) {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = 1;
} else if (keyData&(LV_MASK_PRESSED_LONG)) {
data->state = LV_INDEV_STATE_PR;
data->enc_diff = 0;
} else {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = 0;
}
break;
case LV_BTN_MASK_PREV:
if (keyData&(LV_MASK_PRESSED_LONG)) {
data->state = LV_INDEV_STATE_PR;
data->enc_diff = 0;
} else {
data->state = LV_INDEV_STATE_REL;
data->enc_diff = -1;
}
break;
#endif
default:
return false; /* error case? */
} /* switch */
return McuRB_NofElements(ringBufferHndl)!=0; /* return true if we have more data */
}
/* A static or global variable to store the buffers*/
static lv_disp_buf_t disp_buf;
/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[LV_CONFIG_DISPLAY_WIDTH * 10];
static lv_color_t buf_2[LV_CONFIG_DISPLAY_WIDTH * 10];
void LV_Init(void) {
lv_disp_drv_t disp_drv;
lv_init();
lv_disp_drv_init(&disp_drv);
lv_disp_buf_init(&disp_buf, buf_1, buf_2, LV_CONFIG_DISPLAY_WIDTH*10);
disp_drv.buffer = &disp_buf;
/*Set up the functions to access to your display*/
disp_drv.flush_cb = myDispFlush; /*Used in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
/*************************
* Input device interface
*************************/
lv_indev_drv_t indev_drv; /*Descriptor of an input device driver*/
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
#if 0 /* touch pad */
indev_drv.type = LV_INDEV_TYPE_POINTER; /*The touchpad is pointer type device*/
indev_drv.read = ex_tp_read; /*Library ready your touchpad via this function*/
#elif 1
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_read;
#else /* keyboard input */
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read = keyboard_read;
#endif
inputDevicePtr = lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
#if PL_CONFIG_USE_GUI_SCREENSAVER
timerHndlLcdTimeout = xTimerCreate(
"timerLCD", /* name */
pdMS_TO_TICKS(15*1000), /* period/time */
pdFALSE, /* auto reload */
(void*)1, /* timer ID */
vTimerCallbackLCDExpired); /* callback */
if (timerHndlLcdTimeout==NULL) {
for(;;); /* failure! */
}
if (xTimerStart(timerHndlLcdTimeout, 0)!=pdPASS) {
for(;;); /* failure!?! */
}
#endif
McuRB_Config_t config;
McuRB_GetDefaultconfig(&config);
config.elementSize = 2;
config.nofElements = 16;
ringBufferHndl = McuRB_InitRB(&config);
}
#endif /* PL_CONFIG_USE_GUI */