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 "pixy_control.h"
#include "button.h"
#include "checkbox.h"
#include "tft.h"
@@ -81,19 +80,12 @@ typedef struct {
} TRACKING_CONFIG_STRUCT;
//Methods for our tracking implementation ahead
static int16_t servo_x = 0;
static int16_t servo_y = 0;
//Method/Callback to start our tracking
void tracking_our_start(void* tracking_config) {
//Activate pixy's data send program
int32_t response;
int return_value;
servo_x = servo_y = 500; // set a default value of 500
pixy_rcs_set_position(0, servo_x); // set default
pixy_rcs_set_position(1, servo_y); // set default
return_value = pixy_command("runprog", INT8(0), END_OUT_ARGS, &response, END_IN_ARGS);
}
@@ -107,31 +99,8 @@ void tracking_our_stop(void* tracking_config) {
//Method/Callback to calculate one step of our tracking
void tracking_our_update(void* tracking_config, struct Block* blocks, int num_blocks) {
if(num_blocks <= 0){ // Check if there are blocks available
return; // When there are none, do nothing
}
uint16_t x = blocks[0].x; // Get x coordinate of the biggest object
uint16_t y = blocks[0].y; // Get y coordinate of the biggest object
int16_t xset = 0;
int16_t yset = 0;
xset = (servo_x + pixy_PID_X((FRAME_WIDTH / 2), x)); // calculate the PID output for x
yset = (servo_y - pixy_PID_Y((FRAME_HEIGHT / 2), y)); // calculate the PID output for y
xset = (xset < 0) ? 0 : xset; // x lower boundary check
xset = (xset > 1000) ? 1000 : xset; // x upper boundary check
yset = (yset < 0) ? 0 : yset; // y lower boundary check
yset = (yset > 1000) ? 1000 : yset; // y upper boundary check
servo_x = xset; // update the global, static variable for x
servo_y = yset; // update the global, statuc variable for y
pixy_rcs_set_position(0, servo_x); // set the new x position
pixy_rcs_set_position(1, servo_y); // set the new y position
//TODO: Implement tracking!
//Calculate new servo pos and set the new servo pos
}
//Variable which stores all the callbacks and settings for our tracking implementation

View File

@@ -6,10 +6,6 @@
* This makes it safe to change the screen from an touch interrupt (e.g. button callback)
*/
/* Possible Improvements:
* Ensure that you can not navigate to a screen which is already in the history (because it will corrupt the list)
*/
static SCREEN_STRUCT* screen_list = NULL; //Head of the linked list which stores the screen history.
static SCREEN_STRUCT* screen_current = NULL; //Pointer to the current screen (= tail of the list)
static volatile SCREEN_STRUCT* screen_goto = NULL; //Screen we should navigate to once we enter the gui_screen_update() method again

View File

@@ -44,7 +44,6 @@ typedef struct SCREEN_S{
/**
* Navigate to the given screen as soon as the app enters the main loop again (and gui_screen_update() is called)
* It's safe to call this method from an interrupt
* @note Do not pass a screen which is already in your history of screens!
* @param screen A Pointer to the preinitialized SCREEN_STRUCT
* @return true on success
*/

View File

@@ -12,6 +12,7 @@
/* Possible improvements:
* Exchange pointer-list "areas" with a linked list. This would ensure that we can always accept new regions
* Implement calibration stuff, and calculate the real coordinates out of the data provided in touch_add_raw_event()
*/
#define NUM_AREAS 50 //Number of Touch Areas we can manage

View File

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

BIN
doc/PID_REGELUNG.tgz Normal file

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/ui_*
qt/moc_*
qt/Makefile
qt/Makefile*
qt/debug
qt/release
libs/*/obj
libs/*/*.a

View File

@@ -10,7 +10,7 @@ QT_DIR=./qt
COMMON_DIR=../common
#Tools
CC=gcc -fdiagnostics-color=auto
CC=gcc #-fdiagnostics=auto
GDB=gdb
@@ -24,17 +24,22 @@ INCLUDES:=$(addprefix -I,$(INCLUDES))
QT_LIB=$(QT_DIR)/libemulatorqt.a
CPPFLAGS= -march=x86-64 -mtune=generic -fPIC $(INCLUDES)
CPPFLAGS= -march=x86-64 -mtune=generic #-fPIC
CPPFLAGS+= $(INCLUDES)
CFLAGS= -O0 -g -std=c99
LIBS= pixy usb-1.0 boost_system boost_timer boost_chrono
LIBS+=Qt5Core Qt5Gui Qt5Widgets emulatorqt m stdc++
LIBS= emulatorqt pixy usb-1.0
LIBS+= boost_system-mgw49-mt-1_58 boost_timer-mgw49-mt-1_58 boost_chrono-mgw49-mt-1_58
LIBS+= Qt5Core Qt5Gui Qt5Widgets m stdc++
LDFLAGS= -L$(QT_DIR) $(addprefix -l,$(LIBS))
LDFLAGS= -static-libgcc -static-libstdc++ #-Wl,-t -Wl,--Map=a.map
LDFLAGS+= -L$(QT_DIR)
LDFLAGS+= -L$(LIB_DIR)/Pixy
LDFLAGS+= -L$(LIB_DIR)/boost/lib
LDFLAGS+= -LC:/Qt/5.4/mingw491_32/lib
LDFLAGS+= -L$(LIB_DIR)/Pixy/windows
LDFLAGS+= $(addprefix -l,$(LIBS))
#Finding Input files
CFILES=$(shell find . -maxdepth 1 -name '*.c')
@@ -58,7 +63,7 @@ debug: all
$(GDB) ./build/emulator
$(QT_LIB):
cd $(QT_DIR) && qmake &&make
cd $(QT_DIR) && qmake && $(MAKE)
#objects to elf
$(BUILD_DIR)/$(TARGET): $(OBJS) $(COMMON_OBJS) $(QT_LIB)
@@ -83,7 +88,7 @@ $(OBJ_DIR)/%.o: $(COMMON_DIR)/%.c
#Clean Obj files and builded stuff
clean:
cd $(QT_DIR) && $(MAKE) clean && $(RM) Makefile && $(RM) *.a
cd $(QT_DIR) && $(MAKE) clean && $(RM) Makefile* && $(RM) *.a && $(RMDIR) debug release
$(RMDIR) $(BUILD_DIR) $(OBJ_DIR)

View File

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

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
TEMPLATE = lib
CONFIG += staticlib
CONFIG += staticlib debug
SOURCES += \
mainwindow.cpp \
@@ -30,3 +30,6 @@ INCLUDEPATH+= ../../common/lowlevel/ \
FORMS += \
mainwindow.ui
DESTDIR = $$_PRO_FILE_PWD_ #force windows to not create subfolders
#QMAKE_CXXFLAGS+= -v

View File

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

View File

@@ -6,18 +6,18 @@ extern "C" {
}
bool ll_system_init() {
return true; //nothing to initialize here, apart from the stuff which is done in the main method.
return true;
}
void ll_system_delay(uint32_t msec) {
QThread::msleep(msec); //Let the app_process() Thread sleep
QThread::msleep(msec);
}
void ll_system_process() {
QApplication::processEvents(); //Process pending qt events
QThread::msleep(1); //Sleep for 1ms, to keep the cpu load down
QApplication::processEvents();
QThread::msleep(1);
}
void ll_system_toggle_led() {
//No led emulated :(
}

View File

@@ -1,4 +1,5 @@
#include "mainwindow.h"
#include <QDebug>
extern "C" {
#include "ll_tft.h"
@@ -7,14 +8,13 @@ extern "C" {
MainWindow* mainwindow;
bool ll_tft_init() {
mainwindow = new MainWindow(); //create the designed window
mainwindow->show(); //open it (non blocking)
qDebug() << "tft init done";
mainwindow = new MainWindow();
mainwindow->show();
return true;
}
//the following functions redirect the call to the mainwindow, to a function with the same signature
void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
mainwindow->draw_line(x1,y1,x2,y2,color);
}
@@ -44,17 +44,15 @@ void ll_tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) {
}
uint8_t ll_tft_num_fonts() {
return 2; //we have two fonts (see below)
return 2;
}
//Helper function to get the QFont to the corresponding font number
//Note: only return monospaced fonts!!!
QFont get_font(uint8_t fontnum) {
switch(fontnum) {
case 0:
return QFont("Monospace",8);
return QFont("Courier New",8);
case 1:
return QFont("DejaVu Sans Mono",14);
return QFont("Courier New",14);
default:
return QFont();
}
@@ -64,20 +62,20 @@ QFont get_font(uint8_t fontnum) {
uint8_t ll_tft_font_height(uint8_t fontnum) {
QFont f = get_font(fontnum);
if(f == QFont()) return -1;
QFontMetrics m(f); //use font metcris object to calculate height of font
QFontMetrics m(f);
return m.height();
}
uint8_t ll_tft_font_width(uint8_t fontnum) {
QFont f = get_font(fontnum);
if(f == QFont()) return -1;
QFontMetrics m(f); //use font metcris object to calculate width of font
QFontMetrics m(f);
return m.averageCharWidth();
}
void ll_tft_draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, char c) {
QFont f = get_font(font);
if(f == QFont()) return; //if the font is the default-font, we want to abort.
if(f == QFont()) return;
mainwindow->draw_char(x,y,color,bgcolor,f,c);
}

View File

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

View File

@@ -13,18 +13,16 @@ extern "C" {
#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240
//function to calculate QColor out of a RGB565 16bit color
QColor QColorFromRGB565(uint16_t color) {
//interpolate colors
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5);
int G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5);
return QColor::fromRgb(R8,G8,B8);
}
//function to calculate QRgb out of a RGB565 16bit color
QRgb QRgbFromRGB565(uint16_t color) {
//interpolate colors
int R8 = (int) floor( (color>>(5+6)) * 255.0 / 31.0 + 0.5);
int G8 = (int) floor( ((color>>5)&0x3F) * 255.0 / 63.0 + 0.5);
int B8 = (int) floor( (color&0x1F) * 255.0 / 31.0 + 0.5);
@@ -34,137 +32,156 @@ QRgb QRgbFromRGB565(uint16_t color) {
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), image(DISPLAY_WIDTH,DISPLAY_HEIGHT, QImage::Format_RGB16), ui(new Ui::MainWindow){
ui->setupUi(this);
image.fill(Qt::black); //clear display buffer
currentScale = 1; //start with scale factor 1
ui->widgetDisplay->setMouseTracking(true); //enable mouse move events, even when mouse is not pressed
ui->widgetDisplay->installEventFilter(this); //install event filter for "display" widget, so that we receive those events as well
image.fill(Qt::black);
currentScale = 1;
ui->widgetDisplay->setMouseTracking(true);
ui->widgetDisplay->installEventFilter(this);
}
void MainWindow::draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
//render_mutex.lock();
QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color));
painter.drawLine(x1,y1,x2,y2);
//render_mutex.unlock();
update();
}
void MainWindow::draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{
//render_mutex.lock();
image.setPixel(x,y,QRgbFromRGB565(color));
//render_mutex.unlock();
update();
}
void MainWindow::clear(uint16_t color)
{
//render_mutex.lock();
image.fill(QColorFromRGB565(color));
//render_mutex.unlock();
update();
}
void MainWindow::draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
//render_mutex.lock();
QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color));
painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1),abs((int)y2-(int)y1));
painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1)+1,abs((int)y2-(int)y1)+1);
//render_mutex.unlock();
update();
}
void MainWindow::fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
//render_mutex.lock();
QPainter painter(&(image));
painter.fillRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1)+1,abs((int)y2-(int)y1)+1,QColorFromRGB565(color));
//render_mutex.unlock();
update();
}
void MainWindow::draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *dat)
{
//Creating a new image and access it directly is faster than setPixel
QImage img(width,height,QImage::Format_RGB32); //create a new image
QImage img(width,height,QImage::Format_RGB32);
for(int yi=0; yi<height; yi++) { //for each line
uint32_t* line = (uint32_t*)img.scanLine(yi); //get the pointer to the imagedata of the current line
for(int xi=0; xi<width; xi++) { //for each column
*line++=QRgbFromRGB565(dat[yi*width+xi]); //set pixel
for(int yi=0; yi<height; yi++) {
uint32_t* line = (uint32_t*)img.scanLine(yi);
for(int xi=0; xi<width; xi++) {
*line++=QRgbFromRGB565(dat[yi*width+xi]);
}
}
//render_mutex.lock();
QPainter p(&image);
p.drawImage(x,y,img); //draw created image
p.drawImage(x,y,img);
//render_mutex.unlock();
update();
}
void MainWindow::draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color)
{
//render_mutex.lock();
QPainter painter(&(image));
painter.setPen(QColorFromRGB565(color));
painter.drawEllipse(QPoint(x,y), r, r);
//render_mutex.unlock();
update();
}
void MainWindow::draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, QFont font, char c)
{
//render_mutex.lock();
QPainter painter(&(image));
painter.setFont(font);
if(bgcolor!=TRANSPARENT) { //background color is not transparent
if(bgcolor!=TRANSPARENT) {
painter.setBackgroundMode(Qt::OpaqueMode);
painter.setBackground(QColorFromRGB565(bgcolor)); //set text background
painter.setBackground(QColorFromRGB565(bgcolor));
}
painter.setPen(QColorFromRGB565(color)); //set fontcolor
painter.setPen(QColorFromRGB565(color));
y+=QFontMetrics(font).ascent(); //use y pos as highest point of char, instead of baseline
painter.drawText(QPoint(x,y), QString(QChar(c))); //draw char
painter.drawText(QPoint(x,y), QString(QChar(c)));
//render_mutex.unlock();
update();
}
void MainWindow::paintEvent(QPaintEvent *)
{
//this method is called whenever the window needs to be redrawn (or after update() is called)
//render_mutex.lock();
QPainter painter(this);
//Create a QRectF which represents the rectangle to draw the buffered image to
QRectF imgRect (ui->widgetDisplay->geometry().topLeft(),QSizeF(DISPLAY_WIDTH*currentScale,DISPLAY_HEIGHT*currentScale));
painter.drawImage(imgRect,image); //draw buffer
painter.setPen(QPen(Qt::green,2)); //set border color
painter.drawRect(imgRect.adjusted(-1,-1,1,1)); //draw border
painter.drawImage(imgRect,image);
painter.setPen(QPen(Qt::green,2));
painter.drawRect(imgRect.adjusted(-1,-1,1,1));
//render_mutex.unlock();
}
void MainWindow::mousePressEvent(QMouseEvent *evt)
{
//the mouse was pressed
//qDebug() << "down" << evt->pos();
checkAndSendEvent(evt->pos(),true);
}
void MainWindow::mouseReleaseEvent(QMouseEvent *evt)
{
//the mouse was released
//qDebug() << "up" << evt->pos();
checkAndSendEvent(evt->pos(),false);
}
void MainWindow::mouseMoveEvent(QMouseEvent *evt)
{
//the mouse was released
//qDebug() << "move" << evt->pos();
checkAndSendEvent(evt->pos(),true);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *evt)
{
if(obj==ui->widgetDisplay) { //we received a redirect event from the target rectangle
if(obj==ui->widgetDisplay) {
switch(evt->type()) {
case QEvent::MouseMove: //it's a mouse move event
case QEvent::MouseMove:
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt); //get mouse event
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; //calculate correct corrdinates (undo scale)
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) { //mouse position not out of bounds
//set mouse position text
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(evt);
QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale;
if(p.x()<DISPLAY_WIDTH && p.y()<DISPLAY_HEIGHT) {
ui->txtMousePos->setText(QString("Mouse Position: (%1,%2)").arg(p.x()).arg(p.y()));
}
}
break;
default: break;
}
}
return false;
}
@@ -176,16 +193,18 @@ MainWindow::~MainWindow()
void MainWindow::checkAndSendEvent(QPoint pos, bool down)
{
QPoint p = pos - ui->widgetDisplay->geometry().topLeft(); //make coordinate relative to target area (0,0)
p/=currentScale; //undo scaling
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return; //abort if out of bounds
QPoint p = pos - ui->widgetDisplay->geometry().topLeft();
p/=currentScale;
if(p.x()<0 || p.y()<0 || p.x() >= DISPLAY_WIDTH || p.y() >= DISPLAY_HEIGHT) return;
touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP); //submit touch event to touch module (common)
//qDebug() << down << p;
touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP);
}
void MainWindow::on_cboZoom_currentIndexChanged(int index)
{
currentScale=index+1; //zoom factor 1 is the 0th entry, zoom factor 2 is the 1st entry, zoom factor 3 is the 2nd entry
update(); //force redraw
currentScale=index+1;
update();
}

View File

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

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.