3 Commits

Author SHA1 Message Date
t-moe
c32bfde94e Font fix for windows. 2015-06-06 14:35:01 +02:00
t-moe
129b7e0ee7 Cleaned up windows build, added readme. Added Boost binaries. 2015-06-06 14:29:37 +02:00
t-moe
0fa18290dd Changed makefile of emulator to run on windows. 2015-06-06 13:47:28 +02:00
36 changed files with 2204 additions and 316 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,5 +1,4 @@
#include "screen_tracking.h" #include "screen_tracking.h"
#include "pixy_control.h"
#include "button.h" #include "button.h"
#include "checkbox.h" #include "checkbox.h"
#include "tft.h" #include "tft.h"
@@ -81,19 +80,12 @@ typedef struct {
} TRACKING_CONFIG_STRUCT; } TRACKING_CONFIG_STRUCT;
//Methods for our tracking implementation ahead //Methods for our tracking implementation ahead
static int16_t servo_x = 0;
static int16_t servo_y = 0;
//Method/Callback to start our tracking //Method/Callback to start our tracking
void tracking_our_start(void* tracking_config) { void tracking_our_start(void* tracking_config) {
//Activate pixy's data send program //Activate pixy's data send program
int32_t response; int32_t response;
int return_value; 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); 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 //Method/Callback to calculate one step of our tracking
void tracking_our_update(void* tracking_config, struct Block* blocks, int num_blocks) { void tracking_our_update(void* tracking_config, struct Block* blocks, int num_blocks) {
//TODO: Implement tracking!
if(num_blocks <= 0){ // Check if there are blocks available //Calculate new servo pos and set the new servo pos
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
} }
//Variable which stores all the callbacks and settings for our tracking implementation //Variable which stores all the callbacks and settings for our tracking implementation

View File

@@ -6,10 +6,6 @@
* This makes it safe to change the screen from an touch interrupt (e.g. button callback) * 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_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 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 static volatile SCREEN_STRUCT* screen_goto = NULL; //Screen we should navigate to once we enter the gui_screen_update() method again

View File

@@ -12,7 +12,7 @@
/** /**
* @defgroup screen Screen * @defgroup screen Screen
* The Screen Submodule provides an api to navigate between different "screens" on the UI. * The Screen Submodule provides an api to navigate between different "screens" on the UI.
* Each screen must provide an enter, update and a leave method; which will be called from this module at the right time. * Each screen must provide an enter, update and a leave method; which will be called from this module at the right time.
* The implemented screens of the application are documented in the \ref screens module. * The implemented screens of the application are documented in the \ref screens module.
*/ */
/*@}*/ /*@}*/
@@ -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) * 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 * 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 * @param screen A Pointer to the preinitialized SCREEN_STRUCT
* @return true on success * @return true on success
*/ */

View File

@@ -12,6 +12,7 @@
/* Possible improvements: /* Possible improvements:
* Exchange pointer-list "areas" with a linked list. This would ensure that we can always accept new regions * 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 #define NUM_AREAS 50 //Number of Touch Areas we can manage

View File

@@ -273,7 +273,7 @@ static bool gpio_init()
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
// PORT_B init // PORT_B init -------------------------------------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
@@ -282,7 +282,7 @@ static bool gpio_init()
// configure PORT_B // configure PORT_B
GPIO_Init(GPIOB, &GPIO_InitStructure); 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_PinSource0, GPIO_AF_FSMC); // PD0=FSMC_D2 -> DB2
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC); // PD1=FSMC_D3 -> DB3 GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC); // PD1=FSMC_D3 -> DB3
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC); // PD4=FSMC_NOE -> RD GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC); // PD4=FSMC_NOE -> RD
@@ -305,7 +305,7 @@ static bool gpio_init()
// configure PORT_D // configure PORT_D
GPIO_Init(GPIOD, &GPIO_InitStructure); 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_PinSource3, GPIO_AF_FSMC); // PE3=FSMC_A19 -> RS
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC); // PE7=FSMC_D4 -> DB4 GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC); // PE7=FSMC_D4 -> DB4
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC); // PE8=FSMC_D5 -> DB5 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_PinSource13, GPIO_AF_FSMC); // PE13=FSMC_D10 -> DB12
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // PE14=FSMC_D11 -> DB13 GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // PE14=FSMC_D11 -> DB13
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // PE15=FSMC_D12 -> DB14 GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // PE15=FSMC_D12 -> DB14
// PORT_E struct // PORT_E struct
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | 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 | 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_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
// configure PORT_E // configure PORT_E
GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_Init(GPIOE, &GPIO_InitStructure);
@@ -336,8 +334,6 @@ static bool gpio_init()
/* /*
* ---------------------- display control functions ------------------------------------------------------- * ---------------------- display control functions -------------------------------------------------------
*/ */
// Clear the whole screen by filling it with a specifig color
void ll_tft_clear(uint16_t color) void ll_tft_clear(uint16_t color)
{ {
uint32_t n = 0; 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) static void tft_set_cursor(uint16_t xpos, uint16_t ypos)
{ {
// set cursor // set cursor
@@ -359,69 +354,61 @@ static void tft_set_cursor(uint16_t xpos, uint16_t ypos)
TFT_REG = TFT_SSD1289_REG_22; TFT_REG = TFT_SSD1289_REG_22;
} }
// Enable / Disable the backlight
static void tft_set_backlight(bool state) static void tft_set_backlight(bool state)
{ {
if(state){ // if state is true if(state){
GPIOB->BSRRH = GPIO_Pin_0; // set the backlight output GPIOB->BSRRH = GPIO_Pin_0;
} else { // else } else {
GPIOB->BSRRL = GPIO_Pin_0; // reset the backlight GPIOB->BSRRL = GPIO_Pin_0;
} }
} }
// Port operations on the screen RS PIN
static void tft_reset(bool state) static void tft_reset(bool state)
{ {
if(state){ // if state is ture if(state){
GPIOB->BSRRH = GPIO_Pin_0; // Set the reset pin GPIOB->BSRRH = GPIO_Pin_0;
} else { // else } else {
GPIOB->BSRRL = GPIO_Pin_0; // reset the reset pin 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) static void tft_write_reg(uint8_t reg_adr, uint16_t reg_value)
{ {
TFT_REG = reg_adr; // set adress TFT_REG = reg_adr;
TFT_RAM = reg_value; // send command TFT_RAM = reg_value;
} }
// Read a register value of the display controller
static uint16_t tft_read_reg(uint8_t reg_adr) static uint16_t tft_read_reg(uint8_t reg_adr)
{ {
TFT_REG = reg_adr; // set adress TFT_REG = reg_adr;
return TFT_RAM; // return value 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) static void tft_set_window(uint16_t xstart, uint16_t ystart, uint16_t xend, uint16_t yend)
{ {
uint16_t start,end; uint16_t start,end;
uint16_t ystart_end; uint16_t ystart_end;
start = (ystart & 0x00FF); // Start adress of the window start = (ystart & 0x00FF);
end = ((yend & 0x00FF) << 8); // End adress of the window end = ((yend & 0x00FF) << 8);
ystart_end = (start | end); // Calculate y endpoint ystart_end = (start | end);
tft_write_reg(TFT_SSD1289_REG_44, ystart_end); // Send y size tft_write_reg(TFT_SSD1289_REG_44, ystart_end);
tft_write_reg(TFT_SSD1289_REG_45, 319-xend); // Send x start tft_write_reg(TFT_SSD1289_REG_45, 319-xend);
tft_write_reg(TFT_SSD1289_REG_46, 319-xstart); // Send x end tft_write_reg(TFT_SSD1289_REG_46, 319-xstart);
} }
// Reset a Window
void tft_reset_window() void tft_reset_window()
{ {
// Commands according to the datasheet tft_write_reg(0x44,239<<8);
tft_write_reg(0x44, 239 << 8); tft_write_reg(0x45,0);
tft_write_reg(0x45, 0); tft_write_reg(0x46,319);
tft_write_reg(0x46, 319);
} }
/* /*
* ---------------------- draw functions ----------------------------------------------------------- * ---------------------- 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) 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 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) void ll_tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color)
{ {
tft_set_cursor(x,y); // Set the cursor position tft_set_cursor(x,y);
TFT_RAM = color; // Draw the pixel 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) void ll_tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{ {
unsigned int tmp; 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) void ll_tft_fill_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color)
{ {
uint16_t area; uint16_t area;

BIN
doc/PID_REGELUNG.tgz Normal file

Binary file not shown.

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.

Binary file not shown.

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
View File

@@ -5,8 +5,9 @@ qt/*.o
qt/*.a qt/*.a
qt/ui_* qt/ui_*
qt/moc_* qt/moc_*
qt/Makefile qt/Makefile*
qt/debug
qt/release
libs/*/obj libs/*/obj
libs/*/*.a libs/*/*.a

View File

@@ -10,7 +10,7 @@ QT_DIR=./qt
COMMON_DIR=../common COMMON_DIR=../common
#Tools #Tools
CC=gcc -fdiagnostics-color=auto CC=gcc #-fdiagnostics=auto
GDB=gdb GDB=gdb
@@ -24,17 +24,22 @@ INCLUDES:=$(addprefix -I,$(INCLUDES))
QT_LIB=$(QT_DIR)/libemulatorqt.a 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 CFLAGS= -O0 -g -std=c99
LIBS= pixy usb-1.0 boost_system boost_timer boost_chrono LIBS= emulatorqt pixy usb-1.0
LIBS+=Qt5Core Qt5Gui Qt5Widgets emulatorqt m stdc++ 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= -static-libgcc -static-libstdc++ #-Wl,-t -Wl,--Map=a.map
LDFLAGS= -L$(QT_DIR) $(addprefix -l,$(LIBS)) LDFLAGS+= -L$(QT_DIR)
LDFLAGS+= -L$(LIB_DIR)/Pixy 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 #Finding Input files
CFILES=$(shell find . -maxdepth 1 -name '*.c') CFILES=$(shell find . -maxdepth 1 -name '*.c')
@@ -58,7 +63,7 @@ debug: all
$(GDB) ./build/emulator $(GDB) ./build/emulator
$(QT_LIB): $(QT_LIB):
cd $(QT_DIR) && qmake &&make cd $(QT_DIR) && qmake && $(MAKE)
#objects to elf #objects to elf
$(BUILD_DIR)/$(TARGET): $(OBJS) $(COMMON_OBJS) $(QT_LIB) $(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 Obj files and builded stuff
clean: 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) $(RMDIR) $(BUILD_DIR) $(OBJ_DIR)

View File

@@ -17,11 +17,13 @@ OBJ_DIR=./obj
#Architecture flags #Architecture flags
#Compiler, Linker Options #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=$(ARCH_FLAGS) -O0 -g #-ffunction-sections -fdata-sections -g
#CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork #CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
#CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 #CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS+=-I/usr/include/libusb-1.0 CFLAGS+=-I/usr/include/libusb-1.0
CFLAGS+=-I../boost/include/
CFLAGS+=-I./windows/
#Finding Input files #Finding Input files
CFILES=$(shell find $(SRC_DIR) -name '*.cpp') CFILES=$(shell find $(SRC_DIR) -name '*.cpp')

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

2
emulator/libs/boost/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
include
lib

Binary file not shown.

View 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

View File

@@ -8,7 +8,7 @@ QT += widgets gui
TARGET = emulatorqt TARGET = emulatorqt
TEMPLATE = lib TEMPLATE = lib
CONFIG += staticlib CONFIG += staticlib debug
SOURCES += \ SOURCES += \
mainwindow.cpp \ mainwindow.cpp \
@@ -30,3 +30,6 @@ INCLUDEPATH+= ../../common/lowlevel/ \
FORMS += \ FORMS += \
mainwindow.ui mainwindow.ui
DESTDIR = $$_PRO_FILE_PWD_ #force windows to not create subfolders
#QMAKE_CXXFLAGS+= -v

View File

@@ -7,53 +7,51 @@ extern "C" {
#include <QFileInfoList> #include <QFileInfoList>
#include <QDateTime> #include <QDateTime>
QDir rootdir ("./emulated"); //Create a QDir which points to the "root" of the emulated filesystem QDir rootdir ("./emulated");
bool ll_filesystem_init() { 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"; qWarning() << "Filesystem can not be emulated because the 'emulated' folder does not exist";
return false; //mark an error return false;
} }
return true; return true;
} }
DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) { DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) {
QDir d(rootdir); //Make a copy of the rootdir QDir instance QDir d(rootdir);
d.cd(path); //Change the directory to the passed path d.cd(path);
if(!d.exists()) { if(!d.exists()) {
return NULL; //mark an error return NULL;
} }
DIRECTORY_STRUCT* directory = new DIRECTORY_STRUCT(); 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); 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->path = path;
directory->num_files = entries.count(); 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); 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->fattrib = 0;
entry->fname = new char[fi.fileName().length()+1]; //reserve memory for filename entry->fname = new char[fi.fileName().length()+1];
strcpy(entry->fname,fi.fileName().toStdString().c_str()); //copy filename into struct strcpy(entry->fname,fi.fileName().toStdString().c_str());
if(fi.isDir()) { //it's a direcory if(fi.isDir()) {
entry->fattrib|=F_DIR; //set directory attribute entry->fattrib|=F_DIR;
entry->fsize = 0; entry->fsize = 0;
} else { //it's a file } else {
entry->fsize = fi.size(); //set filesize entry->fsize = fi.size();
} }
if(fi.isHidden()) { //the file is hidden if(fi.isHidden()) {
entry->fattrib|=F_HID; entry->fattrib|=F_HID;
} }
if(!fi.isWritable()) { //the file is not writable if(!fi.isWritable()) {
entry->fattrib|=F_RDO; //set readonly attribue entry->fattrib|=F_RDO;
} }
//Set date & time of file in structure
QDateTime dt = fi.lastModified(); 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.month = dt.date().month();
entry->fdate.day = dt.date().day(); entry->fdate.day = dt.date().day();
entry->ftime.hour = dt.time().hour(); 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) { void ll_filesystem_dir_close(DIRECTORY_STRUCT* dir) {
if(dir!=NULL) { //passed handle is valid if(dir!=NULL) {
for(int i=0; i<dir->num_files; i++) { //foreach file for(int i=0; i<dir->num_files; i++) {
delete dir->files[i].fname; //delete filename buffer delete dir->files[i].fname;
} }
delete[] dir->files; //delete file array delete[] dir->files;
delete dir; //delete structure itself 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) struct QT_FILE_HANDLE : FILE_HANDLE {
QFile* file; //Pointer to the open QFile* instance QFile* file;
}; };
@@ -85,19 +83,17 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
if(!rootdir.exists()) { if(!rootdir.exists()) {
return NULL; return NULL;
} }
QString filepath = rootdir.absoluteFilePath(filename); //get the absolute path to the requested file QString filepath = rootdir.absoluteFilePath(filename);
QFile* f = new QFile(filepath); //create a QFile instance to the requested file QFile* f = new QFile(filepath);
if(!f->exists()) { //File does not exist if(!f->exists()) {
return NULL; //mark error return NULL;
} }
if(!f->open(QFile::ReadWrite)) { //try to open the file, it it fails then ... if(!f->open(QFile::ReadWrite)) {
return NULL; //... mark error return NULL;
} }
//At this point we have a valid QFile instance, pointing to an existing file QT_FILE_HANDLE* fh = new QT_FILE_HANDLE();
QT_FILE_HANDLE* fh = new QT_FILE_HANDLE(); //Create Structure to return to user
fh->file = f; fh->file = f;
fh->fname = filename; fh->fname = filename;
fh->fpos =0; fh->fpos =0;
@@ -106,13 +102,12 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
} }
void ll_filesystem_file_close(FILE_HANDLE* handle) { void ll_filesystem_file_close(FILE_HANDLE* handle) {
if(handle!=NULL) { //passed handle is valid if(handle!=NULL) {
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
if(fh->file->isOpen()) { //if the file is still open if(fh->file->isOpen()) {
fh->file->close(); //close the file fh->file->close();
} }
delete fh->file; //delete QFile instance delete fh;
delete fh; //delete the fle
} }
} }
@@ -120,18 +115,18 @@ FILE_STATUS ll_filesystem_file_seek(FILE_HANDLE* handle, uint32_t offset) {
if(handle==NULL) { if(handle==NULL) {
return F_INVALIDPARAM; return F_INVALIDPARAM;
} }
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
if(!fh->file->isOpen()) { //file is not open if(!fh->file->isOpen()) {
return F_DISKERROR; return F_DISKERROR;
} }
if(offset>=fh->file->size()) { //offset exeeds filesize if(offset>=fh->file->size()) {
return F_INVALIDPARAM; return F_INVALIDPARAM;
} }
if(fh->file->seek(offset)) { //try to seek to desired offset if(fh->file->seek(offset)) {
fh->fpos = offset; //update offset in FILE_HANDLE (for user) fh->fpos = offset;
return F_OK; return F_OK;
} else { //seek failed } else {
return F_DISKERROR; 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) { if(handle==NULL || buf==NULL) {
return F_INVALIDPARAM; return F_INVALIDPARAM;
} }
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
if(!fh->file->isOpen()) { //file is not open if(!fh->file->isOpen()) {
return F_DISKERROR; return F_DISKERROR;
} }
if(!fh->file->isReadable()) { //file is not readable if(!fh->file->isReadable()) {
return F_EACCESS; return F_EACCESS;
} }
qint64 bytesRead = fh->file->read((char*)buf,size); //try to read desired amount of bytes qint64 bytesRead = fh->file->read((char*)buf,size);
if(bytesRead<0) { //read failed if(bytesRead<0) {
return F_DISKERROR; return F_DISKERROR;
} }
fh->fpos+=bytesRead; //increase file position (for user) fh->fpos+=bytesRead;
if(bytesRead!=size) { //we got less bytes than expected if(bytesRead!=size) {
return F_EOF; //we reached the end of the file return F_EOF;
} else { } else {
return F_OK; return F_OK;
} }
@@ -163,22 +158,24 @@ FILE_STATUS ll_filesystem_file_write(FILE_HANDLE* handle, uint8_t* buf, uint32_t
if(handle==NULL) { if(handle==NULL) {
return F_INVALIDPARAM; return F_INVALIDPARAM;
} }
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle);
if(!fh->file->isOpen()) { //file is not open if(!fh->file->isOpen()) {
return F_DISKERROR; return F_DISKERROR;
} }
if(!fh->file->isWritable()) { //file is not writable if(!fh->file->isWritable()) {
return F_EACCESS; return F_EACCESS;
} }
qint64 bytesWritten = fh->file->write((char*)buf,size); //try to write desired amount of bytes qint64 bytesWritten = fh->file->write((char*)buf,size);
if(bytesWritten<0) { //write failed if(bytesWritten<0) {
return F_DISKERROR; return F_DISKERROR;
} }
fh->fpos+=bytesWritten; //increase file position (for user) fh->fpos+=bytesWritten;
if(bytesWritten!=size) { //we wrote less bytes than expected if(bytesWritten!=size) {
return F_EOF; //we reached the end of the file return F_EOF;
} else { } else {
return F_OK; return F_OK;
} }
} }

View File

@@ -6,18 +6,18 @@ extern "C" {
} }
bool ll_system_init() { 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) { void ll_system_delay(uint32_t msec) {
QThread::msleep(msec); //Let the app_process() Thread sleep QThread::msleep(msec);
} }
void ll_system_process() { void ll_system_process() {
QApplication::processEvents(); //Process pending qt events QApplication::processEvents();
QThread::msleep(1); //Sleep for 1ms, to keep the cpu load down QThread::msleep(1);
} }
void ll_system_toggle_led() { void ll_system_toggle_led() {
//No led emulated :(
} }

View File

@@ -1,4 +1,5 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QDebug>
extern "C" { extern "C" {
#include "ll_tft.h" #include "ll_tft.h"
@@ -7,14 +8,13 @@ extern "C" {
MainWindow* mainwindow; MainWindow* mainwindow;
bool ll_tft_init() { bool ll_tft_init() {
mainwindow = new MainWindow(); //create the designed window qDebug() << "tft init done";
mainwindow->show(); //open it (non blocking) mainwindow = new MainWindow();
mainwindow->show();
return true; 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) { 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); 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() { 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) { QFont get_font(uint8_t fontnum) {
switch(fontnum) { switch(fontnum) {
case 0: case 0:
return QFont("Monospace",8); return QFont("Courier New",8);
case 1: case 1:
return QFont("DejaVu Sans Mono",14); return QFont("Courier New",14);
default: default:
return QFont(); return QFont();
} }
@@ -64,20 +62,20 @@ QFont get_font(uint8_t fontnum) {
uint8_t ll_tft_font_height(uint8_t fontnum) { uint8_t ll_tft_font_height(uint8_t fontnum) {
QFont f = get_font(fontnum); QFont f = get_font(fontnum);
if(f == QFont()) return -1; if(f == QFont()) return -1;
QFontMetrics m(f); //use font metcris object to calculate height of font QFontMetrics m(f);
return m.height(); return m.height();
} }
uint8_t ll_tft_font_width(uint8_t fontnum) { uint8_t ll_tft_font_width(uint8_t fontnum) {
QFont f = get_font(fontnum); QFont f = get_font(fontnum);
if(f == QFont()) return -1; if(f == QFont()) return -1;
QFontMetrics m(f); //use font metcris object to calculate width of font QFontMetrics m(f);
return m.averageCharWidth(); 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) { 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); 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); mainwindow->draw_char(x,y,color,bgcolor,f,c);
} }

View File

@@ -2,23 +2,23 @@
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
extern "C" { extern "C" {
//Imported C Functions from the common folder //C Functions from the common folder
void app_init(); //Initializes the app void app_init(); //Initializes the app
void app_process(); //Processes one eventloop of the app void app_process(); //Processes one eventloop of the app
} }
void app_loop() { void app_loop() {
while(!QApplication::closingDown()) { //as long as the application is not terminating while(!QApplication::closingDown()) {
app_process(); //let the application process it's events app_process();
} }
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QApplication app(argc,argv); //Process qt-specific commandline arguments and create event loop QApplication app(argc,argv);
app_init(); //Let the application initialize it self app_init();
QtConcurrent::run(&app_loop); //Start a thread that executes app_loop QtConcurrent::run(&app_loop);
return app.exec(); //Run the event loop until the last window is closed. return app.exec();
} }

View File

@@ -13,18 +13,16 @@ extern "C" {
#define DISPLAY_WIDTH 320 #define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240 #define DISPLAY_HEIGHT 240
//function to calculate QColor out of a RGB565 16bit color
QColor QColorFromRGB565(uint16_t color) { QColor QColorFromRGB565(uint16_t color) {
//interpolate colors
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5); 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 G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5); int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5);
return QColor::fromRgb(R8,G8,B8); return QColor::fromRgb(R8,G8,B8);
} }
//function to calculate QRgb out of a RGB565 16bit color
QRgb QRgbFromRGB565(uint16_t color) { QRgb QRgbFromRGB565(uint16_t color) {
//interpolate colors
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5); 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 G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.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){ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), image(DISPLAY_WIDTH,DISPLAY_HEIGHT, QImage::Format_RGB16), ui(new Ui::MainWindow){
ui->setupUi(this); ui->setupUi(this);
image.fill(Qt::black); //clear display buffer image.fill(Qt::black);
currentScale = 1; //start with scale factor 1 currentScale = 1;
ui->widgetDisplay->setMouseTracking(true); //enable mouse move events, even when mouse is not pressed ui->widgetDisplay->setMouseTracking(true);
ui->widgetDisplay->installEventFilter(this); //install event filter for "display" widget, so that we receive those events as well ui->widgetDisplay->installEventFilter(this);
} }
void MainWindow::draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) 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)); QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color)); painter.setPen(QColorFromRGB565(color));
painter.drawLine(x1,y1,x2,y2); painter.drawLine(x1,y1,x2,y2);
//render_mutex.unlock();
update(); update();
} }
void MainWindow::draw_pixel(uint16_t x, uint16_t y, uint16_t color) void MainWindow::draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{ {
//render_mutex.lock();
image.setPixel(x,y,QRgbFromRGB565(color)); image.setPixel(x,y,QRgbFromRGB565(color));
//render_mutex.unlock();
update(); update();
} }
void MainWindow::clear(uint16_t color) void MainWindow::clear(uint16_t color)
{ {
//render_mutex.lock();
image.fill(QColorFromRGB565(color)); image.fill(QColorFromRGB565(color));
//render_mutex.unlock();
update(); update();
} }
void MainWindow::draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) 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)); QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color)); 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(); update();
} }
void MainWindow::fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) 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)); 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)); 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(); update();
} }
void MainWindow::draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *dat) 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 //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 for(int yi=0; yi<height; yi++) {
uint32_t* line = (uint32_t*)img.scanLine(yi); //get the pointer to the imagedata of the current line uint32_t* line = (uint32_t*)img.scanLine(yi);
for(int xi=0; xi<width; xi++) { //for each column for(int xi=0; xi<width; xi++) {
*line++=QRgbFromRGB565(dat[yi*width+xi]); //set pixel *line++=QRgbFromRGB565(dat[yi*width+xi]);
} }
} }
//render_mutex.lock();
QPainter p(&image); QPainter p(&image);
p.drawImage(x,y,img); //draw created image p.drawImage(x,y,img);
//render_mutex.unlock();
update(); update();
} }
void MainWindow::draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) void MainWindow::draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color)
{ {
//render_mutex.lock();
QPainter painter(&(image)); QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color)); painter.setPen(QColorFromRGB565(color));
painter.drawEllipse(QPoint(x,y), r, r); painter.drawEllipse(QPoint(x,y), r, r);
//render_mutex.unlock();
update(); update();
} }
void MainWindow::draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, QFont font, char c) 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)); QPainter painter(&(image));
painter.setFont(font); painter.setFont(font);
if(bgcolor!=TRANSPARENT) { //background color is not transparent if(bgcolor!=TRANSPARENT) {
painter.setBackgroundMode(Qt::OpaqueMode); 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 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(); update();
} }
void MainWindow::paintEvent(QPaintEvent *) 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); 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)); QRectF imgRect (ui->widgetDisplay->geometry().topLeft(),QSizeF(DISPLAY_WIDTH*currentScale,DISPLAY_HEIGHT*currentScale));
painter.drawImage(imgRect,image); //draw buffer painter.drawImage(imgRect,image);
painter.setPen(QPen(Qt::green,2)); //set border color painter.setPen(QPen(Qt::green,2));
painter.drawRect(imgRect.adjusted(-1,-1,1,1)); //draw border painter.drawRect(imgRect.adjusted(-1,-1,1,1));
//render_mutex.unlock();
} }
void MainWindow::mousePressEvent(QMouseEvent *evt) void MainWindow::mousePressEvent(QMouseEvent *evt)
{ {
//the mouse was pressed //qDebug() << "down" << evt->pos();
checkAndSendEvent(evt->pos(),true); checkAndSendEvent(evt->pos(),true);
} }
void MainWindow::mouseReleaseEvent(QMouseEvent *evt) void MainWindow::mouseReleaseEvent(QMouseEvent *evt)
{ {
//the mouse was released //qDebug() << "up" << evt->pos();
checkAndSendEvent(evt->pos(),false); checkAndSendEvent(evt->pos(),false);
} }
void MainWindow::mouseMoveEvent(QMouseEvent *evt) void MainWindow::mouseMoveEvent(QMouseEvent *evt)
{ {
//the mouse was released //qDebug() << "move" << evt->pos();
checkAndSendEvent(evt->pos(),true); checkAndSendEvent(evt->pos(),true);
} }
bool MainWindow::eventFilter(QObject *obj, QEvent *evt) 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()) { switch(evt->type()) {
case QEvent::MouseMove: //it's a mouse move event case QEvent::MouseMove:
{ {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt); //get mouse event QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt);
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; //calculate correct corrdinates (undo scale) QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale;
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) { //mouse position not out of bounds if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) {
//set mouse position text
ui->txtMousePos->setText(QString("Mouse Position: (%1,%2)").arg(p.x()).arg(p.y())); ui->txtMousePos->setText(QString("Mouse Position: (%1,%2)").arg(p.x()).arg(p.y()));
} }
} }
break; break;
default: break; default: break;
} }
} }
return false; return false;
} }
@@ -176,16 +193,18 @@ MainWindow::~MainWindow()
void MainWindow::checkAndSendEvent(QPoint pos, bool down) void MainWindow::checkAndSendEvent(QPoint pos, bool down)
{ {
QPoint p = pos - ui->widgetDisplay->geometry().topLeft(); //make coordinate relative to target area (0,0) QPoint p = pos - ui->widgetDisplay->geometry().topLeft();
p/=currentScale; //undo scaling p/=currentScale;
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return; //abort if out of bounds 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) 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 currentScale=index+1;
update(); //force redraw update();
} }

View File

@@ -33,11 +33,12 @@ protected:
~MainWindow(); ~MainWindow();
private slots: private slots:
void on_cboZoom_currentIndexChanged(int index); //slot that is called when the zoomlevel changed void on_cboZoom_currentIndexChanged(int index);
private: private:
QImage image; //Display buffer //QMutex render_mutex;
int currentScale; //current scale factor QImage image;
int currentScale;
void checkAndSendEvent(QPoint pos, bool down); void checkAndSendEvent(QPoint pos, bool down);
Ui::MainWindow *ui; Ui::MainWindow *ui;

View 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

Binary file not shown.