24 Commits

Author SHA1 Message Date
id101010
f18a936129 Updated PID values with Ziegler/Nichols 2015-06-08 11:10:26 +02:00
id101010
72dc291e4d Corrected some Errors 2015-06-07 23:26:32 +02:00
id101010
20b20f10c1 Added Fazit and a picture 2015-06-07 22:04:10 +02:00
id101010
d006dbd6a5 Wrote even more documentation 2015-06-07 18:58:20 +02:00
id101010
7e3de6af80 Merge remote-tracking branch 'origin/master' into dev_aaron 2015-06-07 17:02:47 +02:00
t-moe
f432236628 Merge remote-tracking branch 'origin/dev_aaron' 2015-06-07 17:01:59 +02:00
id101010
ce27acef98 Added pictures 2015-06-07 16:57:21 +02:00
t-moe
87523569a7 Started with tests in docu. fixed a small bug in emulator when drawing a rectangle. 2015-06-07 16:45:06 +02:00
id101010
33815f0d6c Documentated TFT, Touch, PID, System 2015-06-07 16:43:03 +02:00
t-moe
4b5768cedc Improved Comments in whole emulator. Finalized emulator section in docu. 2015-06-07 15:29:46 +02:00
t-moe
3e4fbab00a Merge remote-tracking branch 'origin/dev_aaron' into emulator 2015-06-07 13:48:25 +02:00
t-moe
ca1459d9d4 Copied doc resources from master branch. 2015-06-07 13:46:13 +02:00
id101010
3d98ca93bc Minor changes 2015-06-07 13:41:07 +02:00
t-moe
422b1a623c Updated Docu from Emulator. 2015-06-07 13:39:29 +02:00
id101010
802d3df373 Fixed pid controller and refactored code 2015-06-07 13:13:49 +02:00
t-moe
f004cbffa6 Updated Docu: Documented touch module and systemmodule. Improved already documented topics. 2015-06-07 00:02:23 +02:00
t-moe
c06661d25b Fixed some outdated comments in source code. Documented Gui Module in docu. 2015-06-06 20:10:10 +02:00
t-moe
ef467d0fee Merge remote-tracking branch 'origin/dev_aaron' into emulator 2015-06-06 19:07:10 +02:00
t-moe
fb652e3670 Updated docu: Added links to online doxygen docu. Added some description to app module doc. 2015-06-06 19:01:30 +02:00
id101010
a04cda9fc2 Refactured comments and implemented a bugfix for the PID controller 2015-06-06 18:51:57 +02:00
id101010
8c264c237a Comment refactoring, updated PID values 2015-06-06 18:19:28 +02:00
t-moe
6db62a6b50 Completed Docu for Pixy&Usb. Started with new table structure for other parts. 2015-06-06 18:09:33 +02:00
id101010
e018a75cd3 Implemented basic pi and pid controller 2015-06-02 16:25:45 +02:00
id101010
7ad16797ab Merge remote-tracking branch 'origin/emulator' into dev_aaron 2015-06-01 21:34:32 +02:00
36 changed files with 316 additions and 2204 deletions

73
common/app/pixy_control.c Normal file
View File

