diff --git a/README.md b/README.md
index e12b80e..24d2b6d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,12 @@
# discoverpixy
-Project with the Pixy cam and the STM32F4 Discovery
+A Project with the Pixy cam and the STM32F4 Discovery. The project can also be run on linux/windows using a qt-based emulator.
+
+
+
+
+
+## Documentation
+Take a look at our [docu.pdf](./doc/docu.pdf) (German)
## Folder structure
* *common*: device independent code and the "Application" itself
diff --git a/common/app/pixy_control.c b/common/app/pixy_control.c
new file mode 100644
index 0000000..c30418d
--- /dev/null
+++ b/common/app/pixy_control.c
@@ -0,0 +1,69 @@
+/*
+ * pixy_control.c
+ *
+ * Notation
+ * --------
+ *
+ * x : Sollwert (Führgrösse)
+ * w : Istwert (Reglergrösse)
+ * esum : Integralteil
+ * e : Regelabweichung
+ * y : Stellgrösse
+ *
+ *
+ */
+#include
+#include
+
+// PID tuning factors
+#define REG_PID_KP (0.5f)
+#define REG_PID_KI (0.001f)
+#define REG_PID_KD (0.001f)
+#define REG_PID_TA (0.01f)
+
+
+// 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 * 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;
+}
diff --git a/common/app/pixy_control.h b/common/app/pixy_control.h
new file mode 100644
index 0000000..708cac4
--- /dev/null
+++ b/common/app/pixy_control.h
@@ -0,0 +1,41 @@
+#ifndef PIXY_CONTROL_H_
+#define PIXY_CONTROL_H_
+
+#include
+
+/**
+ * @addtogroup app
+ */
+/*@{*/
+
+/**
+ * @defgroup pixy_control Pixy Control Helper
+ * A collection of helper functions that contain PID Control code used for object tracking.
+ */
+/*@}*/
+
+
+/**
+ * @addtogroup pixy_control
+ */
+/*@{*/
+
+/**
+ * Execute one step of PID regulation for the Y-servo.
+ * @param x desired value (e.g. current y-position of the biggest block)
+ * @param w actual value (e.g desired y-position)
+ * @return The offset which needs to be added to the Y-Servo position
+ */
+int16_t pixy_PID_Y(int16_t x, int16_t w);
+
+/**
+ * Execute one step of PID regulation for the X-servo.
+ * @param x desired value (e.g. current x-position of the biggest block)
+ * @param w actual value (e.g desired x-position)
+ * @return The offset which needs to be added to the X-Servo position
+ */
+int16_t pixy_PID_X(int16_t x, int16_t w);
+
+/*@}*/
+
+#endif /* PIXY_CONTROL_H_ */
diff --git a/common/app/pixy_helper.c b/common/app/pixy_frame.c
similarity index 99%
rename from common/app/pixy_helper.c
rename to common/app/pixy_frame.c
index d137d71..8c7dc0d 100644
--- a/common/app/pixy_helper.c
+++ b/common/app/pixy_frame.c
@@ -1,4 +1,4 @@
-#include "pixy_helper.h"
+#include "pixy_frame.h"
#include "pixy.h"
#include "tft.h"
#include
diff --git a/common/app/pixy_helper.h b/common/app/pixy_frame.h
similarity index 87%
rename from common/app/pixy_helper.h
rename to common/app/pixy_frame.h
index 7f7cd40..5f70b42 100644
--- a/common/app/pixy_helper.h
+++ b/common/app/pixy_frame.h
@@ -1,10 +1,30 @@
-#ifndef PIXY_HELPER_H
-#define PIXY_HELPER_H
+#ifndef PIXY_FRAME_H
+#define PIXY_FRAME_H
#include
#include
#include "filesystem.h"
+
+/**
+ * @addtogroup app
+ */
+/*@{*/
+
+/**
+ * @defgroup pixy_helper Pixy Frame Helper
+ * A collection of helper functions that allow receiving and rendering a frame from pixy onto the display.
+ * Furthermore you can select a color in a frame, to use for tracking.
+ */
+/*@}*/
+
+
+/**
+ * @addtogroup pixy_helper
+ */
+/*@{*/
+
+
/**
* Receives a fullsized frame from pixy and display's it on the display with the topleft corner at (x,y)
* @param x The x-Coordinate of the top left corner
@@ -56,4 +76,6 @@ int pixy_save_cropped_frame(FILE_HANDLE* handle, uint16_t xoffset, uint16_t yoff
*/
int pixy_cc_set_region(uint8_t signum, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height);
-#endif /* PIXY_HELPER_H */
+/*@}*/
+
+#endif /* PIXY_FRAME_H */
diff --git a/common/app/screen_photomode.c b/common/app/screen_photomode.c
index eb41ed5..01232f4 100644
--- a/common/app/screen_photomode.c
+++ b/common/app/screen_photomode.c
@@ -5,7 +5,7 @@
#include "touch.h"
#include "pixy.h"
#include "system.h"
-#include "pixy_helper.h"
+#include "pixy_frame.h"
static bool pixy_connected = false; //Whether or not the pixy cam is currently connected
diff --git a/common/app/screen_photomode_save.c b/common/app/screen_photomode_save.c
index d05c4c8..e00f8dd 100644
--- a/common/app/screen_photomode_save.c
+++ b/common/app/screen_photomode_save.c
@@ -4,7 +4,7 @@
#include "tft.h"
#include "touch.h"
#include "pixy.h"
-#include "pixy_helper.h"
+#include "pixy_frame.h"
#include
#include
diff --git a/common/app/screen_pixytest.c b/common/app/screen_pixytest.c
index 05b5402..8b7b4cd 100644
--- a/common/app/screen_pixytest.c
+++ b/common/app/screen_pixytest.c
@@ -5,7 +5,7 @@
#include "touch.h"
#include "pixy.h"
#include "system.h"
-#include "pixy_helper.h"
+#include "pixy_frame.h"
static volatile enum {detecting, idle,update_servos, update_ledcolor, update_ledcurrent} state; //Current state of the screen state machine
diff --git a/common/app/screen_tracking.c b/common/app/screen_tracking.c
index a1066d2..cf6af59 100644
--- a/common/app/screen_tracking.c
+++ b/common/app/screen_tracking.c
@@ -1,11 +1,12 @@
#include "screen_tracking.h"
+#include "pixy_control.h"
#include "button.h"
#include "checkbox.h"
#include "tft.h"
#include "touch.h"
#include "pixy.h"
#include "system.h"
-#include "pixy_helper.h"
+#include "pixy_frame.h"
static BUTTON_STRUCT b_back; //Button to navigate back
static BUTTON_STRUCT b_select; //Button to start the color region selection
@@ -80,12 +81,19 @@ 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);
}
@@ -99,8 +107,31 @@ 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) {
- //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
diff --git a/common/gui/screen.c b/common/gui/screen.c
index 1365a5e..8eb3072 100644
--- a/common/gui/screen.c
+++ b/common/gui/screen.c
@@ -6,6 +6,10 @@
* 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
diff --git a/common/gui/screen.h b/common/gui/screen.h
index fdef182..8ef82a2 100644
--- a/common/gui/screen.h
+++ b/common/gui/screen.h
@@ -12,7 +12,7 @@
/**
* @defgroup screen Screen
* 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.
*/
/*@}*/
@@ -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)
* 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
*/
diff --git a/common/touch/touch.c b/common/touch/touch.c
index 93eac9f..fbd9d5f 100644
--- a/common/touch/touch.c
+++ b/common/touch/touch.c
@@ -12,7 +12,6 @@
/* 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
diff --git a/discovery/src/ll_tft.c b/discovery/src/ll_tft.c
index ba290e5..0b25998 100644
--- a/discovery/src/ll_tft.c
+++ b/discovery/src/ll_tft.c
@@ -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,6 +316,7 @@ 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 |
@@ -325,6 +326,7 @@ 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);
@@ -334,6 +336,8 @@ 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;
@@ -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)
{
// set cursor
@@ -354,61 +359,69 @@ 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){
- GPIOB->BSRRH = GPIO_Pin_0;
- } else {
- GPIOB->BSRRL = GPIO_Pin_0;
+ 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
}
}
+// Port operations on the screen RS PIN
static void tft_reset(bool state)
{
- if(state){
- GPIOB->BSRRH = GPIO_Pin_0;
- } else {
- GPIOB->BSRRL = GPIO_Pin_0;
+ 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
}
}
+// 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;
- TFT_RAM = reg_value;
+ TFT_REG = reg_adr; // set adress
+ TFT_RAM = reg_value; // send command
}
+// Read a register value of the display controller
static uint16_t tft_read_reg(uint8_t reg_adr)
{
- TFT_REG = reg_adr;
- return TFT_RAM;
+ TFT_REG = reg_adr; // set adress
+ 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)
{
uint16_t start,end;
uint16_t ystart_end;
- start = (ystart & 0x00FF);
- end = ((yend & 0x00FF) << 8);
- ystart_end = (start | 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
- 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);
+ 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
}
+// Reset a Window
void tft_reset_window()
{
- tft_write_reg(0x44,239<<8);
- tft_write_reg(0x45,0);
- tft_write_reg(0x46,319);
+ // Commands according to the datasheet
+ 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
@@ -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)
{
- tft_set_cursor(x,y);
- TFT_RAM = color;
+ tft_set_cursor(x,y); // Set the cursor position
+ 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)
{
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)
{
uint16_t area;
diff --git a/doc/PID_REGELUNG.tgz b/doc/PID_REGELUNG.tgz
deleted file mode 100644
index c1be5df..0000000
Binary files a/doc/PID_REGELUNG.tgz and /dev/null differ
diff --git a/doc/PI_PD_REGELUNG.tgz b/doc/PI_PD_REGELUNG.tgz
deleted file mode 100644
index 5f86a3d..0000000
Binary files a/doc/PI_PD_REGELUNG.tgz and /dev/null differ
diff --git a/doc/Pinmap b/doc/Pinmap.txt
similarity index 100%
rename from doc/Pinmap
rename to doc/Pinmap.txt
diff --git a/doc/analyse_touch.jpg b/doc/analyse_touch.jpg
new file mode 100644
index 0000000..7c329f7
Binary files /dev/null and b/doc/analyse_touch.jpg differ
diff --git a/doc/datasheet_ssd1289.pdf b/doc/datasheet_ssd1289.pdf
new file mode 100644
index 0000000..10ba9a3
Binary files /dev/null and b/doc/datasheet_ssd1289.pdf differ
diff --git a/doc/docu.odt b/doc/docu.odt
index f0c5685..e400a42 100644
Binary files a/doc/docu.odt and b/doc/docu.odt differ
diff --git a/doc/docu.pdf b/doc/docu.pdf
index 4894e60..4e45d7d 100644
Binary files a/doc/docu.pdf and b/doc/docu.pdf differ
diff --git a/doc/idpa_software.tar.gz b/doc/idpa_software.tar.gz
new file mode 100644
index 0000000..ba6a915
Binary files /dev/null and b/doc/idpa_software.tar.gz differ
diff --git a/doc/mainscreen_emulator.png b/doc/mainscreen_emulator.png
new file mode 100644
index 0000000..8bbbdfc
Binary files /dev/null and b/doc/mainscreen_emulator.png differ
diff --git a/doc/pixy.png b/doc/pixy.png
new file mode 100644
index 0000000..f39b294
Binary files /dev/null and b/doc/pixy.png differ
diff --git a/doc/screenshot_emulator.png b/doc/screenshot_emulator.png
new file mode 100644
index 0000000..8fcf5ce
Binary files /dev/null and b/doc/screenshot_emulator.png differ
diff --git a/doc/touch_controller_responds_notouch.jpg b/doc/touch_controller_responds_notouch.jpg
new file mode 100644
index 0000000..441171c
Binary files /dev/null and b/doc/touch_controller_responds_notouch.jpg differ
diff --git a/doc/touch_controller_responds_touch.jpg b/doc/touch_controller_responds_touch.jpg
new file mode 100644
index 0000000..04f2b86
Binary files /dev/null and b/doc/touch_controller_responds_touch.jpg differ
diff --git a/doc/tracking_emulator.png b/doc/tracking_emulator.png
new file mode 100644
index 0000000..3b5a484
Binary files /dev/null and b/doc/tracking_emulator.png differ
diff --git a/emulator/qt/ll_filesystem.cpp b/emulator/qt/ll_filesystem.cpp
index a89e08d..8d1d47f 100644
--- a/emulator/qt/ll_filesystem.cpp
+++ b/emulator/qt/ll_filesystem.cpp
@@ -7,51 +7,53 @@ extern "C" {
#include
#include
-QDir rootdir ("./emulated");
+QDir rootdir ("./emulated"); //Create a QDir which points to the "root" of the emulated filesystem
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";
- return false;
+ return false; //mark an error
}
return true;
}
DIRECTORY_STRUCT* ll_filesystem_dir_open(const char* path) {
- QDir d(rootdir);
- d.cd(path);
+ QDir d(rootdir); //Make a copy of the rootdir QDir instance
+ d.cd(path); //Change the directory to the passed path
if(!d.exists()) {
- return NULL;
+ return NULL; //mark an error
}
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];
+ directory->files = new FILE_STRUCT[directory->num_files]; //allocate array of file structs
-
- for(int i=0; ifiles[i]);
+ FILE_STRUCT* entry = &(directory->files[i]); //get the pointer to the current filestruct (which should be filled)
entry->fattrib = 0;
- entry->fname = new char[fi.fileName().length()+1];
- strcpy(entry->fname,fi.fileName().toStdString().c_str());
- if(fi.isDir()) {
- entry->fattrib|=F_DIR;
+ 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->fsize = 0;
- } else {
- entry->fsize = fi.size();
+ } else { //it's a file
+ entry->fsize = fi.size(); //set filesize
}
- if(fi.isHidden()) {
+ if(fi.isHidden()) { //the file is hidden
entry->fattrib|=F_HID;
}
- if(!fi.isWritable()) {
- entry->fattrib|=F_RDO;
+ if(!fi.isWritable()) { //the file is not writable
+ entry->fattrib|=F_RDO; //set readonly attribue
}
+ //Set date & time of file in structure
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.day = dt.date().day();
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) {
- if(dir!=NULL) {
- for(int i=0; inum_files; i++) {
- delete dir->files[i].fname;
+ if(dir!=NULL) { //passed handle is valid
+ for(int i=0; inum_files; i++) { //foreach file
+ delete dir->files[i].fname; //delete filename buffer
}
- delete[] dir->files;
- delete dir;
+ delete[] dir->files; //delete file array
+ delete dir; //delete structure itself
}
}
-
-struct QT_FILE_HANDLE : FILE_HANDLE {
- QFile* file;
+//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
};
@@ -83,17 +85,19 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
if(!rootdir.exists()) {
return NULL;
}
- QString filepath = rootdir.absoluteFilePath(filename);
- QFile* f = new QFile(filepath);
- if(!f->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
}
- if(!f->open(QFile::ReadWrite)) {
- return NULL;
+ if(!f->open(QFile::ReadWrite)) { //try to open the file, it it fails then ...
+ 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->fname = filename;
fh->fpos =0;
@@ -102,12 +106,13 @@ FILE_HANDLE* ll_filesystem_file_open(const char* filename) {
}
void ll_filesystem_file_close(FILE_HANDLE* handle) {
- if(handle!=NULL) {
- QT_FILE_HANDLE* fh = static_cast(handle);
- if(fh->file->isOpen()) {
- fh->file->close();
+ if(handle!=NULL) { //passed handle is valid
+ QT_FILE_HANDLE* fh = static_cast(handle); //cast pointer to QT_FILE_HANDLE
+ if(fh->file->isOpen()) { //if the file is still open
+ 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) {
return F_INVALIDPARAM;
}
- QT_FILE_HANDLE* fh = static_cast(handle);
- if(!fh->file->isOpen()) {
+ QT_FILE_HANDLE* fh = static_cast(handle); //cast pointer to QT_FILE_HANDLE
+ if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR;
}
- if(offset>=fh->file->size()) {
+ if(offset>=fh->file->size()) { //offset exeeds filesize
return F_INVALIDPARAM;
}
- if(fh->file->seek(offset)) {
- fh->fpos = offset;
+ if(fh->file->seek(offset)) { //try to seek to desired offset
+ fh->fpos = offset; //update offset in FILE_HANDLE (for user)
return F_OK;
- } else {
+ } else { //seek failed
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) {
return F_INVALIDPARAM;
}
- QT_FILE_HANDLE* fh = static_cast(handle);
- if(!fh->file->isOpen()) {
+ QT_FILE_HANDLE* fh = static_cast(handle); //cast pointer to QT_FILE_HANDLE
+ if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR;
}
- if(!fh->file->isReadable()) {
+ if(!fh->file->isReadable()) { //file is not readable
return F_EACCESS;
}
- qint64 bytesRead = fh->file->read((char*)buf,size);
- if(bytesRead<0) {
+ qint64 bytesRead = fh->file->read((char*)buf,size); //try to read desired amount of bytes
+ if(bytesRead<0) { //read failed
return F_DISKERROR;
}
- fh->fpos+=bytesRead;
- if(bytesRead!=size) {
- return F_EOF;
+ 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
} else {
return F_OK;
}
@@ -158,24 +163,22 @@ 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(handle);
- if(!fh->file->isOpen()) {
+ QT_FILE_HANDLE* fh = static_cast(handle); //cast pointer to QT_FILE_HANDLE
+ if(!fh->file->isOpen()) { //file is not open
return F_DISKERROR;
}
- if(!fh->file->isWritable()) {
+ if(!fh->file->isWritable()) { //file is not writable
return F_EACCESS;
}
- qint64 bytesWritten = fh->file->write((char*)buf,size);
- if(bytesWritten<0) {
+ qint64 bytesWritten = fh->file->write((char*)buf,size); //try to write desired amount of bytes
+ if(bytesWritten<0) { //write failed
return F_DISKERROR;
}
- fh->fpos+=bytesWritten;
- if(bytesWritten!=size) {
- return F_EOF;
+ 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
} else {
return F_OK;
}
}
-
-
diff --git a/emulator/qt/ll_system.cpp b/emulator/qt/ll_system.cpp
index 8d087b5..68efd72 100644
--- a/emulator/qt/ll_system.cpp
+++ b/emulator/qt/ll_system.cpp
@@ -6,18 +6,18 @@ extern "C" {
}
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) {
- QThread::msleep(msec);
+ QThread::msleep(msec); //Let the app_process() Thread sleep
}
void ll_system_process() {
- QApplication::processEvents();
- QThread::msleep(1);
+ QApplication::processEvents(); //Process pending qt events
+ QThread::msleep(1); //Sleep for 1ms, to keep the cpu load down
}
void ll_system_toggle_led() {
-
+ //No led emulated :(
}
diff --git a/emulator/qt/ll_tft.cpp b/emulator/qt/ll_tft.cpp
index 9c63578..5963104 100644
--- a/emulator/qt/ll_tft.cpp
+++ b/emulator/qt/ll_tft.cpp
@@ -1,5 +1,4 @@
#include "mainwindow.h"
-#include
extern "C" {
#include "ll_tft.h"
@@ -8,13 +7,14 @@ extern "C" {
MainWindow* mainwindow;
bool ll_tft_init() {
- qDebug() << "tft init done";
- mainwindow = new MainWindow();
- mainwindow->show();
+ mainwindow = new MainWindow(); //create the designed window
+ mainwindow->show(); //open it (non blocking)
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,9 +44,11 @@ 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;
+ 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) {
switch(fontnum) {
case 0:
@@ -62,20 +64,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);
+ QFontMetrics m(f); //use font metcris object to calculate height of font
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);
+ QFontMetrics m(f); //use font metcris object to calculate width of font
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(f == QFont()) return; //if the font is the default-font, we want to abort.
mainwindow->draw_char(x,y,color,bgcolor,f,c);
}
diff --git a/emulator/qt/main.cpp b/emulator/qt/main.cpp
index dc67c83..96937c1 100644
--- a/emulator/qt/main.cpp
+++ b/emulator/qt/main.cpp
@@ -2,23 +2,23 @@
#include
extern "C" {
- //C Functions from the common folder
+ //Imported 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()) {
- app_process();
+ while(!QApplication::closingDown()) { //as long as the application is not terminating
+ app_process(); //let the application process it's events
}
}
int main(int argc, char* argv[]) {
- QApplication app(argc,argv);
- app_init();
+ QApplication app(argc,argv); //Process qt-specific commandline arguments and create event loop
+ app_init(); //Let the application initialize it self
- QtConcurrent::run(&app_loop);
- return app.exec();
+ QtConcurrent::run(&app_loop); //Start a thread that executes app_loop
+ return app.exec(); //Run the event loop until the last window is closed.
}
diff --git a/emulator/qt/mainwindow.cpp b/emulator/qt/mainwindow.cpp
index 0ed5eea..99b2ae2 100644
--- a/emulator/qt/mainwindow.cpp
+++ b/emulator/qt/mainwindow.cpp
@@ -13,16 +13,18 @@ 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);
@@ -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){
ui->setupUi(this);
- image.fill(Qt::black);
- currentScale = 1;
- ui->widgetDisplay->setMouseTracking(true);
- ui->widgetDisplay->installEventFilter(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
}
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)+1,abs((int)y2-(int)y1)+1);
- //render_mutex.unlock();
+ painter.drawRect(qMin(x1,x2),qMin(y1,y2),abs((int)x2-(int)x1),abs((int)y2-(int)y1));
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);
+ QImage img(width,height,QImage::Format_RGB32); //create a new image
- for(int yi=0; yiwidgetDisplay->geometry().topLeft(),QSizeF(DISPLAY_WIDTH*currentScale,DISPLAY_HEIGHT*currentScale));
- painter.drawImage(imgRect,image);
- painter.setPen(QPen(Qt::green,2));
- painter.drawRect(imgRect.adjusted(-1,-1,1,1));
-
-
- //render_mutex.unlock();
+ 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
}
void MainWindow::mousePressEvent(QMouseEvent *evt)
{
- //qDebug() << "down" << evt->pos();
+ //the mouse was pressed
checkAndSendEvent(evt->pos(),true);
}
void MainWindow::mouseReleaseEvent(QMouseEvent *evt)
{
- //qDebug() << "up" << evt->pos();
+ //the mouse was released
checkAndSendEvent(evt->pos(),false);
}
void MainWindow::mouseMoveEvent(QMouseEvent *evt)
{
- //qDebug() << "move" << evt->pos();
+ //the mouse was released
checkAndSendEvent(evt->pos(),true);
}
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()) {
- case QEvent::MouseMove:
+ case QEvent::MouseMove: //it's a mouse move event
{
- QMouseEvent* mouseEvent = static_cast(evt);
- QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale;
- if(p.x()(evt); //get mouse event
+ QPoint p = (mouseEvent->pos()-QPoint(1,1))/currentScale; //calculate correct corrdinates (undo scale)
+ if(p.x()txtMousePos->setText(QString("Mouse Position: (%1,%2)").arg(p.x()).arg(p.y()));
}
}
break;
-
default: break;
}
}
-
return false;
}
@@ -193,18 +176,16 @@ MainWindow::~MainWindow()
void MainWindow::checkAndSendEvent(QPoint pos, bool down)
{
- 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;
+ 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
- //qDebug() << down << p;
-
- touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP);
+ touch_add_raw_event(p.x(),p.y(),down?TOUCH_DOWN:TOUCH_UP); //submit touch event to touch module (common)
}
void MainWindow::on_cboZoom_currentIndexChanged(int index)
{
- currentScale=index+1;
- update();
+ 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
}
diff --git a/emulator/qt/mainwindow.h b/emulator/qt/mainwindow.h
index e9034e1..7c0f845 100644
--- a/emulator/qt/mainwindow.h
+++ b/emulator/qt/mainwindow.h
@@ -33,12 +33,11 @@ protected:
~MainWindow();
private slots:
- void on_cboZoom_currentIndexChanged(int index);
+ void on_cboZoom_currentIndexChanged(int index); //slot that is called when the zoomlevel changed
private:
- //QMutex render_mutex;
- QImage image;
- int currentScale;
+ QImage image; //Display buffer
+ int currentScale; //current scale factor
void checkAndSendEvent(QPoint pos, bool down);
Ui::MainWindow *ui;
diff --git a/genheader.sh b/utils/genheader.sh
similarity index 93%
rename from genheader.sh
rename to utils/genheader.sh
index 7be2999..26ee24b 100755
--- a/genheader.sh
+++ b/utils/genheader.sh
@@ -7,7 +7,7 @@ echo "* Institution: BFH Bern University of Applied Sciences"
echo "* File: $1"
echo "*"
echo "* Version History:"
-echo "* Date Autor Email SHA Changes"
+echo "* Date Autor Email SHA Changes"
git log --pretty=format:"* %ad%x09%ae%x09%h%x09%s" --date=short --date-order --no-merges --reverse $1 | grep -v -i "fileheader"
diff --git a/utils/style.astylerc b/utils/style.astylerc
new file mode 100644
index 0000000..8fdbb87
--- /dev/null
+++ b/utils/style.astylerc
@@ -0,0 +1,16 @@
+
+# general style
+--style=1tbs
+--indent=spaces=4 # default
+--lineend=linux #only \r as line ending
+
+# alignment
+--align-pointer=type #put asterisks to the type. eg. char* a
+--align-reference=type #put references to the type. eg. int& a
+
+# padding
+--break-blocks # insert empty lines between header blocks
+--unpad-paren # remove extra padding around parens
+--pad-oper # spaces around operators
+--pad-header # insert space between header blocks and the following paren
+--add-brackets # add brackets to one line conditionals
diff --git a/updateheaders.sh b/utils/updateheaders.sh
similarity index 71%
rename from updateheaders.sh
rename to utils/updateheaders.sh
index 84068bb..55d8b74 100755
--- a/updateheaders.sh
+++ b/utils/updateheaders.sh
@@ -3,14 +3,15 @@
FILES=`find common/ emulator/ discovery/ -name "*.c" -or -name "*.h" -or -name "*.cpp" | grep -v libs | grep -v /pixy/`
+
for FILE in $FILES; do
echo "Adding Header to $FILE"
- #remove old header
- CONTENT=$(perl -0777 -pe 's%^/\*.*?discoverpixy.*?\*/%%igs' $FILE)
+ #remove old header, and format file with astyle
+ CONTENT=$(perl -0777 -pe 's%^/\*.*?discoverpixy.*?\*/%%igs' $FILE | astyle --options=./utils/style.astylerc)
#add new header
- ./genheader.sh $FILE > $FILE
+ ./utils/genheader.sh $FILE > $FILE
#append file content
echo "$CONTENT" >> $FILE