From 2cfca62b0072a356e38d39b1dff01bce927f5376 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Thu, 24 Sep 2020 12:45:24 +0200 Subject: [PATCH] Driver for SDL-based display emulator, updated lcd.h documentation --- openrtx/include/interfaces/lcd.h | 20 ++- platform/drivers/display/display_libSDL.c | 142 ++++++++++++++++++++++ tests/platform/.keep | 1 - tests/platform/display_test_SDL.c | 80 ++++++++++++ 4 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 platform/drivers/display/display_libSDL.c delete mode 100644 tests/platform/.keep create mode 100644 tests/platform/display_test_SDL.c diff --git a/openrtx/include/interfaces/lcd.h b/openrtx/include/interfaces/lcd.h index 2f989649..040f386d 100644 --- a/openrtx/include/interfaces/lcd.h +++ b/openrtx/include/interfaces/lcd.h @@ -15,16 +15,14 @@ * along with this program; if not, see * ***************************************************************************/ -#ifndef LCH_H -#define LCH_H +#ifndef LCD_H +#define LCD_H #include #include /** - * Low level driver for Tytera MD380 display, which is has an HX8302-A controller. - * Actually, no datasheet for the display controller exists on the internet, - * however a fairly compatible chip, for which datasheet exists, is the HX8353-E. + * Standard interface for all low-level display drivers. * *********************** HOW TO MANAGE FRAMEBUFFER ***************************** * @@ -46,9 +44,9 @@ */ /** - * This function initialises the display, configures TIM8 for backlight control - * and allocates framebuffer on the heap. After initialisation, backlight is - * set to zero. + * This function initialises the display, configures backlight control and + * allocates framebuffer on the heap. After initialisation, backlight is set + * to zero. * NOTE: framebuffer allocation is the first operation performed, if fails an * error message is printed on the virtual COM port and this function returns * prematurely, without configuring the display and the backlight timer. Thus, a @@ -57,8 +55,8 @@ void lcd_init(); /** - * When called, this function turns off backlight, shuts down TIM8 and - * deallocates the framebuffer. + * When called, this function turns off backlight, shuts down backlight control + * and deallocates the framebuffer. */ void lcd_terminate(); @@ -118,4 +116,4 @@ bool lcd_renderingInProgress(); */ uint16_t *lcd_getFrameBuffer(); -#endif /* LCH_H */ +#endif /* LCD_H */ diff --git a/platform/drivers/display/display_libSDL.c b/platform/drivers/display/display_libSDL.c new file mode 100644 index 00000000..71f30706 --- /dev/null +++ b/platform/drivers/display/display_libSDL.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2020 by Federico Izzo IU2NUO, Niccolò Izzo IU2KIN and * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +/** + * This driver provides an lcd screen emulator to allow UI development and + * testing on a x86/x64 computer. + * Graphics control is provided through SDL2 library, you need to have the SDL2 + * development library installed on your machine to compile and run code using + * this driver. + */ + +#include "lcd.h" +#include +#include +#include +#undef main /* necessary to avoid conflicts with SDL_main */ + +/* + * Screen dimensions, adjust basing on the size of the screen you need to + * emulate + */ +#define SCREEN_WIDTH 160 +#define SCREEN_HEIGHT 128 + +SDL_Window *window; +SDL_Surface *renderSurface; +uint16_t *frameBuffer; +bool inProgress; + +void lcd_init() +{ + if(SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("SDL video init error!!\n"); + + } + else + { + + window = SDL_CreateWindow("", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + SCREEN_WIDTH,SCREEN_HEIGHT, + SDL_WINDOW_SHOWN); + + renderSurface = SDL_GetWindowSurface(window); + SDL_FillRect(renderSurface,NULL,0xFFFFFF); + + unsigned int scrSize = SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint16_t); + frameBuffer = (uint16_t *)(malloc(scrSize)); + memset(frameBuffer, 0xFFFF, scrSize); + inProgress = false; + } +} + +void lcd_terminate() +{ + SDL_DestroyWindow(window); +} + +uint16_t lcd_screenWidth() +{ + return SCREEN_WIDTH; +} + +uint16_t lcd_screenHeight() +{ + return SCREEN_HEIGHT; +} + +void lcd_setBacklightLevel(uint8_t level) +{ + printf("Backlight level set to %d\n", level); +} + +void lcd_renderRows(uint8_t startRow, uint8_t endRow) +{ + Uint32 *pixels = (Uint32*)renderSurface->pixels; + inProgress = true; + + for(int x = 0; x < SCREEN_WIDTH; x++) + { + for(int y = startRow; y < endRow; y++) + { + /* + * SDL pixel format is ARGB8888, while ours is RGB565, thus we need + * to do some conversions when writing framebuffer content to the + * window. We also set alpha value to its maximum. + */ + uint32_t r = (frameBuffer[x + y*SCREEN_WIDTH] & 0xF800) >> 11; + uint32_t g = (frameBuffer[x + y*SCREEN_WIDTH] & 0x07E0) >> 5; + uint32_t b = (frameBuffer[x + y*SCREEN_WIDTH] & 0x001F) & 0x1F; + + /* + * Here we do conversions by multiplying by some scaling factors, + * we use ints just because the precision of floats is not really + * needed. + * Conversion factors: + * - five bit to eight bit: 8.226 + * - six bit to eight bit: 4.0476 + */ + r = (r * 8) + (r * 226)/1000; + g = (g * 4) + (g * 476)/10000; + b = (b * 8) + (b * 226)/1000; + + pixels[x + y*SCREEN_WIDTH] = 0xFF000000 | (r << 16) | (g << 8) | b; + } + } + + inProgress = false; + SDL_UpdateWindowSurface(window); +} + +void lcd_render() +{ + lcd_renderRows(0, SCREEN_HEIGHT); +} + +bool lcd_renderingInProgress() +{ + return inProgress; +} + +uint16_t *lcd_getFrameBuffer() +{ + return frameBuffer; +} diff --git a/tests/platform/.keep b/tests/platform/.keep deleted file mode 100644 index 8d1c8b69..00000000 --- a/tests/platform/.keep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/platform/display_test_SDL.c b/tests/platform/display_test_SDL.c new file mode 100644 index 00000000..62b17ef9 --- /dev/null +++ b/tests/platform/display_test_SDL.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2020 by Federico Izzo IU2NUO, Niccolò Izzo IU2KIN and * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +/** + * Testing module for SDL-based display driver, serves both to check that + * everything is fine and as a simple example on how to use both the driver and + * the SDL platform. + * + * To adjust screen dimensions you have to adjust the corresponding constants in + * the driver source file. + */ + +#include "lcd.h" +#include +#include +#include +#include +#undef main //necessary to avoid conflicts with SDL_main + + +void drawRect(int x, int y, int width, int height, uint16_t color) +{ + int x_max = x + width; + int y_max = y + height; + uint16_t *buf = lcd_getFrameBuffer(); + + for(int i=y; i < y_max; i++) + { + for(int j=x; j < x_max; j++) + { + buf[j + i*lcd_screenWidth()] = color; + } + } +} + +int main() +{ + lcd_init(); + lcd_setBacklightLevel(254); + + /* Horizontal red line */ + drawRect(0, 10, lcd_screenWidth(), 20, 0xF800); + + /* Vertical blue line */ + drawRect(10, 0, 20, lcd_screenHeight(), 0x001F); + + /* Vertical green line */ + drawRect(80, 0, 20, lcd_screenHeight(), 0x07e0); + + /* + * Use SDL event listener to check if window close button has been pressed, + * in this case quit. + */ + SDL_Event eventListener; + + while(1) + { + lcd_render(); + SDL_PollEvent(&eventListener); + if(eventListener.type == SDL_QUIT) break; + } + + lcd_terminate(); + return 0; +}