@@ -0,0 +1,73 @@
/*
* 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;
}

14
common/app/pixy_control.h Normal file
View File

@@ -0,0 +1,14 @@
/*
* 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,4 +1,5 @@
#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"
@@ -80,12 +81,19 @@ 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);
} }
@@ -99,8 +107,31 @@ 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!
//Calculate new servo pos and set the new servo pos 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
} }
//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,6 +6,10 @@
* 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

@@ -44,6 +44,7 @@ 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,7 +12,6 @@
/* 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,6 +316,7 @@ 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 |
@@ -325,6 +326,7 @@ 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);
@@ -334,6 +336,8 @@ 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;
@@ -346,6 +350,7 @@ 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
@@ -354,52 +359,59 @@ 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){ // if state is true
GPIOB->BSRRH = GPIO_Pin_0; GPIOB->BSRRH = GPIO_Pin_0; // set the backlight output
} else { } else { // else
GPIOB->BSRRL = GPIO_Pin_0; GPIOB->BSRRL = GPIO_Pin_0; // reset the backlight
} }
} }
// Port operations on the screen RS PIN
static void tft_reset(bool state) static void tft_reset(bool state)
{ {
if(state){ if(state){ // if state is ture
GPIOB->BSRRH = GPIO_Pin_0; GPIOB->BSRRH = GPIO_Pin_0; // Set the reset pin
} else { } else { // else
GPIOB->BSRRL = GPIO_Pin_0; GPIOB->BSRRL = GPIO_Pin_0; // reset the reset pin
} }
} }
// 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; TFT_REG = reg_adr; // set adress
TFT_RAM = reg_value; TFT_RAM = reg_value; // send command
} }
// 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; TFT_REG = reg_adr; // set adress
return TFT_RAM; return TFT_RAM; // return value
} }
// 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 = (ystart & 0x00FF); // Start adress of the window
end = ((yend & 0x00FF) << 8); end = ((yend & 0x00FF) << 8); // End adress of the window
ystart_end = (start | end); ystart_end = (start | end); // Calculate y endpoint
tft_write_reg(TFT_SSD1289_REG_44, ystart_end); tft_write_reg(TFT_SSD1289_REG_44, ystart_end); // Send y size
tft_write_reg(TFT_SSD1289_REG_45, 319-xend); tft_write_reg(TFT_SSD1289_REG_45, 319-xend); // Send x start
tft_write_reg(TFT_SSD1289_REG_46, 319-xstart); tft_write_reg(TFT_SSD1289_REG_46, 319-xstart); // Send x end
} }
// 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);
@@ -409,6 +421,7 @@ void tft_reset_window()
* ---------------------- 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
@@ -462,12 +475,14 @@ 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); tft_set_cursor(x,y); // Set the cursor position
TFT_RAM = color; TFT_RAM = color; // Draw the pixel
} }
// 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;
@@ -508,6 +523,7 @@ 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;

Binary file not shown.

Binary file not shown.

BIN
doc/analyse_touch.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
doc/datasheet_ssd1289.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
doc/idpa_software.tar.gz Normal file

Binary file not shown.

BIN
doc/screenshot_emulator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

5
emulator/.gitignore vendored
View File

@@ -5,9 +5,8 @@ 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=auto CC=gcc -fdiagnostics-color=auto
GDB=gdb GDB=gdb
@@ -24,22 +24,17 @@ INCLUDES:=$(addprefix -I,$(INCLUDES))
QT_LIB=$(QT_DIR)/libemulatorqt.a QT_LIB=$(QT_DIR)/libemulatorqt.a
CPPFLAGS= -march=x86-64 -mtune=generic #-fPIC CPPFLAGS= -march=x86-64 -mtune=generic -fPIC $(INCLUDES)
CPPFLAGS+= $(INCLUDES)
CFLAGS= -O0 -g -std=c99 CFLAGS= -O0 -g -std=c99
LIBS= emulatorqt pixy usb-1.0 LIBS= pixy usb-1.0 boost_system boost_timer boost_chrono
LIBS+= boost_system-mgw49-mt-1_58 boost_timer-mgw49-mt-1_58 boost_chrono-mgw49-mt-1_58 LIBS+=Qt5Core Qt5Gui Qt5Widgets emulatorqt m stdc++
LIBS+= Qt5Core Qt5Gui Qt5Widgets m stdc++
LDFLAGS= -static-libgcc -static-libstdc++ #-Wl,-t -Wl,--Map=a.map
LDFLAGS+= -L$(QT_DIR) LDFLAGS= -L$(QT_DIR) $(addprefix -l,$(LIBS))
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')
@@ -63,7 +58,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)
@@ -88,7 +83,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 && $(RMDIR) debug release cd $(QT_DIR) && $(MAKE) clean && $(RM) Makefile && $(RM) *.a
$(RMDIR) $(BUILD_DIR) $(OBJ_DIR) $(RMDIR) $(BUILD_DIR) $(OBJ_DIR)

View File

@@ -17,13 +17,11 @@ OBJ_DIR=./obj
#Architecture flags #Architecture flags
#Compiler, Linker Options #Compiler, Linker Options
CPPFLAGS=-I$(INC_DIR) -DHOST=1 #-D__LINUX__=1 -DDEBUG=1 CPPFLAGS=-I$(INC_DIR) -D__LINUX__=1 -DHOST=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')

File diff suppressed because it is too large Load Diff

View File

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

Binary file not shown.

View File

@@ -1,2 +0,0 @@
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 debug CONFIG += staticlib
SOURCES += \ SOURCES += \
mainwindow.cpp \ mainwindow.cpp \
@@ -30,6 +30,3 @@ 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,51 +7,53 @@ extern "C" {
#include <QFileInfoList> #include <QFileInfoList>
#include <QDateTime> #include <QDateTime>
QDir rootdir ("./emulated"); QDir rootdir ("./emulated"); //Create a QDir which points to the "root" of the emulated filesystem
bool ll_filesystem_init() { bool ll_filesystem_init() {
if(!rootdir.exists()) { if(!rootdir.exists()) { //if our root dir is nonexistent
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; return false; //mark an error
} }
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); QDir d(rootdir); //Make a copy of the rootdir QDir instance
d.cd(path); d.cd(path); //Change the directory to the passed path
if(!d.exists()) { if(!d.exists()) {
return NULL; return NULL; //mark an error
} }
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]; directory->files = new FILE_STRUCT[directory->num_files]; //allocate array of file structs
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]); FILE_STRUCT* entry = &(directory->files[i]); //get the pointer to the current filestruct (which should be filled)
entry->fattrib = 0; entry->fattrib = 0;
entry->fname = new char[fi.fileName().length()+1]; entry->fname = new char[fi.fileName().length()+1]; //reserve memory for filename
strcpy(entry->fname,fi.fileName().toStdString().c_str()); strcpy(entry->fname,fi.fileName().toStdString().c_str()); //copy filename into struct
if(fi.isDir()) { if(fi.isDir()) { //it's a direcory
entry->fattrib|=F_DIR; entry->fattrib|=F_DIR; //set directory attribute
entry->fsize = 0; entry->fsize = 0;
} else { } else { //it's a file
entry->fsize = fi.size(); entry->fsize = fi.size(); //set filesize
} }
if(fi.isHidden()) { if(fi.isHidden()) { //the file is hidden
entry->fattrib|=F_HID; entry->fattrib|=F_HID;
} }
if(!fi.isWritable()) { if(!fi.isWritable()) { //the file is not writable
entry->fattrib|=F_RDO; entry->fattrib|=F_RDO; //set readonly attribue
} }
//Set date & time of file in structure
QDateTime dt = fi.lastModified(); QDateTime dt = fi.lastModified();
entry->fdate.year = dt.date().year()-1980; entry->fdate.year = dt.date().year()-1980; //year is realtive to 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();
@@ -60,22 +62,22 @@ DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) {
} }
return directory; return directory; //return filled directory struct
} }
void ll_filesystem_dir_close(DIRECTORY_STRUCT* dir) { void ll_filesystem_dir_close(DIRECTORY_STRUCT* dir) {
if(dir!=NULL) { if(dir!=NULL) { //passed handle is valid
for(int i=0; i<dir->num_files; i++) { for(int i=0; i<dir->num_files; i++) { //foreach file
delete dir->files[i].fname; delete dir->files[i].fname; //delete filename buffer
} }
delete[] dir->files; delete[] dir->files; //delete file array
delete dir; delete dir; //delete structure itself
} }
} }
//Struct that represents a file handle for the emulator
struct QT_FILE_HANDLE : FILE_HANDLE { struct QT_FILE_HANDLE : FILE_HANDLE { //..derived from the FILE_HANDLE (of the Filesystem modul)
QFile* file; QFile* file; //Pointer to the open QFile* instance
}; };
@@ -83,17 +85,19 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
if(!rootdir.exists()) { if(!rootdir.exists()) {
return NULL; return NULL;
} }
QString filepath = rootdir.absoluteFilePath(filename); QString filepath = rootdir.absoluteFilePath(filename); //get the absolute path to the requested file
QFile* f = new QFile(filepath); QFile* f = new QFile(filepath); //create a QFile instance to the requested file
if(!f->exists()) { if(!f->exists()) { //File does not exist
return NULL; return NULL; //mark error
} }
if(!f->open(QFile::ReadWrite)) { if(!f->open(QFile::ReadWrite)) { //try to open the file, it it fails then ...
return NULL; return NULL; //... mark error
} }
QT_FILE_HANDLE* fh = new QT_FILE_HANDLE(); //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
fh->file = f; fh->file = f;
fh->fname = filename; fh->fname = filename;
fh->fpos =0; fh->fpos =0;
@@ -102,12 +106,13 @@ 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) { if(handle!=NULL) { //passed handle is valid
QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
if(fh->file->isOpen()) { if(fh->file->isOpen()) { //if the file is still open
fh->file->close(); fh->file->close(); //close the file
} }
delete fh; delete fh->file; //delete QFile instance
delete fh; //delete the fle
} }
} }
@@ -115,18 +120,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); QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
if(!fh->file->isOpen()) { if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR; return F_DISKERROR;
} }
if(offset>=fh->file->size()) { if(offset>=fh->file->size()) { //offset exeeds filesize
return F_INVALIDPARAM; return F_INVALIDPARAM;
} }
if(fh->file->seek(offset)) { if(fh->file->seek(offset)) { //try to seek to desired offset
fh->fpos = offset; fh->fpos = offset; //update offset in FILE_HANDLE (for user)
return F_OK; return F_OK;
} else { } else { //seek failed
return F_DISKERROR; return F_DISKERROR;
} }
} }
@@ -135,20 +140,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); QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
if(!fh->file->isOpen()) { if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR; return F_DISKERROR;
} }
if(!fh->file->isReadable()) { if(!fh->file->isReadable()) { //file is not readable
return F_EACCESS; return F_EACCESS;
} }
qint64 bytesRead = fh->file->read((char*)buf,size); qint64 bytesRead = fh->file->read((char*)buf,size); //try to read desired amount of bytes
if(bytesRead<0) { if(bytesRead<0) { //read failed
return F_DISKERROR; return F_DISKERROR;
} }
fh->fpos+=bytesRead; fh->fpos+=bytesRead; //increase file position (for user)
if(bytesRead!=size) { if(bytesRead!=size) { //we got less bytes than expected
return F_EOF; return F_EOF; //we reached the end of the file
} else { } else {
return F_OK; return F_OK;
} }
@@ -158,24 +163,22 @@ 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); QT_FILE_HANDLE* fh = static_cast<QT_FILE_HANDLE*>(handle); //cast pointer to QT_FILE_HANDLE
if(!fh->file->isOpen()) { if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR; return F_DISKERROR;
} }
if(!fh->file->isWritable()) { if(!fh->file->isWritable()) { //file is not writable
return F_EACCESS; return F_EACCESS;
} }
qint64 bytesWritten = fh->file->write((char*)buf,size); qint64 bytesWritten = fh->file->write((char*)buf,size); //try to write desired amount of bytes
if(bytesWritten<0) { if(bytesWritten<0) { //write failed
return F_DISKERROR; return F_DISKERROR;
} }
fh->fpos+=bytesWritten; fh->fpos+=bytesWritten; //increase file position (for user)
if(bytesWritten!=size) { if(bytesWritten!=size) { //we wrote less bytes than expected
return F_EOF; return F_EOF; //we reached the end of the file
} 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; return true; //nothing to initialize here, apart from the stuff which is done in the main method.
} }
void ll_system_delay(uint32_t msec) { void ll_system_delay(uint32_t msec) {
QThread::msleep(msec); QThread::msleep(msec); //Let the app_process() Thread sleep
} }
void ll_system_process() { void ll_system_process() {
QApplication::processEvents(); QApplication::processEvents(); //Process pending qt events
QThread::msleep(1); QThread::msleep(1); //Sleep for 1ms, to keep the cpu load down
} }
void ll_system_toggle_led() { void ll_system_toggle_led() {
//No led emulated :(
} }

View File

@@ -1,5 +1,4 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QDebug>
extern "C" { extern "C" {
#include "ll_tft.h" #include "ll_tft.h"
@@ -8,13 +7,14 @@ extern "C" {
MainWindow* mainwindow; MainWindow* mainwindow;
bool ll_tft_init() { bool ll_tft_init() {
qDebug() << "tft init done"; mainwindow = new MainWindow(); //create the designed window
mainwindow = new MainWindow(); mainwindow->show(); //open it (non blocking)
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,15 +44,17 @@ 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; return 2; //we have two fonts (see below)
} }
//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("Courier New",8); return QFont("Monospace",8);
case 1: case 1:
return QFont("Courier New",14); return QFont("DejaVu Sans Mono",14);
default: default:
return QFont(); return QFont();
} }
@@ -62,20 +64,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); QFontMetrics m(f); //use font metcris object to calculate height of font
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); QFontMetrics m(f); //use font metcris object to calculate width of font
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(f == QFont()) return; //if the font is the default-font, we want to abort.
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" {
//C Functions from the common folder //Imported 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()) { while(!QApplication::closingDown()) { //as long as the application is not terminating
app_process(); app_process(); //let the application process it's events
} }
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QApplication app(argc,argv); QApplication app(argc,argv); //Process qt-specific commandline arguments and create event loop
app_init(); app_init(); //Let the application initialize it self
QtConcurrent::run(&app_loop); QtConcurrent::run(&app_loop); //Start a thread that executes app_loop
return app.exec(); return app.exec(); //Run the event loop until the last window is closed.
} }

View File

@@ -13,16 +13,18 @@ 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);
@@ -32,156 +34,137 @@ 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); image.fill(Qt::black); //clear display buffer
currentScale = 1; currentScale = 1; //start with scale factor 1
ui->widgetDisplay->setMouseTracking(true); ui->widgetDisplay->setMouseTracking(true); //enable mouse move events, even when mouse is not pressed
ui->widgetDisplay->installEventFilter(this); ui->widgetDisplay->installEventFilter(this); //install event filter for "display" widget, so that we receive those events as well
} }
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)+1,abs((int)y2-(int)y1)+1); painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1),abs((int)y2-(int)y1));
//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); QImage img(width,height,QImage::Format_RGB32); //create a new image
for(int yi=0; yi<height; yi++) { for(int yi=0; yi<height; yi++) { //for each line
uint32_t* line = (uint32_t*)img.scanLine(yi); 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(int xi=0; xi<width; xi++) { //for each column
*line++=QRgbFromRGB565(dat[yi*width+xi]); *line++=QRgbFromRGB565(dat[yi*width+xi]); //set pixel
} }
} }
//render_mutex.lock();
QPainter p(&image); QPainter p(&image);
p.drawImage(x,y,img); p.drawImage(x,y,img); //draw created image
//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) { if(bgcolor!=TRANSPARENT) { //background color is not transparent
painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackgroundMode(Qt::OpaqueMode);
painter.setBackground(QColorFromRGB565(bgcolor)); painter.setBackground(QColorFromRGB565(bgcolor)); //set text background
} }
painter.setPen(QColorFromRGB565(color)); painter.setPen(QColorFromRGB565(color)); //set fontcolor
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))); painter.drawText(QPoint(x,y), QString(QChar(c))); //draw char
//render_mutex.unlock();
update(); update();
} }
void MainWindow::paintEvent(QPaintEvent *) void MainWindow::paintEvent(QPaintEvent *)
{ {
//render_mutex.lock(); //this method is called whenever the window needs to be redrawn (or after update() is called)
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); painter.drawImage(imgRect,image); //draw buffer
painter.setPen(QPen(Qt::green,2)); painter.setPen(QPen(Qt::green,2)); //set border color
painter.drawRect(imgRect.adjusted(-1,-1,1,1)); painter.drawRect(imgRect.adjusted(-1,-1,1,1)); //draw border
//render_mutex.unlock();
} }
void MainWindow::mousePressEvent(QMouseEvent *evt) void MainWindow::mousePressEvent(QMouseEvent *evt)
{ {
//qDebug() << "down" << evt->pos(); //the mouse was pressed
checkAndSendEvent(evt->pos(),true); checkAndSendEvent(evt->pos(),true);
} }
void MainWindow::mouseReleaseEvent(QMouseEvent *evt) void MainWindow::mouseReleaseEvent(QMouseEvent *evt)
{ {
//qDebug() << "up" << evt->pos(); //the mouse was released
checkAndSendEvent(evt->pos(),false); checkAndSendEvent(evt->pos(),false);
} }
void MainWindow::mouseMoveEvent(QMouseEvent *evt) void MainWindow::mouseMoveEvent(QMouseEvent *evt)
{ {
//qDebug() << "move" << evt->pos(); //the mouse was released
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) { if(obj==ui->widgetDisplay) { //we received a redirect event from the target rectangle
switch(evt->type()) { switch(evt->type()) {
case QEvent::MouseMove: case QEvent::MouseMove: //it's a mouse move event
{ {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt); QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt); //get mouse event
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; //calculate correct corrdinates (undo scale)
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) { if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) { //mouse position not out of bounds
//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;
} }
@@ -193,18 +176,16 @@ MainWindow::~MainWindow()
void MainWindow::checkAndSendEvent(QPoint pos, bool down) void MainWindow::checkAndSendEvent(QPoint pos, bool down)
{ {
QPoint p = pos - ui->widgetDisplay->geometry().topLeft(); QPoint p = pos - ui->widgetDisplay->geometry().topLeft(); //make coordinate relative to target area (0,0)
p/=currentScale; p/=currentScale; //undo scaling
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return; if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return; //abort if out of bounds
//qDebug() << down << p; touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP); //submit touch event to touch module (common)
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; 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(); update(); //force redraw
} }

View File

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

View File

@@ -1,26 +0,0 @@
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

Binary file not shown.