Implement an SDL main loop inside the Main Thread
This commit is contained in:
parent
51acccaec2
commit
82699f3d07
|
|
@ -30,6 +30,7 @@ openrtx_src = ['openrtx/src/state.c',
|
||||||
'openrtx/src/input.c',
|
'openrtx/src/input.c',
|
||||||
'openrtx/src/calibUtils.c',
|
'openrtx/src/calibUtils.c',
|
||||||
'openrtx/src/queue.c',
|
'openrtx/src/queue.c',
|
||||||
|
'openrtx/src/chan.c',
|
||||||
'openrtx/src/rtx/rtx.cpp',
|
'openrtx/src/rtx/rtx.cpp',
|
||||||
'openrtx/src/rtx/OpMode_FM.cpp',
|
'openrtx/src/rtx/OpMode_FM.cpp',
|
||||||
'openrtx/src/rtx/OpMode_M17.cpp',
|
'openrtx/src/rtx/OpMode_M17.cpp',
|
||||||
|
|
@ -214,6 +215,7 @@ mk22fn512_def = {'_POSIX_PRIORITY_SCHEDULING':''}
|
||||||
## Linux
|
## Linux
|
||||||
##
|
##
|
||||||
linux_platform_src = ['platform/targets/linux/emulator/emulator.c',
|
linux_platform_src = ['platform/targets/linux/emulator/emulator.c',
|
||||||
|
'platform/targets/linux/emulator/sdl_engine.c',
|
||||||
'platform/drivers/display/display_libSDL.c',
|
'platform/drivers/display/display_libSDL.c',
|
||||||
'platform/drivers/keyboard/keyboard_linux.c',
|
'platform/drivers/keyboard/keyboard_linux.c',
|
||||||
'platform/drivers/NVM/nvmem_linux.c',
|
'platform/drivers/NVM/nvmem_linux.c',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2021 by Alessio Caiazza IU5BON *
|
||||||
|
* *
|
||||||
|
* 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 <http://www.gnu.org/licenses/> *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef CHAN_H
|
||||||
|
#define CHAN_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* chan_t is an unbuffered synchronization channel.
|
||||||
|
* Both reader and writer are blocked untill the data is exchanged.
|
||||||
|
*/
|
||||||
|
typedef struct chan_t
|
||||||
|
{
|
||||||
|
pthread_mutex_t m_meta;
|
||||||
|
pthread_mutex_t m_read;
|
||||||
|
pthread_mutex_t m_write;
|
||||||
|
pthread_cond_t c_reader;
|
||||||
|
pthread_cond_t c_writer;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
bool closed;
|
||||||
|
bool reader;
|
||||||
|
bool writer;
|
||||||
|
}
|
||||||
|
chan_t;
|
||||||
|
|
||||||
|
void chan_init(chan_t *c);
|
||||||
|
void chan_send(chan_t *c, void *data);
|
||||||
|
void chan_recv(chan_t *c, void **data);
|
||||||
|
bool chan_can_recv(chan_t *c);
|
||||||
|
bool chan_can_send(chan_t *c);
|
||||||
|
void chan_close(chan_t *c);
|
||||||
|
void chan_terminate(chan_t *c);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2021 by Alessio Caiazza IU5BON *
|
||||||
|
* *
|
||||||
|
* 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 <http://www.gnu.org/licenses/> *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "chan.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void chan_init(chan_t *c)
|
||||||
|
{
|
||||||
|
if(c == NULL) return;
|
||||||
|
|
||||||
|
pthread_mutex_init(&c->m_meta, NULL);
|
||||||
|
pthread_mutex_init(&c->m_read, NULL);
|
||||||
|
pthread_mutex_init(&c->m_write, NULL);
|
||||||
|
|
||||||
|
pthread_cond_init(&c->c_reader, NULL);
|
||||||
|
pthread_cond_init(&c->c_writer, NULL);
|
||||||
|
|
||||||
|
c->reader = false;
|
||||||
|
c->writer = false;
|
||||||
|
c->closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chan_send(chan_t *c, void *data)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&c->m_write);
|
||||||
|
pthread_mutex_lock(&c->m_meta);
|
||||||
|
|
||||||
|
if(c->closed)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
pthread_mutex_unlock(&c->m_write);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->data = data;
|
||||||
|
c->writer = true;
|
||||||
|
|
||||||
|
// notify the waiting reader that data is ready
|
||||||
|
if (c->reader)
|
||||||
|
{
|
||||||
|
pthread_cond_signal(&c->c_writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until data is consumed
|
||||||
|
pthread_cond_wait(&c->c_reader, &c->m_meta);
|
||||||
|
c->writer = false;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
pthread_mutex_unlock(&c->m_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chan_recv(chan_t *c, void **data)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&c->m_read);
|
||||||
|
pthread_mutex_lock(&c->m_meta);
|
||||||
|
|
||||||
|
// wait for a writer
|
||||||
|
while(!c->closed && !c->writer)
|
||||||
|
{
|
||||||
|
c->reader = true;
|
||||||
|
pthread_cond_wait(&c->c_writer, &c->m_meta);
|
||||||
|
c->reader = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c->closed)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
pthread_mutex_unlock(&c->m_read);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
*data = c->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify the waiting writer that the reader consumed the data
|
||||||
|
pthread_cond_signal(&c->c_reader);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
pthread_mutex_unlock(&c->m_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool chan_can_recv(chan_t *c)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&c->m_meta);
|
||||||
|
bool can_receive = c->writer;
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
|
||||||
|
return can_receive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool chan_can_send(chan_t *c)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&c->m_meta);
|
||||||
|
bool can_send = c->reader;
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
|
||||||
|
return can_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chan_close(chan_t *c)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&c->m_meta);
|
||||||
|
if (!c->closed)
|
||||||
|
{
|
||||||
|
c->closed = true;
|
||||||
|
pthread_cond_broadcast(&c->c_reader);
|
||||||
|
pthread_cond_broadcast(&c->c_writer);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&c->m_meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chan_terminate(chan_t *c)
|
||||||
|
{
|
||||||
|
chan_close(c);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&c->m_write);
|
||||||
|
pthread_mutex_destroy(&c->m_read);
|
||||||
|
pthread_mutex_destroy(&c->m_meta);
|
||||||
|
|
||||||
|
pthread_cond_destroy(&c->c_writer);
|
||||||
|
pthread_cond_destroy(&c->c_reader);
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,9 @@
|
||||||
#include <interfaces/graphics.h>
|
#include <interfaces/graphics.h>
|
||||||
#include <interfaces/delays.h>
|
#include <interfaces/delays.h>
|
||||||
#include <hwconfig.h>
|
#include <hwconfig.h>
|
||||||
|
#ifdef PLATFORM_LINUX
|
||||||
|
#include <emulator/sdl_engine.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void *ui_task(void *arg);
|
extern void *ui_task(void *arg);
|
||||||
|
|
||||||
|
|
@ -74,6 +77,16 @@ int main(void)
|
||||||
// Create OpenRTX threads
|
// Create OpenRTX threads
|
||||||
create_threads();
|
create_threads();
|
||||||
|
|
||||||
|
#ifndef PLATFORM_LINUX
|
||||||
// Jump to the UI task
|
// Jump to the UI task
|
||||||
ui_task(NULL);
|
ui_task(NULL);
|
||||||
|
#else
|
||||||
|
// macOS requires SDL main loop to run on the main thread.
|
||||||
|
// Here we create a new thread for ui_task and utilize the masin thread for
|
||||||
|
// the SDL main loop.
|
||||||
|
pthread_t ui_thread;
|
||||||
|
pthread_create(&ui_thread, NULL, ui_task, NULL);
|
||||||
|
|
||||||
|
sdl_task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,6 @@
|
||||||
#include <interfaces/gps.h>
|
#include <interfaces/gps.h>
|
||||||
#include <gps.h>
|
#include <gps.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef PLATFORM_LINUX
|
|
||||||
#include <emulator.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Mutex for concurrent access to state variable */
|
/* Mutex for concurrent access to state variable */
|
||||||
pthread_mutex_t state_mutex;
|
pthread_mutex_t state_mutex;
|
||||||
|
|
@ -77,10 +73,6 @@ void *ui_task(void *arg)
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
#ifdef PLATFORM_LINUX
|
|
||||||
emulator_process_sdl_events();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Read from the keyboard queue (returns 0 if no message is present)
|
// Read from the keyboard queue (returns 0 if no message is present)
|
||||||
// Copy keyboard_t keys from received void * pointer msg
|
// Copy keyboard_t keys from received void * pointer msg
|
||||||
event_t event;
|
event_t event;
|
||||||
|
|
|
||||||
|
|
@ -25,139 +25,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <interfaces/display.h>
|
#include <interfaces/display.h>
|
||||||
|
#include <emulator/sdl_engine.h>
|
||||||
|
#include <chan.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#undef main /* necessary to avoid conflicts with SDL_main */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Screen dimensions, adjust basing on the size of the screen you need to
|
|
||||||
* emulate
|
|
||||||
*/
|
|
||||||
#ifndef SCREEN_WIDTH
|
|
||||||
#define SCREEN_WIDTH 160
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SCREEN_HEIGHT
|
|
||||||
#define SCREEN_HEIGHT 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PIX_FMT_RGB565
|
|
||||||
#define PIXEL_FORMAT SDL_PIXELFORMAT_RGB565
|
|
||||||
#define PIXEL_SIZE uint16_t
|
|
||||||
#else
|
|
||||||
#define PIXEL_FORMAT SDL_PIXELFORMAT_ARGB8888
|
|
||||||
#define PIXEL_SIZE uint32_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDL_Renderer *renderer; /* SDL renderer */
|
|
||||||
SDL_Window *window; /* SDL window */
|
|
||||||
SDL_Texture *displayTexture; /* SDL rendering surface */
|
|
||||||
void *frameBuffer; /* Pointer to framebuffer */
|
void *frameBuffer; /* Pointer to framebuffer */
|
||||||
bool inProgress; /* Flag to signal when rendering is in progress */
|
bool inProgress; /* Flag to signal when rendering is in progress */
|
||||||
|
|
||||||
|
/*
|
||||||
int screenshot_display(const char *filename)
|
* SDL main loop syncronization
|
||||||
{
|
*/
|
||||||
//https://stackoverflow.com/a/48176678
|
bool sdl_ready = false; /* Flag to signal the sdl main loop is running */
|
||||||
//user1902824
|
extern chan_t fb_sync; /* Shared channel to send a frame buffer update */
|
||||||
//modified to keep renderer and display texture references in the body rather than as a parameter
|
|
||||||
SDL_Renderer * ren = renderer;
|
|
||||||
SDL_Texture * tex = displayTexture;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
|
|
||||||
SDL_Texture *ren_tex;
|
|
||||||
SDL_Surface *surf;
|
|
||||||
int st;
|
|
||||||
int w;
|
|
||||||
int h;
|
|
||||||
int format;
|
|
||||||
void *pixels;
|
|
||||||
|
|
||||||
pixels = NULL;
|
|
||||||
surf = NULL;
|
|
||||||
ren_tex = NULL;
|
|
||||||
format = SDL_PIXELFORMAT_RGBA32;
|
|
||||||
|
|
||||||
/* Get information about texture we want to save */
|
|
||||||
st = SDL_QueryTexture(tex, NULL, NULL, &w, &h);
|
|
||||||
if (st != 0)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed querying texture: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ren_tex = SDL_CreateTexture(ren, format, SDL_TEXTUREACCESS_TARGET, w, h);
|
|
||||||
if (!ren_tex)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed creating render texture: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize our canvas, then copy texture to a target whose pixel data we
|
|
||||||
* can access
|
|
||||||
*/
|
|
||||||
st = SDL_SetRenderTarget(ren, ren_tex);
|
|
||||||
if (st != 0)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed setting render target: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00);
|
|
||||||
SDL_RenderClear(ren);
|
|
||||||
st = SDL_RenderCopy(ren, tex, NULL, NULL);
|
|
||||||
if (st != 0)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed copying texture data: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
/* Create buffer to hold texture data and load it */
|
|
||||||
pixels = malloc(w * h * SDL_BYTESPERPIXEL(format));
|
|
||||||
if (!pixels)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed allocating memory\n");
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
st = SDL_RenderReadPixels(ren, NULL, format, pixels, w * SDL_BYTESPERPIXEL(format));
|
|
||||||
if (st != 0)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed reading pixel data: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
/* Copy pixel data over to surface */
|
|
||||||
surf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(format), w * SDL_BYTESPERPIXEL(format), format);
|
|
||||||
if (!surf)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed creating new surface: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
/* Save result to an image */
|
|
||||||
st = SDL_SaveBMP(surf, filename);
|
|
||||||
if (st != 0)
|
|
||||||
{
|
|
||||||
SDL_Log("Failed saving image: %s\n", SDL_GetError());
|
|
||||||
err++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
SDL_Log("Saved texture as BMP to \"%s\"\n", filename);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
SDL_FreeSurface(surf);
|
|
||||||
free(pixels);
|
|
||||||
SDL_DestroyTexture(ren_tex);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
|
@ -197,60 +78,36 @@ uint32_t fetchPixelFromFb(unsigned int x, unsigned int y)
|
||||||
|
|
||||||
void display_init()
|
void display_init()
|
||||||
{
|
{
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
|
/*
|
||||||
{
|
* Black and white pixel format: framebuffer type is uint8_t where each
|
||||||
printf("SDL video init error!!\n");
|
* bit represents a pixel. We have to allocate
|
||||||
|
* (SCREEN_HEIGHT * SCREEN_WIDTH)/8 elements
|
||||||
}
|
*/
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
window = SDL_CreateWindow("OpenRTX",
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
SCREEN_WIDTH * 3, SCREEN_HEIGHT * 3,
|
|
||||||
SDL_WINDOW_SHOWN );
|
|
||||||
//removed RESIZABLE flag so automatic screen recording is a little easier
|
|
||||||
|
|
||||||
renderer = SDL_CreateRenderer(window, -1, 0);
|
|
||||||
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
displayTexture = SDL_CreateTexture(renderer, PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING,
|
|
||||||
SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
SDL_RenderCopy(renderer, displayTexture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Black and white pixel format: framebuffer type is uint8_t where each
|
|
||||||
* bit represents a pixel. We have to allocate
|
|
||||||
* (SCREEN_HEIGHT * SCREEN_WIDTH)/8 elements
|
|
||||||
*/
|
|
||||||
#ifdef PIX_FMT_BW
|
#ifdef PIX_FMT_BW
|
||||||
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
|
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
|
||||||
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1; /* Compensate for eventual truncation error in division */
|
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1; /* Compensate for eventual truncation error in division */
|
||||||
fbSize *= sizeof(uint8_t);
|
fbSize *= sizeof(uint8_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grayscale pixel format: framebuffer type is uint8_t where each element
|
* Grayscale pixel format: framebuffer type is uint8_t where each element
|
||||||
* controls one pixel
|
* controls one pixel
|
||||||
*/
|
*/
|
||||||
#ifdef PIX_FMT_GRAYSC
|
#ifdef PIX_FMT_GRAYSC
|
||||||
unsigned int fbSize = SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint8_t);
|
unsigned int fbSize = SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint8_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RGB565 pixel format: framebuffer type is uint16_t where each element
|
* RGB565 pixel format: framebuffer type is uint16_t where each element
|
||||||
* controls one pixel
|
* controls one pixel
|
||||||
*/
|
*/
|
||||||
#ifdef PIX_FMT_RGB565
|
#ifdef PIX_FMT_RGB565
|
||||||
unsigned int fbSize = SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint16_t);
|
unsigned int fbSize = SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint16_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
frameBuffer = malloc(fbSize);
|
frameBuffer = malloc(fbSize);
|
||||||
memset(frameBuffer, 0xFFFF, fbSize);
|
memset(frameBuffer, 0xFFFF, fbSize);
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_terminate()
|
void display_terminate()
|
||||||
|
|
@ -259,36 +116,36 @@ void display_terminate()
|
||||||
{} /* Wait until current render finishes */
|
{} /* Wait until current render finishes */
|
||||||
printf("Terminating SDL display emulator, goodbye!\n");
|
printf("Terminating SDL display emulator, goodbye!\n");
|
||||||
free(frameBuffer);
|
free(frameBuffer);
|
||||||
SDL_DestroyWindow(window);
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_renderRows(uint8_t startRow, uint8_t endRow)
|
void display_renderRows(uint8_t startRow, uint8_t endRow)
|
||||||
{
|
{
|
||||||
(void) startRow;
|
(void) startRow;
|
||||||
(void) endRow;
|
(void) endRow;
|
||||||
PIXEL_SIZE *pixels;
|
|
||||||
int pitch = 0;
|
|
||||||
if (SDL_LockTexture(displayTexture, NULL, (void **) &pixels, &pitch) < 0)
|
|
||||||
{
|
|
||||||
printf("SDL_lock failed: %s\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
inProgress = true;
|
inProgress = true;
|
||||||
#ifdef PIX_FMT_RGB565
|
if(!sdl_ready)
|
||||||
uint16_t *fb = (uint16_t *) (frameBuffer);
|
|
||||||
memcpy(pixels, fb, sizeof(uint16_t) * SCREEN_HEIGHT * SCREEN_WIDTH);
|
|
||||||
#else
|
|
||||||
for (unsigned int x = 0; x < SCREEN_WIDTH; x++)
|
|
||||||
{
|
{
|
||||||
for (unsigned int y = startRow; y < endRow; y++)
|
sdl_ready = sdl_main_loop_ready();
|
||||||
{
|
|
||||||
pixels[x + y * SCREEN_WIDTH] = fetchPixelFromFb(x, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sdl_ready)
|
||||||
|
{
|
||||||
|
#ifdef PIX_FMT_RGB565
|
||||||
|
chan_send(&fb_sync, frameBuffer);
|
||||||
|
#else
|
||||||
|
//TODO free
|
||||||
|
PIXEL_SIZE *pixels = malloc(sizeof(uint16_t) * SCREEN_HEIGHT * SCREEN_WIDTH);
|
||||||
|
for (unsigned int x = 0; x < SCREEN_WIDTH; x++)
|
||||||
|
{
|
||||||
|
for (unsigned int y = startRow; y < endRow; y++)
|
||||||
|
{
|
||||||
|
pixels[x + y * SCREEN_WIDTH] = fetchPixelFromFb(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan_send(&fb_sync, (void *)pixels);
|
||||||
#endif
|
#endif
|
||||||
SDL_UnlockTexture(displayTexture);
|
}
|
||||||
SDL_RenderCopy(renderer, displayTexture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,4 +168,3 @@ void display_setContrast(uint8_t contrast)
|
||||||
{
|
{
|
||||||
printf("Setting display contrast to %d\n", contrast);
|
printf("Setting display contrast to %d\n", contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,22 +20,24 @@
|
||||||
|
|
||||||
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "sdl_engine.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <interfaces/keyboard.h>
|
#include <interfaces/keyboard.h>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
/* Custom SDL Event to request a screenshot */
|
||||||
|
extern Uint32 SDL_Screenshot_Event;
|
||||||
|
|
||||||
radio_state Radio_State = {12, 8.2f, 3, 4, 1, false, false};
|
radio_state Radio_State = {12, 8.2f, 3, 4, 1, false, false};
|
||||||
|
|
||||||
extern int screenshot_display(const char *filename);
|
|
||||||
|
|
||||||
typedef int (*_climenu_fn)(void *self, int argc, char **argv);
|
typedef int (*_climenu_fn)(void *self, int argc, char **argv);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -250,8 +252,14 @@ int screenshot(void *_self, int _argc, char **_argv)
|
||||||
{
|
{
|
||||||
filename = _argv[0];
|
filename = _argv[0];
|
||||||
}
|
}
|
||||||
return screenshot_display(filename) == 0 ? SH_CONTINUE : SH_ERR;
|
|
||||||
//screenshot_display returns 0 if ok, which is same as SH_CONTINUE
|
SDL_Event e;
|
||||||
|
SDL_zero(e);
|
||||||
|
e.type = SDL_Screenshot_Event;
|
||||||
|
e.user.data1 = malloc(sizeof(filename));
|
||||||
|
strcpy(e.user.data1, filename);
|
||||||
|
|
||||||
|
return SDL_PushEvent(&e) == 1 ? SH_CONTINUE : SH_ERR;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
int record_start(void * _self, int _argc, char ** _argv ){
|
int record_start(void * _self, int _argc, char ** _argv ){
|
||||||
|
|
@ -528,116 +536,15 @@ void *startCLIMenu()
|
||||||
Radio_State.PowerOff = true;
|
Radio_State.PowerOff = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void emulator_start()
|
void emulator_start()
|
||||||
{
|
{
|
||||||
|
init_sdl();
|
||||||
|
|
||||||
pthread_t cli_thread;
|
pthread_t cli_thread;
|
||||||
int err = pthread_create(&cli_thread, NULL, startCLIMenu, NULL);
|
int err = pthread_create(&cli_thread, NULL, startCLIMenu, NULL);
|
||||||
|
|
||||||
if(err)
|
if(err)
|
||||||
{
|
{
|
||||||
printf("An error occurred starting the emulator thread: %d\n", err);
|
printf("An error occurred starting the emulator CLI thread: %d\n", err);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
keyboard_t sdl_keys;
|
|
||||||
keyboard_t sdl_getKeys() { return sdl_keys; }
|
|
||||||
|
|
||||||
bool sdk_key_code_to_key(SDL_KeyCode sym, keyboard_t *key)
|
|
||||||
{
|
|
||||||
switch (sym) {
|
|
||||||
case SDLK_0:
|
|
||||||
*key = KEY_0;
|
|
||||||
return true;
|
|
||||||
case SDLK_1:
|
|
||||||
*key = KEY_1;
|
|
||||||
return true;
|
|
||||||
case SDLK_2:
|
|
||||||
*key = KEY_2;
|
|
||||||
return true;
|
|
||||||
case SDLK_3:
|
|
||||||
*key = KEY_3;
|
|
||||||
return true;
|
|
||||||
case SDLK_4:
|
|
||||||
*key = KEY_4;
|
|
||||||
return true;
|
|
||||||
case SDLK_5:
|
|
||||||
*key = KEY_5;
|
|
||||||
return true;
|
|
||||||
case SDLK_6:
|
|
||||||
*key = KEY_6;
|
|
||||||
return true;
|
|
||||||
case SDLK_7:
|
|
||||||
*key = KEY_7;
|
|
||||||
return true;
|
|
||||||
case SDLK_8:
|
|
||||||
*key = KEY_8;
|
|
||||||
return true;
|
|
||||||
case SDLK_9:
|
|
||||||
*key = KEY_9;
|
|
||||||
return true;
|
|
||||||
case SDLK_ASTERISK:
|
|
||||||
*key = KEY_STAR;
|
|
||||||
return true;
|
|
||||||
case SDLK_ESCAPE:
|
|
||||||
*key = KEY_ESC;
|
|
||||||
return true;
|
|
||||||
case SDLK_LEFT:
|
|
||||||
*key = KEY_LEFT;
|
|
||||||
return true;
|
|
||||||
case SDLK_RIGHT:
|
|
||||||
*key = KEY_RIGHT;
|
|
||||||
return true;
|
|
||||||
case SDLK_RETURN:
|
|
||||||
*key = KEY_ENTER;
|
|
||||||
return true;
|
|
||||||
case SDLK_HASH:
|
|
||||||
*key = KEY_HASH;
|
|
||||||
return true;
|
|
||||||
case SDLK_n:
|
|
||||||
*key = KEY_F1;
|
|
||||||
return true;
|
|
||||||
case SDLK_m:
|
|
||||||
*key = KEY_MONI;
|
|
||||||
return true;
|
|
||||||
case SDLK_PAGEUP:
|
|
||||||
*key = KNOB_LEFT;
|
|
||||||
return true;
|
|
||||||
case SDLK_PAGEDOWN:
|
|
||||||
*key = KNOB_RIGHT;
|
|
||||||
return true;
|
|
||||||
case SDLK_UP:
|
|
||||||
*key = KEY_UP;
|
|
||||||
return true;
|
|
||||||
case SDLK_DOWN:
|
|
||||||
*key = KEY_DOWN;
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void emulator_process_sdl_events()
|
|
||||||
{
|
|
||||||
Uint32 now = SDL_GetTicks();
|
|
||||||
|
|
||||||
SDL_Event ev = { 0 };
|
|
||||||
keyboard_t key = 0;
|
|
||||||
|
|
||||||
SDL_PollEvent( &ev);
|
|
||||||
|
|
||||||
switch (ev.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
Radio_State.PowerOff = true;
|
|
||||||
break;
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
if (sdk_key_code_to_key(ev.key.keysym.sym, &key))
|
|
||||||
sdl_keys |= key;
|
|
||||||
break;
|
|
||||||
case SDL_KEYUP:
|
|
||||||
if (sdk_key_code_to_key(ev.key.keysym.sym, &key))
|
|
||||||
sdl_keys ^= key;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2021 by Alessio Caiazza IU5BON *
|
||||||
|
* *
|
||||||
|
* 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 <http://www.gnu.org/licenses/> *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "sdl_engine.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <interfaces/keyboard.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
int screenshot_display(const char *filename);
|
||||||
|
|
||||||
|
/* Shared channel to receive frame buffer updates */
|
||||||
|
chan_t fb_sync;
|
||||||
|
|
||||||
|
SDL_Window *window;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
SDL_Texture *displayTexture;
|
||||||
|
|
||||||
|
/* Custom SDL Event to request a screenshot */
|
||||||
|
Uint32 SDL_Screenshot_Event;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex protected variables
|
||||||
|
*/
|
||||||
|
pthread_mutex_t mu;
|
||||||
|
bool ready = false; /* Signal if the main loop is ready */
|
||||||
|
keyboard_t sdl_keys; /* Store the keyboard status */
|
||||||
|
|
||||||
|
bool sdk_key_code_to_key(SDL_KeyCode sym, keyboard_t *key)
|
||||||
|
{
|
||||||
|
switch (sym) {
|
||||||
|
case SDLK_0:
|
||||||
|
*key = KEY_0;
|
||||||
|
return true;
|
||||||
|
case SDLK_1:
|
||||||
|
*key = KEY_1;
|
||||||
|
return true;
|
||||||
|
case SDLK_2:
|
||||||
|
*key = KEY_2;
|
||||||
|
return true;
|
||||||
|
case SDLK_3:
|
||||||
|
*key = KEY_3;
|
||||||
|
return true;
|
||||||
|
case SDLK_4:
|
||||||
|
*key = KEY_4;
|
||||||
|
return true;
|
||||||
|
case SDLK_5:
|
||||||
|
*key = KEY_5;
|
||||||
|
return true;
|
||||||
|
case SDLK_6:
|
||||||
|
*key = KEY_6;
|
||||||
|
return true;
|
||||||
|
case SDLK_7:
|
||||||
|
*key = KEY_7;
|
||||||
|
return true;
|
||||||
|
case SDLK_8:
|
||||||
|
*key = KEY_8;
|
||||||
|
return true;
|
||||||
|
case SDLK_9:
|
||||||
|
*key = KEY_9;
|
||||||
|
return true;
|
||||||
|
case SDLK_ASTERISK:
|
||||||
|
*key = KEY_STAR;
|
||||||
|
return true;
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
*key = KEY_ESC;
|
||||||
|
return true;
|
||||||
|
case SDLK_LEFT:
|
||||||
|
*key = KEY_LEFT;
|
||||||
|
return true;
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
*key = KEY_RIGHT;
|
||||||
|
return true;
|
||||||
|
case SDLK_RETURN:
|
||||||
|
*key = KEY_ENTER;
|
||||||
|
return true;
|
||||||
|
case SDLK_HASH:
|
||||||
|
*key = KEY_HASH;
|
||||||
|
return true;
|
||||||
|
case SDLK_n:
|
||||||
|
*key = KEY_F1;
|
||||||
|
return true;
|
||||||
|
case SDLK_m:
|
||||||
|
*key = KEY_MONI;
|
||||||
|
return true;
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
*key = KNOB_LEFT;
|
||||||
|
return true;
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
*key = KNOB_RIGHT;
|
||||||
|
return true;
|
||||||
|
case SDLK_UP:
|
||||||
|
*key = KEY_UP;
|
||||||
|
return true;
|
||||||
|
case SDLK_DOWN:
|
||||||
|
*key = KEY_DOWN;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int screenshot_display(const char *filename)
|
||||||
|
{
|
||||||
|
//https://stackoverflow.com/a/48176678
|
||||||
|
//user1902824
|
||||||
|
//modified to keep renderer and display texture references in the body rather than as a parameter
|
||||||
|
SDL_Renderer * ren = renderer;
|
||||||
|
SDL_Texture * tex = displayTexture;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
|
||||||
|
SDL_Texture *ren_tex;
|
||||||
|
SDL_Surface *surf;
|
||||||
|
int st;
|
||||||
|
int w;
|
||||||
|
int h;
|
||||||
|
int format;
|
||||||
|
void *pixels;
|
||||||
|
|
||||||
|
pixels = NULL;
|
||||||
|
surf = NULL;
|
||||||
|
ren_tex = NULL;
|
||||||
|
format = SDL_PIXELFORMAT_RGBA32;
|
||||||
|
|
||||||
|
/* Get information about texture we want to save */
|
||||||
|
st = SDL_QueryTexture(tex, NULL, NULL, &w, &h);
|
||||||
|
if (st != 0)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed querying texture: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ren_tex = SDL_CreateTexture(ren, format, SDL_TEXTUREACCESS_TARGET, w, h);
|
||||||
|
if (!ren_tex)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed creating render texture: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize our canvas, then copy texture to a target whose pixel data we
|
||||||
|
* can access
|
||||||
|
*/
|
||||||
|
st = SDL_SetRenderTarget(ren, ren_tex);
|
||||||
|
if (st != 0)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed setting render target: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00);
|
||||||
|
SDL_RenderClear(ren);
|
||||||
|
st = SDL_RenderCopy(ren, tex, NULL, NULL);
|
||||||
|
if (st != 0)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed copying texture data: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* Create buffer to hold texture data and load it */
|
||||||
|
pixels = malloc(w * h * SDL_BYTESPERPIXEL(format));
|
||||||
|
if (!pixels)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed allocating memory\n");
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
st = SDL_RenderReadPixels(ren, NULL, format, pixels, w * SDL_BYTESPERPIXEL(format));
|
||||||
|
if (st != 0)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed reading pixel data: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* Copy pixel data over to surface */
|
||||||
|
surf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(format), w * SDL_BYTESPERPIXEL(format), format);
|
||||||
|
if (!surf)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed creating new surface: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* Save result to an image */
|
||||||
|
st = SDL_SaveBMP(surf, filename);
|
||||||
|
if (st != 0)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed saving image: %s\n", SDL_GetError());
|
||||||
|
err++;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
SDL_Log("Saved texture as BMP to \"%s\"\n", filename);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
SDL_FreeSurface(surf);
|
||||||
|
free(pixels);
|
||||||
|
SDL_DestroyTexture(ren_tex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sdl_main_loop_ready()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mu);
|
||||||
|
bool is_ready = ready;
|
||||||
|
pthread_mutex_unlock(&mu);
|
||||||
|
|
||||||
|
return is_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyboard_t sdl_getKeys()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mu);
|
||||||
|
keyboard_t keys = sdl_keys;
|
||||||
|
pthread_mutex_unlock(&mu);
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SDL main loop. Due to macOS restrictions, this must run on the Main Thread.
|
||||||
|
*/
|
||||||
|
void sdl_task()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mu);
|
||||||
|
ready = true;
|
||||||
|
pthread_mutex_unlock(&mu);
|
||||||
|
|
||||||
|
SDL_Event ev = { 0 };
|
||||||
|
while(!Radio_State.PowerOff)
|
||||||
|
{
|
||||||
|
keyboard_t key = 0;
|
||||||
|
if(SDL_PollEvent(&ev) == 1)
|
||||||
|
{
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case SDL_QUIT:
|
||||||
|
Radio_State.PowerOff = true;
|
||||||
|
break;
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
if (sdk_key_code_to_key(ev.key.keysym.sym, &key))
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mu);
|
||||||
|
sdl_keys |= key;
|
||||||
|
pthread_mutex_unlock(&mu);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
if (sdk_key_code_to_key(ev.key.keysym.sym, &key))
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mu);
|
||||||
|
sdl_keys ^= key;
|
||||||
|
pthread_mutex_unlock(&mu);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( ev.type == SDL_Screenshot_Event)
|
||||||
|
{
|
||||||
|
char *filename = (char *)ev.user.data1;
|
||||||
|
screenshot_display(filename);
|
||||||
|
free(ev.user.data1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan_can_recv(&fb_sync))
|
||||||
|
{
|
||||||
|
PIXEL_SIZE *pixels;
|
||||||
|
int pitch = 0;
|
||||||
|
if (SDL_LockTexture(displayTexture, NULL, (void **) &pixels, &pitch) < 0)
|
||||||
|
{
|
||||||
|
SDL_Log("SDL_lock failed: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
void *fb;
|
||||||
|
chan_recv(&fb_sync, &fb);
|
||||||
|
memcpy(pixels, fb, sizeof(PIXEL_SIZE) * SCREEN_HEIGHT * SCREEN_WIDTH);
|
||||||
|
|
||||||
|
SDL_UnlockTexture(displayTexture);
|
||||||
|
SDL_RenderCopy(renderer, displayTexture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
} /* while(!Radio_State.PowerOff) */
|
||||||
|
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_sdl()
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&mu, NULL);
|
||||||
|
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
|
||||||
|
{
|
||||||
|
printf("SDL video init error!!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register an SDL custom event type to handle screenshot requests
|
||||||
|
SDL_Screenshot_Event = SDL_RegisterEvents(1);
|
||||||
|
|
||||||
|
chan_init(&fb_sync);
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("OpenRTX",
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SCREEN_WIDTH * 3, SCREEN_HEIGHT * 3,
|
||||||
|
SDL_WINDOW_SHOWN );
|
||||||
|
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
displayTexture = SDL_CreateTexture(renderer,
|
||||||
|
PIXEL_FORMAT,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
SCREEN_WIDTH,
|
||||||
|
SCREEN_HEIGHT);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderCopy(renderer, displayTexture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2021 by Alessio Caiazza IU5BON *
|
||||||
|
* *
|
||||||
|
* 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 <http://www.gnu.org/licenses/> *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef SDL_ENGINE_H
|
||||||
|
#define SDL_ENGINE_H
|
||||||
|
|
||||||
|
#include "chan.h"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen dimensions, adjust basing on the size of the screen you need to
|
||||||
|
* emulate
|
||||||
|
*/
|
||||||
|
#ifndef SCREEN_WIDTH
|
||||||
|
#define SCREEN_WIDTH 160
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SCREEN_HEIGHT
|
||||||
|
#define SCREEN_HEIGHT 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PIX_FMT_RGB565
|
||||||
|
#define PIXEL_FORMAT SDL_PIXELFORMAT_RGB565
|
||||||
|
#define PIXEL_SIZE uint16_t
|
||||||
|
#else
|
||||||
|
#define PIXEL_FORMAT SDL_PIXELFORMAT_ARGB8888
|
||||||
|
#define PIXEL_SIZE uint32_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initialize the SDL engine. Must be called in the Main Thread */
|
||||||
|
void init_sdl();
|
||||||
|
/* SDL main loop. Must be called in the Main Thread */
|
||||||
|
void sdl_task();
|
||||||
|
/* Thread-safe check to verify if the application entered the SDL main loop. */
|
||||||
|
bool sdl_main_loop_ready();
|
||||||
|
|
||||||
|
#endif /* SDL_ENGINE_H */
|
||||||
Loading…
Reference in New Issue