Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c32bfde94e | ||
|
|
129b7e0ee7 | ||
|
|
0fa18290dd |
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* pixy_control.c
|
||||
*
|
||||
* Notation
|
||||
* --------
|
||||
*
|
||||
* x : Sollwert (Führgrösse)
|
||||
* w : Istwert (Reglergrösse)
|
||||
* esum : Integralteil
|
||||
* e : Regelabweichung
|
||||
* y : Stellgrösse
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include<pixy_control.h>
|
||||
#include<stdint.h>
|
||||
|
||||
// PID tuning factors
|
||||
#define REG_PID_KP (0.41f)
|
||||
#define REG_PID_KI (0.001f)
|
||||
#define REG_PID_KD (0.00025f)
|
||||
#define REG_PID_TA (0.001f)
|
||||
#define REG_PID_YKOR (0.3f)
|
||||
|
||||
void int_init(void){
|
||||
// TODO Init ports and outputs if needed.
|
||||
}
|
||||
|
||||
// PID controller implementatoin for the y-axis
|
||||
int16_t pixy_PID_Y(int16_t x, int16_t w)
|
||||
{
|
||||
float e = 0;
|
||||
static float esum = 0;
|
||||
static float eold = 0;
|
||||
float y = 0;
|
||||
|
||||
e = (float)(x - w); // calculate the controller offset
|
||||
|
||||
//----PID-control-------------------------------------------------------------------------
|
||||
esum = esum + e; // add e to the current sum
|
||||
|
||||
y += (REG_PID_KP + REG_PID_YKOR) * e; // add the proportional part to the output
|
||||
y += REG_PID_KI * REG_PID_TA * esum; // add the integral part to the output
|
||||
y += REG_PID_KD * (e - eold) / REG_PID_TA; // add the differential part to the output
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
eold = e; // save the previous value
|
||||
|
||||
return (int16_t)y;
|
||||
}
|
||||
|
||||
// PID controller implementation for the x-axis
|
||||
int16_t pixy_PID_X(int16_t x, int16_t w)
|
||||
{
|
||||
float e = 0;
|
||||
static float esum = 0;
|
||||
static float eold = 0;
|
||||
float y = 0;
|
||||
|
||||
e = (float)(x - w); // calculate the controller offset
|
||||
|
||||
//----PID-control-------------------------------------------------------------------------
|
||||
esum = esum + e; // add e to the current sum
|
||||
|
||||
y += REG_PID_KP * e; // add the proportional part to the output
|
||||
y += REG_PID_KI * REG_PID_TA * esum; // add the integral part to the output
|
||||
y += REG_PID_KD * (e - eold) / REG_PID_TA; // add the differential part to the output
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
eold = e; // save the previous value
|
||||
|
||||
return (int16_t)y;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* pixy_control.h
|
||||
*/
|
||||
|
||||
#ifndef _CONTROL_H_
|
||||
#define _CONTROL_H_
|
||||
|
||||
#include<stdint.h>
|
||||
|
||||
void int_init(void);
|
||||
int16_t pixy_PID_Y(int16_t x, int16_t w);
|
||||
int16_t pixy_PID_X(int16_t x, int16_t w);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "screen_tracking.h"
|
||||
#include "pixy_control.h"
|
||||
#include "button.h"
|
||||
#include "checkbox.h"
|
||||
#include "tft.h"
|
||||
@@ -81,19 +80,12 @@ typedef struct {
|
||||
} TRACKING_CONFIG_STRUCT;
|
||||
|
||||
//Methods for our tracking implementation ahead
|
||||
static int16_t servo_x = 0;
|
||||
static int16_t servo_y = 0;
|
||||
|
||||
//Method/Callback to start our tracking
|
||||
void tracking_our_start(void* tracking_config) {
|
||||
//Activate pixy's data send program
|
||||
int32_t response;
|
||||
int return_value;
|
||||
|
||||
servo_x = servo_y = 500; // set a default value of 500
|
||||
pixy_rcs_set_position(0, servo_x); // set default
|
||||
pixy_rcs_set_position(1, servo_y); // set default
|
||||
|
||||
return_value = pixy_command("runprog", INT8(0), END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
}
|
||||
|
||||
@@ -107,31 +99,8 @@ void tracking_our_stop(void* tracking_config) {
|
||||
|
||||
//Method/Callback to calculate one step of our tracking
|
||||
void tracking_our_update(void* tracking_config, struct Block* blocks, int num_blocks) {
|
||||
|
||||
if(num_blocks <= 0){ // Check if there are blocks available
|
||||
return; // When there are none, do nothing
|
||||
}
|
||||
|
||||
uint16_t x = blocks[0].x; // Get x coordinate of the biggest object
|
||||
uint16_t y = blocks[0].y; // Get y coordinate of the biggest object
|
||||
|
||||
int16_t xset = 0;
|
||||
int16_t yset = 0;
|
||||
|
||||
xset = (servo_x + pixy_PID_X((FRAME_WIDTH / 2), x)); // calculate the PID output for x
|
||||
yset = (servo_y - pixy_PID_Y((FRAME_HEIGHT / 2), y)); // calculate the PID output for y
|
||||
|
||||
xset = (xset < 0) ? 0 : xset; // x lower boundary check
|
||||
xset = (xset > 1000) ? 1000 : xset; // x upper boundary check
|
||||
|
||||
yset = (yset < 0) ? 0 : yset; // y lower boundary check
|
||||
yset = (yset > 1000) ? 1000 : yset; // y upper boundary check
|
||||
|
||||
servo_x = xset; // update the global, static variable for x
|
||||
servo_y = yset; // update the global, statuc variable for y
|
||||
|
||||
pixy_rcs_set_position(0, servo_x); // set the new x position
|
||||
pixy_rcs_set_position(1, servo_y); // set the new y position
|
||||
//TODO: Implement tracking!
|
||||
//Calculate new servo pos and set the new servo pos
|
||||
}
|
||||
|
||||
//Variable which stores all the callbacks and settings for our tracking implementation
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
* This makes it safe to change the screen from an touch interrupt (e.g. button callback)
|
||||
*/
|
||||
|
||||
/* Possible Improvements:
|
||||
* Ensure that you can not navigate to a screen which is already in the history (because it will corrupt the list)
|
||||
*/
|
||||
|
||||
static SCREEN_STRUCT* screen_list = NULL; //Head of the linked list which stores the screen history.
|
||||
static SCREEN_STRUCT* screen_current = NULL; //Pointer to the current screen (= tail of the list)
|
||||
static volatile SCREEN_STRUCT* screen_goto = NULL; //Screen we should navigate to once we enter the gui_screen_update() method again
|
||||
|
||||
@@ -44,7 +44,6 @@ typedef struct SCREEN_S{
|
||||
/**
|
||||
* Navigate to the given screen as soon as the app enters the main loop again (and gui_screen_update() is called)
|
||||
* It's safe to call this method from an interrupt
|
||||
* @note Do not pass a screen which is already in your history of screens!
|
||||
* @param screen A Pointer to the preinitialized SCREEN_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
/* Possible improvements:
|
||||
* Exchange pointer-list "areas" with a linked list. This would ensure that we can always accept new regions
|
||||
* Implement calibration stuff, and calculate the real coordinates out of the data provided in touch_add_raw_event()
|
||||
*/
|
||||
|
||||
#define NUM_AREAS 50 //Number of Touch Areas we can manage
|
||||
|
||||
@@ -273,7 +273,7 @@ static bool gpio_init()
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
|
||||
|
||||
// PORT_B init
|
||||
// PORT_B init -------------------------------------------------------------------------------------
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
@@ -282,7 +282,7 @@ static bool gpio_init()
|
||||
// configure PORT_B
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
// PORT_D init
|
||||
// PORT_D init -------------------------------------------------------------------------------------
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC); // PD0=FSMC_D2 -> DB2
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC); // PD1=FSMC_D3 -> DB3
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC); // PD4=FSMC_NOE -> RD
|
||||
@@ -305,7 +305,7 @@ static bool gpio_init()
|
||||
// configure PORT_D
|
||||
GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
|
||||
// PORT_E init
|
||||
// PORT_E init --------------------------------------------------------------------------------------
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource3, GPIO_AF_FSMC); // PE3=FSMC_A19 -> RS
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC); // PE7=FSMC_D4 -> DB4
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC); // PE8=FSMC_D5 -> DB5
|
||||
@@ -316,7 +316,6 @@ static bool gpio_init()
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC); // PE13=FSMC_D10 -> DB12
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // PE14=FSMC_D11 -> DB13
|
||||
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // PE15=FSMC_D12 -> DB14
|
||||
|
||||
// PORT_E struct
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 |
|
||||
GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
|
||||
@@ -326,7 +325,6 @@ static bool gpio_init()
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
|
||||
// configure PORT_E
|
||||
GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
|
||||
@@ -336,8 +334,6 @@ static bool gpio_init()
|
||||
/*
|
||||
* ---------------------- display control functions -------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Clear the whole screen by filling it with a specifig color
|
||||
void ll_tft_clear(uint16_t color)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
@@ -350,7 +346,6 @@ void ll_tft_clear(uint16_t color)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursorposition
|
||||
static void tft_set_cursor(uint16_t xpos, uint16_t ypos)
|
||||
{
|
||||
// set cursor
|
||||
@@ -359,59 +354,52 @@ static void tft_set_cursor(uint16_t xpos, uint16_t ypos)
|
||||
TFT_REG = TFT_SSD1289_REG_22;
|
||||
}
|
||||
|
||||
// Enable / Disable the backlight
|
||||
static void tft_set_backlight(bool state)
|
||||
{
|
||||
if(state){ // if state is true
|
||||
GPIOB->BSRRH = GPIO_Pin_0; // set the backlight output
|
||||
} else { // else
|
||||
GPIOB->BSRRL = GPIO_Pin_0; // reset the backlight
|
||||
if(state){
|
||||
GPIOB->BSRRH = GPIO_Pin_0;
|
||||
} else {
|
||||
GPIOB->BSRRL = GPIO_Pin_0;
|
||||
}
|
||||
}
|
||||
|
||||
// Port operations on the screen RS PIN
|
||||
static void tft_reset(bool state)
|
||||
{
|
||||
if(state){ // if state is ture
|
||||
GPIOB->BSRRH = GPIO_Pin_0; // Set the reset pin
|
||||
} else { // else
|
||||
GPIOB->BSRRL = GPIO_Pin_0; // reset the reset pin
|
||||
if(state){
|
||||
GPIOB->BSRRH = GPIO_Pin_0;
|
||||
} else {
|
||||
GPIOB->BSRRL = GPIO_Pin_0;
|
||||
}
|
||||
}
|
||||
|
||||
// Send a single command to the display controller
|
||||
static void tft_write_reg(uint8_t reg_adr, uint16_t reg_value)
|
||||
{
|
||||
TFT_REG = reg_adr; // set adress
|
||||
TFT_RAM = reg_value; // send command
|
||||
TFT_REG = reg_adr;
|
||||
TFT_RAM = reg_value;
|
||||
}
|
||||
|
||||
// Read a register value of the display controller
|
||||
static uint16_t tft_read_reg(uint8_t reg_adr)
|
||||
{
|
||||
TFT_REG = reg_adr; // set adress
|
||||
return TFT_RAM; // return value
|
||||
TFT_REG = reg_adr;
|
||||
return TFT_RAM;
|
||||
}
|
||||
|
||||
// This sets a window for current draw functions
|
||||
static void tft_set_window(uint16_t xstart, uint16_t ystart, uint16_t xend, uint16_t yend)
|
||||
{
|
||||
uint16_t start,end;
|
||||
uint16_t ystart_end;
|
||||
|
||||
start = (ystart & 0x00FF); // Start adress of the window
|
||||
end = ((yend & 0x00FF) << 8); // End adress of the window
|
||||
ystart_end = (start | end); // Calculate y endpoint
|
||||
start = (ystart & 0x00FF);
|
||||
end = ((yend & 0x00FF) << 8);
|
||||
ystart_end = (start | end);
|
||||
|
||||
tft_write_reg(TFT_SSD1289_REG_44, ystart_end); // Send y size
|
||||
tft_write_reg(TFT_SSD1289_REG_45, 319-xend); // Send x start
|
||||
tft_write_reg(TFT_SSD1289_REG_46, 319-xstart); // Send x end
|
||||
tft_write_reg(TFT_SSD1289_REG_44, ystart_end);
|
||||
tft_write_reg(TFT_SSD1289_REG_45, 319-xend);
|
||||
tft_write_reg(TFT_SSD1289_REG_46, 319-xstart);
|
||||
}
|
||||
|
||||
// Reset a Window
|
||||
void tft_reset_window()
|
||||
{
|
||||
// Commands according to the datasheet
|
||||
tft_write_reg(0x44,239<<8);
|
||||
tft_write_reg(0x45,0);
|
||||
tft_write_reg(0x46,319);
|
||||
@@ -421,7 +409,6 @@ void tft_reset_window()
|
||||
* ---------------------- draw functions -----------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Draw a line on the given coordinates
|
||||
void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
if(abs(x2-x1) > abs(y2-y1)) //line has more distance in x than y => iterate over x distance
|
||||
@@ -475,14 +462,12 @@ void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a single pixel on (x,y) with the given color
|
||||
void ll_tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color)
|
||||
{
|
||||
tft_set_cursor(x,y); // Set the cursor position
|
||||
TFT_RAM = color; // Draw the pixel
|
||||
tft_set_cursor(x,y);
|
||||
TFT_RAM = color;
|
||||
}
|
||||
|
||||
// Draw a rectangle at the given coordinates with the given color
|
||||
void ll_tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
unsigned int tmp;
|
||||
@@ -523,7 +508,6 @@ void ll_tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, u
|
||||
|
||||
}
|
||||
|
||||
// Draw a filled rectangle at the given coordinates with the given color
|
||||
void ll_tft_fill_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color)
|
||||
{
|
||||
uint16_t area;
|
||||
|
||||
BIN
doc/PID_REGELUNG.tgz
Normal file
BIN
doc/PID_REGELUNG.tgz
Normal file
Binary file not shown.
BIN
doc/PI_PD_REGELUNG.tgz
Normal file
BIN
doc/PI_PD_REGELUNG.tgz
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
BIN
doc/docu.odt
BIN
doc/docu.odt
Binary file not shown.
BIN
doc/docu.pdf
BIN
doc/docu.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB |
5
emulator/.gitignore
vendored
5
emulator/.gitignore
vendored
@@ -5,8 +5,9 @@ qt/*.o
|
||||
qt/*.a
|
||||
qt/ui_*
|
||||
qt/moc_*
|
||||
qt/Makefile
|
||||
|
||||
qt/Makefile*
|
||||
qt/debug
|
||||
qt/release
|
||||
|
||||
libs/*/obj
|
||||
libs/*/*.a
|
||||
|
||||
@@ -10,7 +10,7 @@ QT_DIR=./qt
|
||||
COMMON_DIR=../common
|
||||
|
||||
#Tools
|
||||
CC=gcc -fdiagnostics-color=auto
|
||||
CC=gcc #-fdiagnostics=auto
|
||||
GDB=gdb
|
||||
|
||||
|
||||
@@ -24,17 +24,22 @@ INCLUDES:=$(addprefix -I,$(INCLUDES))
|
||||
QT_LIB=$(QT_DIR)/libemulatorqt.a
|
||||
|
||||
|
||||
CPPFLAGS= -march=x86-64 -mtune=generic -fPIC $(INCLUDES)
|
||||
CPPFLAGS= -march=x86-64 -mtune=generic #-fPIC
|
||||
CPPFLAGS+= $(INCLUDES)
|
||||
CFLAGS= -O0 -g -std=c99
|
||||
|
||||
|
||||
LIBS= pixy usb-1.0 boost_system boost_timer boost_chrono
|
||||
LIBS+=Qt5Core Qt5Gui Qt5Widgets emulatorqt m stdc++
|
||||
LIBS= emulatorqt pixy usb-1.0
|
||||
LIBS+= boost_system-mgw49-mt-1_58 boost_timer-mgw49-mt-1_58 boost_chrono-mgw49-mt-1_58
|
||||
LIBS+= Qt5Core Qt5Gui Qt5Widgets m stdc++
|
||||
|
||||
|
||||
LDFLAGS= -L$(QT_DIR) $(addprefix -l,$(LIBS))
|
||||
LDFLAGS= -static-libgcc -static-libstdc++ #-Wl,-t -Wl,--Map=a.map
|
||||
LDFLAGS+= -L$(QT_DIR)
|
||||
LDFLAGS+= -L$(LIB_DIR)/Pixy
|
||||
|
||||
LDFLAGS+= -L$(LIB_DIR)/boost/lib
|
||||
LDFLAGS+= -LC:/Qt/5.4/mingw491_32/lib
|
||||
LDFLAGS+= -L$(LIB_DIR)/Pixy/windows
|
||||
LDFLAGS+= $(addprefix -l,$(LIBS))
|
||||
|
||||
#Finding Input files
|
||||
CFILES=$(shell find . -maxdepth 1 -name '*.c')
|
||||
@@ -58,7 +63,7 @@ debug: all
|
||||
$(GDB) ./build/emulator
|
||||
|
||||
$(QT_LIB):
|
||||
cd $(QT_DIR) && qmake &&make
|
||||
cd $(QT_DIR) && qmake && $(MAKE)
|
||||
|
||||
#objects to elf
|
||||
$(BUILD_DIR)/$(TARGET): $(OBJS) $(COMMON_OBJS) $(QT_LIB)
|
||||
@@ -83,7 +88,7 @@ $(OBJ_DIR)/%.o: $(COMMON_DIR)/%.c
|
||||
|
||||
#Clean Obj files and builded stuff
|
||||
clean:
|
||||
cd $(QT_DIR) && $(MAKE) clean && $(RM) Makefile && $(RM) *.a
|
||||
cd $(QT_DIR) && $(MAKE) clean && $(RM) Makefile* && $(RM) *.a && $(RMDIR) debug release
|
||||
$(RMDIR) $(BUILD_DIR) $(OBJ_DIR)
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,13 @@ OBJ_DIR=./obj
|
||||
#Architecture flags
|
||||
|
||||
#Compiler, Linker Options
|
||||
CPPFLAGS=-I$(INC_DIR) -D__LINUX__=1 -DHOST=1 #-DDEBUG=1
|
||||
CPPFLAGS=-I$(INC_DIR) -DHOST=1 #-D__LINUX__=1 -DDEBUG=1
|
||||
CFLAGS=$(ARCH_FLAGS) -O0 -g #-ffunction-sections -fdata-sections -g
|
||||
#CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||
#CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
||||
CFLAGS+=-I/usr/include/libusb-1.0
|
||||
CFLAGS+=-I../boost/include/
|
||||
CFLAGS+=-I./windows/
|
||||
|
||||
#Finding Input files
|
||||
CFILES=$(shell find $(SRC_DIR) -name '*.cpp')
|
||||
|
||||
BIN
emulator/libs/Pixy/windows/libusb-1.0.dll
Normal file
BIN
emulator/libs/Pixy/windows/libusb-1.0.dll
Normal file
Binary file not shown.
BIN
emulator/libs/Pixy/windows/libusb-1.0.dll.a
Normal file
BIN
emulator/libs/Pixy/windows/libusb-1.0.dll.a
Normal file
Binary file not shown.
1970
emulator/libs/Pixy/windows/libusb.h
Normal file
1970
emulator/libs/Pixy/windows/libusb.h
Normal file
File diff suppressed because it is too large
Load Diff
2
emulator/libs/boost/.gitignore
vendored
Normal file
2
emulator/libs/boost/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
include
|
||||
lib
|
||||
BIN
emulator/libs/boost/boost.rar
Normal file
BIN
emulator/libs/boost/boost.rar
Normal file
Binary file not shown.
2
emulator/libs/boost/readme.txt
Normal file
2
emulator/libs/boost/readme.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
This directory is only needed on windows, and if you do not have boost installed.
|
||||
Extract the rar file here, to get boost 1.58 header files and the libraries that we need for discoverpixy
|
||||
@@ -8,7 +8,7 @@ QT += widgets gui
|
||||
|
||||
TARGET = emulatorqt
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
CONFIG += staticlib debug
|
||||
|
||||
SOURCES += \
|
||||
mainwindow.cpp \
|
||||
@@ -30,3 +30,6 @@ INCLUDEPATH+= ../../common/lowlevel/ \
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
DESTDIR = $$_PRO_FILE_PWD_ #force windows to not create subfolders
|
||||
|
||||
#QMAKE_CXXFLAGS+= -v
|
||||
|
||||
@@ -7,53 +7,51 @@ extern "C" {
|
||||
#include <QFileInfoList>
|
||||
#include <QDateTime>
|
||||
|
||||
QDir rootdir ("./emulated"); //Create a QDir which points to the "root" of the emulated filesystem
|
||||
QDir rootdir ("./emulated");
|
||||
|
||||
bool ll_filesystem_init() {
|
||||
if(!rootdir.exists()) { //if our root dir is nonexistent
|
||||
if(!rootdir.exists()) {
|
||||
qWarning() << "Filesystem can not be emulated because the 'emulated' folder does not exist";
|
||||
return false; //mark an error
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) {
|
||||
QDir d(rootdir); //Make a copy of the rootdir QDir instance
|
||||
d.cd(path); //Change the directory to the passed path
|
||||
QDir d(rootdir);
|
||||
d.cd(path);
|
||||
if(!d.exists()) {
|
||||
return NULL; //mark an error
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DIRECTORY_STRUCT* directory = new DIRECTORY_STRUCT();
|
||||
//get all files and directories which are important to us. Filter out . and .. symlinks (linux)
|
||||
QFileInfoList entries = d.entryInfoList(QDir::NoDotAndDotDot|QDir::Files|QDir::Dirs|QDir::Readable|QDir::Writable|QDir::Hidden|QDir::System);
|
||||
//Fill the directory structure for the user
|
||||
directory->path = path;
|
||||
directory->num_files = entries.count();
|
||||
directory->files = new FILE_STRUCT[directory->num_files]; //allocate array of file structs
|
||||
directory->files = new FILE_STRUCT[directory->num_files];
|
||||
|
||||
for(int i=0; i<entries.count(); i++){ //foreach file that we found
|
||||
|
||||
for(int i=0; i<entries.count(); i++){
|
||||
QFileInfo fi = entries.at(i);
|
||||
FILE_STRUCT* entry = &(directory->files[i]); //get the pointer to the current filestruct (which should be filled)
|
||||
FILE_STRUCT* entry = &(directory->files[i]);
|
||||
entry->fattrib = 0;
|
||||
entry->fname = new char[fi.fileName().length()+1]; //reserve memory for filename
|
||||
strcpy(entry->fname,fi.fileName().toStdString().c_str()); //copy filename into struct
|
||||
if(fi.isDir()) { //it's a direcory
|
||||
entry->fattrib|=F_DIR; //set directory attribute
|
||||
entry->fname = new char[fi.fileName().length()+1];
|
||||
strcpy(entry->fname,fi.fileName().toStdString().c_str());
|
||||
if(fi.isDir()) {
|
||||
entry->fattrib|=F_DIR;
|
||||
entry->fsize = 0;
|
||||
} else { //it's a file
|
||||
entry->fsize = fi.size(); //set filesize
|
||||
} else {
|
||||
entry->fsize = fi.size();
|
||||
}
|
||||
if(fi.isHidden()) { //the file is hidden
|
||||
if(fi.isHidden()) {
|
||||
entry->fattrib|=F_HID;
|
||||
}
|
||||
if(!fi.isWritable()) { //the file is not writable
|
||||
entry->fattrib|=F_RDO; //set readonly attribue
|
||||
if(!fi.isWritable()) {
|
||||
entry->fattrib|=F_RDO;
|
||||
}
|
||||
|
||||
//Set date & time of file in structure
|
||||
QDateTime dt = fi.lastModified();
|
||||
entry->fdate.year = dt.date().year()-1980; //year is realtive to 1980
|
||||
entry->fdate.year = dt.date().year()-1980;
|
||||
entry->fdate.month = dt.date().month();
|
||||
entry->fdate.day = dt.date().day();
|
||||
entry->ftime.hour = dt.time().hour();
|
||||
@@ -62,22 +60,22 @@ DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) {
|
||||
|
||||
}
|
||||
|
||||
return directory; //return filled directory struct
|
||||
return directory;
|
||||
}
|
||||
|
||||
void ll_filesystem_dir_close(DIRECTORY_STRUCT* dir) {
|
||||
if(dir!=NULL) { //passed handle is valid
|
||||
for(int i=0; i<dir->num_files; i++) { //foreach file
|
||||
delete dir->files[i].fname; //delete filename buffer
|
||||
if(dir!=NULL) {
|
||||
for(int i=0; i<dir->num_files; i++) {
|
||||
delete dir->files[i].fname;
|
||||
}
|
||||
delete[] dir->files; //delete file array
|
||||
delete dir; //delete structure itself
|
||||
delete[] dir->files;
|
||||
delete dir;
|
||||
}
|
||||
}
|
||||
|
||||
//Struct that represents a file handle for the emulator
|
||||
struct QT_FILE_HANDLE : FILE_HANDLE { //..derived from the FILE_HANDLE (of the Filesystem modul)
|
||||
QFile* file; //Pointer to the open QFile* instance
|
||||
|
||||
struct QT_FILE_HANDLE : FILE_HANDLE {
|
||||
QFile* file;
|
||||
};
|
||||
|
||||
|
||||
@@ -85,19 +83,17 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
|
||||
if(!rootdir.exists()) {
|
||||
return NULL;
|
||||
}
|
||||
QString filepath = rootdir.absoluteFilePath(filename); //get the absolute path to the requested file
|
||||
QFile* f = new QFile(filepath); //create a QFile instance to the requested file
|
||||
if(!f->exists()) { //File does not exist
|
||||
return NULL; //mark error
|
||||
QString filepath = rootdir.absoluteFilePath(filename);
|
||||
QFile* f = new QFile(filepath);
|
||||
if(!f->exists()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!f->open(QFile::ReadWrite)) { //try to open the file, it it fails then ...
|
||||
return NULL; //... mark error
|
||||
if(!f->open(QFile::ReadWrite)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//At this point we have a valid QFile instance, pointing to an existing file
|
||||
|
||||
QT_FILE_HANDLE* fh = new QT_FILE_HANDLE(); //Create Structure to return to user
|
||||
QT_FILE_HANDLE* fh = new QT_FILE_HANDLE();
|
||||
fh->file = f;
|
||||
fh->fname = filename;
|
||||
fh->fpos =0;
|
||||
@@ -106,13 +102,12 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
|
||||
}
|
||||
|
||||
void ll_filesystem_file_close(FILE_HANDLE* handle) {
|
||||
if(handle!=NULL) { //passed handle is valid
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
|
||||
if(fh->file->isOpen()) { //if the file is still open
|
||||
fh->file->close(); //close the file
|
||||
if(handle!=NULL) {
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
|
||||
if(fh->file->isOpen()) {
|
||||
fh->file->close();
|
||||
}
|
||||
delete fh->file; //delete QFile instance
|
||||
delete fh; //delete the fle
|
||||
delete fh;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,18 +115,18 @@ FILE_STATUS ll_filesystem_file_seek(FILE_HANDLE* handle, uint32_t offset) {
|
||||
if(handle==NULL) {
|
||||
return F_INVALIDPARAM;
|
||||
}
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
|
||||
if(!fh->file->isOpen()) { //file is not open
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
|
||||
if(!fh->file->isOpen()) {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
if(offset>=fh->file->size()) { //offset exeeds filesize
|
||||
if(offset>=fh->file->size()) {
|
||||
return F_INVALIDPARAM;
|
||||
}
|
||||
|
||||
if(fh->file->seek(offset)) { //try to seek to desired offset
|
||||
fh->fpos = offset; //update offset in FILE_HANDLE (for user)
|
||||
if(fh->file->seek(offset)) {
|
||||
fh->fpos = offset;
|
||||
return F_OK;
|
||||
} else { //seek failed
|
||||
} else {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
}
|
||||
@@ -140,20 +135,20 @@ FILE_STATUS ll_filesystem_file_read(FILE_HANDLE* handle, uint8_t* buf, uint32_t
|
||||
if(handle==NULL || buf==NULL) {
|
||||
return F_INVALIDPARAM;
|
||||
}
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
|
||||
if(!fh->file->isOpen()) { //file is not open
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
|
||||
if(!fh->file->isOpen()) {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
if(!fh->file->isReadable()) { //file is not readable
|
||||
if(!fh->file->isReadable()) {
|
||||
return F_EACCESS;
|
||||
}
|
||||
qint64 bytesRead = fh->file->read((char*)buf,size); //try to read desired amount of bytes
|
||||
if(bytesRead<0) { //read failed
|
||||
qint64 bytesRead = fh->file->read((char*)buf,size);
|
||||
if(bytesRead<0) {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
fh->fpos+=bytesRead; //increase file position (for user)
|
||||
if(bytesRead!=size) { //we got less bytes than expected
|
||||
return F_EOF; //we reached the end of the file
|
||||
fh->fpos+=bytesRead;
|
||||
if(bytesRead!=size) {
|
||||
return F_EOF;
|
||||
} else {
|
||||
return F_OK;
|
||||
}
|
||||
@@ -163,22 +158,24 @@ FILE_STATUS ll_filesystem_file_write(FILE_HANDLE* handle, uint8_t* buf, uint32_t
|
||||
if(handle==NULL) {
|
||||
return F_INVALIDPARAM;
|
||||
}
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
|
||||
if(!fh->file->isOpen()) { //file is not open
|
||||
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
|
||||
if(!fh->file->isOpen()) {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
if(!fh->file->isWritable()) { //file is not writable
|
||||
if(!fh->file->isWritable()) {
|
||||
return F_EACCESS;
|
||||
}
|
||||
qint64 bytesWritten = fh->file->write((char*)buf,size); //try to write desired amount of bytes
|
||||
if(bytesWritten<0) { //write failed
|
||||
qint64 bytesWritten = fh->file->write((char*)buf,size);
|
||||
if(bytesWritten<0) {
|
||||
return F_DISKERROR;
|
||||
}
|
||||
fh->fpos+=bytesWritten; //increase file position (for user)
|
||||
if(bytesWritten!=size) { //we wrote less bytes than expected
|
||||
return F_EOF; //we reached the end of the file
|
||||
fh->fpos+=bytesWritten;
|
||||
if(bytesWritten!=size) {
|
||||
return F_EOF;
|
||||
} else {
|
||||
return F_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,18 +6,18 @@ extern "C" {
|
||||
}
|
||||
|
||||
bool ll_system_init() {
|
||||
return true; //nothing to initialize here, apart from the stuff which is done in the main method.
|
||||
return true;
|
||||
}
|
||||
|
||||
void ll_system_delay(uint32_t msec) {
|
||||
QThread::msleep(msec); //Let the app_process() Thread sleep
|
||||
QThread::msleep(msec);
|
||||
}
|
||||
|
||||
void ll_system_process() {
|
||||
QApplication::processEvents(); //Process pending qt events
|
||||
QThread::msleep(1); //Sleep for 1ms, to keep the cpu load down
|
||||
QApplication::processEvents();
|
||||
QThread::msleep(1);
|
||||
}
|
||||
|
||||
void ll_system_toggle_led() {
|
||||
//No led emulated :(
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QDebug>
|
||||
|
||||
extern "C" {
|
||||
#include "ll_tft.h"
|
||||
@@ -7,14 +8,13 @@ extern "C" {
|
||||
MainWindow* mainwindow;
|
||||
|
||||
bool ll_tft_init() {
|
||||
mainwindow = new MainWindow(); //create the designed window
|
||||
mainwindow->show(); //open it (non blocking)
|
||||
qDebug() << "tft init done";
|
||||
mainwindow = new MainWindow();
|
||||
mainwindow->show();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//the following functions redirect the call to the mainwindow, to a function with the same signature
|
||||
|
||||
void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
|
||||
mainwindow->draw_line(x1,y1,x2,y2,color);
|
||||
}
|
||||
@@ -44,17 +44,15 @@ void ll_tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) {
|
||||
}
|
||||
|
||||
uint8_t ll_tft_num_fonts() {
|
||||
return 2; //we have two fonts (see below)
|
||||
return 2;
|
||||
}
|
||||
|
||||
//Helper function to get the QFont to the corresponding font number
|
||||
//Note: only return monospaced fonts!!!
|
||||
QFont get_font(uint8_t fontnum) {
|
||||
switch(fontnum) {
|
||||
case 0:
|
||||
return QFont("Monospace",8);
|
||||
return QFont("Courier New",8);
|
||||
case 1:
|
||||
return QFont("DejaVu Sans Mono",14);
|
||||
return QFont("Courier New",14);
|
||||
default:
|
||||
return QFont();
|
||||
}
|
||||
@@ -64,20 +62,20 @@ QFont get_font(uint8_t fontnum) {
|
||||
uint8_t ll_tft_font_height(uint8_t fontnum) {
|
||||
QFont f = get_font(fontnum);
|
||||
if(f == QFont()) return -1;
|
||||
QFontMetrics m(f); //use font metcris object to calculate height of font
|
||||
QFontMetrics m(f);
|
||||
return m.height();
|
||||
}
|
||||
|
||||
uint8_t ll_tft_font_width(uint8_t fontnum) {
|
||||
QFont f = get_font(fontnum);
|
||||
if(f == QFont()) return -1;
|
||||
QFontMetrics m(f); //use font metcris object to calculate width of font
|
||||
QFontMetrics m(f);
|
||||
return m.averageCharWidth();
|
||||
}
|
||||
|
||||
void ll_tft_draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, char c) {
|
||||
QFont f = get_font(font);
|
||||
if(f == QFont()) return; //if the font is the default-font, we want to abort.
|
||||
if(f == QFont()) return;
|
||||
mainwindow->draw_char(x,y,color,bgcolor,f,c);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
extern "C" {
|
||||
//Imported C Functions from the common folder
|
||||
//C Functions from the common folder
|
||||
void app_init(); //Initializes the app
|
||||
void app_process(); //Processes one eventloop of the app
|
||||
}
|
||||
|
||||
void app_loop() {
|
||||
while(!QApplication::closingDown()) { //as long as the application is not terminating
|
||||
app_process(); //let the application process it's events
|
||||
while(!QApplication::closingDown()) {
|
||||
app_process();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication app(argc,argv); //Process qt-specific commandline arguments and create event loop
|
||||
app_init(); //Let the application initialize it self
|
||||
QApplication app(argc,argv);
|
||||
app_init();
|
||||
|
||||
QtConcurrent::run(&app_loop); //Start a thread that executes app_loop
|
||||
return app.exec(); //Run the event loop until the last window is closed.
|
||||
QtConcurrent::run(&app_loop);
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,18 +13,16 @@ extern "C" {
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 240
|
||||
|
||||
//function to calculate QColor out of a RGB565 16bit color
|
||||
QColor QColorFromRGB565(uint16_t color) {
|
||||
//interpolate colors
|
||||
|
||||
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5);
|
||||
int G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
|
||||
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5);
|
||||
return QColor::fromRgb(R8,G8,B8);
|
||||
}
|
||||
|
||||
//function to calculate QRgb out of a RGB565 16bit color
|
||||
QRgb QRgbFromRGB565(uint16_t color) {
|
||||
//interpolate colors
|
||||
|
||||
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5);
|
||||
int G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
|
||||
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5);
|
||||
@@ -34,137 +32,156 @@ QRgb QRgbFromRGB565(uint16_t color) {
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), image(DISPLAY_WIDTH,DISPLAY_HEIGHT, QImage::Format_RGB16), ui(new Ui::MainWindow){
|
||||
ui->setupUi(this);
|
||||
image.fill(Qt::black); //clear display buffer
|
||||
currentScale = 1; //start with scale factor 1
|
||||
ui->widgetDisplay->setMouseTracking(true); //enable mouse move events, even when mouse is not pressed
|
||||
ui->widgetDisplay->installEventFilter(this); //install event filter for "display" widget, so that we receive those events as well
|
||||
image.fill(Qt::black);
|
||||
currentScale = 1;
|
||||
ui->widgetDisplay->setMouseTracking(true);
|
||||
ui->widgetDisplay->installEventFilter(this);
|
||||
}
|
||||
|
||||
void MainWindow::draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
QPainter painter(&(image));
|
||||
painter.setPen(QColorFromRGB565(color));
|
||||
painter.drawLine(x1,y1,x2,y2);
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::draw_pixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
image.setPixel(x,y,QRgbFromRGB565(color));
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::clear(uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
image.fill(QColorFromRGB565(color));
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
QPainter painter(&(image));
|
||||
painter.setPen(QColorFromRGB565(color));
|
||||
painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1),abs((int)y2-(int)y1));
|
||||
painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1)+1,abs((int)y2-(int)y1)+1);
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
QPainter painter(&(image));
|
||||
painter.fillRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1)+1,abs((int)y2-(int)y1)+1,QColorFromRGB565(color));
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *dat)
|
||||
{
|
||||
//Creating a new image and access it directly is faster than setPixel
|
||||
QImage img(width,height,QImage::Format_RGB32); //create a new image
|
||||
QImage img(width,height,QImage::Format_RGB32);
|
||||
|
||||
for(int yi=0; yi<height; yi++) { //for each line
|
||||
uint32_t* line = (uint32_t*)img.scanLine(yi); //get the pointer to the imagedata of the current line
|
||||
for(int xi=0; xi<width; xi++) { //for each column
|
||||
*line++=QRgbFromRGB565(dat[yi*width+xi]); //set pixel
|
||||
for(int yi=0; yi<height; yi++) {
|
||||
uint32_t* line = (uint32_t*)img.scanLine(yi);
|
||||
for(int xi=0; xi<width; xi++) {
|
||||
*line++=QRgbFromRGB565(dat[yi*width+xi]);
|
||||
}
|
||||
}
|
||||
|
||||
//render_mutex.lock();
|
||||
QPainter p(&image);
|
||||
p.drawImage(x,y,img); //draw created image
|
||||
p.drawImage(x,y,img);
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
QPainter painter(&(image));
|
||||
painter.setPen(QColorFromRGB565(color));
|
||||
painter.drawEllipse(QPoint(x,y), r, r);
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, QFont font, char c)
|
||||
{
|
||||
//render_mutex.lock();
|
||||
QPainter painter(&(image));
|
||||
painter.setFont(font);
|
||||
|
||||
if(bgcolor!=TRANSPARENT) { //background color is not transparent
|
||||
if(bgcolor!=TRANSPARENT) {
|
||||
painter.setBackgroundMode(Qt::OpaqueMode);
|
||||
painter.setBackground(QColorFromRGB565(bgcolor)); //set text background
|
||||
painter.setBackground(QColorFromRGB565(bgcolor));
|
||||
}
|
||||
|
||||
painter.setPen(QColorFromRGB565(color)); //set fontcolor
|
||||
painter.setPen(QColorFromRGB565(color));
|
||||
y+=QFontMetrics(font).ascent(); //use y pos as highest point of char, instead of baseline
|
||||
painter.drawText(QPoint(x,y), QString(QChar(c))); //draw char
|
||||
painter.drawText(QPoint(x,y), QString(QChar(c)));
|
||||
//render_mutex.unlock();
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::paintEvent(QPaintEvent *)
|
||||
{
|
||||
//this method is called whenever the window needs to be redrawn (or after update() is called)
|
||||
//render_mutex.lock();
|
||||
QPainter painter(this);
|
||||
|
||||
//Create a QRectF which represents the rectangle to draw the buffered image to
|
||||
QRectF imgRect (ui->widgetDisplay->geometry().topLeft(),QSizeF(DISPLAY_WIDTH*currentScale,DISPLAY_HEIGHT*currentScale));
|
||||
|
||||
painter.drawImage(imgRect,image); //draw buffer
|
||||
painter.setPen(QPen(Qt::green,2)); //set border color
|
||||
painter.drawRect(imgRect.adjusted(-1,-1,1,1)); //draw border
|
||||
painter.drawImage(imgRect,image);
|
||||
painter.setPen(QPen(Qt::green,2));
|
||||
painter.drawRect(imgRect.adjusted(-1,-1,1,1));
|
||||
|
||||
|
||||
//render_mutex.unlock();
|
||||
}
|
||||
|
||||
void MainWindow::mousePressEvent(QMouseEvent *evt)
|
||||
{
|
||||
//the mouse was pressed
|
||||
//qDebug() << "down" << evt->pos();
|
||||
checkAndSendEvent(evt->pos(),true);
|
||||
}
|
||||
|
||||
void MainWindow::mouseReleaseEvent(QMouseEvent *evt)
|
||||
{
|
||||
//the mouse was released
|
||||
//qDebug() << "up" << evt->pos();
|
||||
checkAndSendEvent(evt->pos(),false);
|
||||
}
|
||||
|
||||
void MainWindow::mouseMoveEvent(QMouseEvent *evt)
|
||||
{
|
||||
//the mouse was released
|
||||
//qDebug() << "move" << evt->pos();
|
||||
checkAndSendEvent(evt->pos(),true);
|
||||
}
|
||||
|
||||
|
||||
bool MainWindow::eventFilter(QObject *obj, QEvent *evt)
|
||||
{
|
||||
if(obj==ui->widgetDisplay) { //we received a redirect event from the target rectangle
|
||||
if(obj==ui->widgetDisplay) {
|
||||
switch(evt->type()) {
|
||||
case QEvent::MouseMove: //it's a mouse move event
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt); //get mouse event
|
||||
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; //calculate correct corrdinates (undo scale)
|
||||
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) { //mouse position not out of bounds
|
||||
//set mouse position text
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt);
|
||||
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale;
|
||||
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) {
|
||||
ui->txtMousePos->setText(QString("Mouse Position: (%1,%2)").arg(p.x()).arg(p.y()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -176,16 +193,18 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::checkAndSendEvent(QPoint pos, bool down)
|
||||
{
|
||||
QPoint p = pos - ui->widgetDisplay->geometry().topLeft(); //make coordinate relative to target area (0,0)
|
||||
p/=currentScale; //undo scaling
|
||||
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return; //abort if out of bounds
|
||||
QPoint p = pos - ui->widgetDisplay->geometry().topLeft();
|
||||
p/=currentScale;
|
||||
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return;
|
||||
|
||||
touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP); //submit touch event to touch module (common)
|
||||
//qDebug() << down << p;
|
||||
|
||||
touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_cboZoom_currentIndexChanged(int index)
|
||||
{
|
||||
currentScale=index+1; //zoom factor 1 is the 0th entry, zoom factor 2 is the 1st entry, zoom factor 3 is the 2nd entry
|
||||
update(); //force redraw
|
||||
currentScale=index+1;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -33,11 +33,12 @@ protected:
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void on_cboZoom_currentIndexChanged(int index); //slot that is called when the zoomlevel changed
|
||||
void on_cboZoom_currentIndexChanged(int index);
|
||||
|
||||
private:
|
||||
QImage image; //Display buffer
|
||||
int currentScale; //current scale factor
|
||||
//QMutex render_mutex;
|
||||
QImage image;
|
||||
int currentScale;
|
||||
void checkAndSendEvent(QPoint pos, bool down);
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
26
emulator/readme_windows.txt
Normal file
26
emulator/readme_windows.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
Prerequisites:
|
||||
- Qt5 for Windows (provides C:\Qt\5.4\mingw491_32 and C:\Qt\Tools\mingw491_32)
|
||||
- Mingw msys-base (provides C:\MinGW\msys\1.0 and make, find )
|
||||
- Boost (check emulator\libs\boost)
|
||||
|
||||
Steps:
|
||||
- Open up the msys shell using the batchfile
|
||||
- Navigate to the emulator folder of the project
|
||||
- Source the qt binaries (qmake, gcc, g++) by executing
|
||||
export PATH=$PATH:/c/Qt/Tools/mingw491_32/bin:/c/Qt/5.4/mingw491_32/bin
|
||||
- navigate to libs/Pixy and execute make
|
||||
- navigate back into the emulator folder and execute make
|
||||
- this should generate you build/emulator.exe
|
||||
|
||||
Starting:
|
||||
- Extract windows_dlls.rar to the build folder
|
||||
- Copy the emulated folder into the build folder
|
||||
- Make sure that you installed the pixy usb driver (e.g. by installing pixymon http://cmucam.org/projects/cmucam5/wiki/Latest_release)
|
||||
- Start emulator.exe
|
||||
|
||||
Pitfalls:
|
||||
- libstdc++ must be provided by qt. do not use one of msys or mingw. you will waste hours with debugging of the make process
|
||||
|
||||
Sources:
|
||||
- libusb for windows was taken from https://github.com/charmedlabs/pixy/tree/master/src/host/windows
|
||||
- Boost was compiled from sources, using http://andres.jaimes.net/718/how-to-install-the-c-boost-libraries-on-windows/ and http://www.boost.org/doc/libs/1_58_0/more/getting_started/windows.html
|
||||
BIN
emulator/windows_dlls.rar
Normal file
BIN
emulator/windows_dlls.rar
Normal file
Binary file not shown.
Reference in New Issue
Block a user