Updated fileheaders and styled files using astyle.
This commit is contained in:
@@ -1,3 +1,32 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/app.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com cab8609 Integrated pixy into emulator. Pixy is no longer in the common/libs folder but in emulator/libs and discovery/libs
|
||||
* 2015-04-03 timolang@gmail.com 1aa9194 Fixed Drawing of rects in Emulator. Got frames from pixy to emulator. Slooooow.
|
||||
* 2015-04-25 timolang@gmail.com 416883c Pixy&Usb work with the new folder structure now.
|
||||
* 2015-04-25 timolang@gmail.com 3d1e4b2 Simplified code a bit. Emulator does not work stable when replugging pixy.
|
||||
* 2015-04-25 timolang@gmail.com 0858b0d Fixed some bugs when receiving large data.
|
||||
* 2015-04-27 timolang@gmail.com 259d446 Added touch support to emulator. Implemented basic touch function.
|
||||
* 2015-04-27 aaron@duckpond.ch aed90ef Drawcircle added (emulator)
|
||||
* 2015-04-27 timolang@gmail.com e249fb2 Added font support
|
||||
* 2015-04-27 timolang@gmail.com 7c9eabc Added button support.
|
||||
* 2015-04-27 timolang@gmail.com b300ac5 Added Checkbox support
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-12 aaron@duckpond.ch aec62d4 Added datasheets, updated touchsupport.
|
||||
* 2015-05-28 aaron@duckpond.ch 5bda699 implemented functions to get x and y coordinates and a test function
|
||||
* 2015-05-29 aaron@duckpond.ch 7d2d1a1 Implemented basic sampling and averaging of touch coordinates using timer7
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "app.h"
|
||||
#include "tft.h"
|
||||
#include "system.h"
|
||||
@@ -5,20 +34,20 @@
|
||||
#include "screen_main.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
void app_init() {
|
||||
system_init();
|
||||
tft_init();
|
||||
touch_init();
|
||||
filesystem_init();
|
||||
void app_init()
|
||||
{
|
||||
system_init();
|
||||
tft_init();
|
||||
touch_init();
|
||||
filesystem_init();
|
||||
|
||||
gui_screen_navigate(get_screen_main());
|
||||
gui_screen_navigate(get_screen_main());
|
||||
}
|
||||
|
||||
//app event loop
|
||||
void app_process() {
|
||||
|
||||
system_process(); //Let the system handle it's pending events
|
||||
gui_screen_update(); //update the currently active screen
|
||||
void app_process()
|
||||
{
|
||||
|
||||
system_process(); //Let the system handle it's pending events
|
||||
gui_screen_update(); //update the currently active screen
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/app.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-06-08 timolang@gmail.com 73db8b5 Added doxygen mainpage comment in app.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
/*!
|
||||
/*!
|
||||
\mainpage discoverpixy Doxygen Documentation
|
||||
Welcome to the code-documentation for all common (and plattformindependent) code. \n
|
||||
A good point to start is probably the <a href="modules.html">Modules</a> page.
|
||||
A good point to start is probably the <a href="modules.html">Modules</a> page.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/pixy_control.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-02 aaron@duckpond.ch e018a75 Implemented basic pi and pid controller
|
||||
* 2015-06-06 aaron@duckpond.ch 8c264c2 Comment refactoring, updated PID values
|
||||
* 2015-06-06 aaron@duckpond.ch a04cda9 Refactured comments and implemented a bugfix for the PID controller
|
||||
* 2015-06-07 aaron@duckpond.ch 802d3df Fixed pid controller and refactored code
|
||||
* 2015-06-07 aaron@duckpond.ch 3d98ca9 Minor changes
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
/*
|
||||
* pixy_control.c
|
||||
*
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/pixy_control.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-02 aaron@duckpond.ch e018a75 Implemented basic pi and pid controller
|
||||
* 2015-06-06 aaron@duckpond.ch 8c264c2 Comment refactoring, updated PID values
|
||||
* 2015-06-06 aaron@duckpond.ch a04cda9 Refactured comments and implemented a bugfix for the PID controller
|
||||
* 2015-06-07 aaron@duckpond.ch 802d3df Fixed pid controller and refactored code
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef PIXY_CONTROL_H_
|
||||
#define PIXY_CONTROL_H_
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/pixy_frame.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "pixy_frame.h"
|
||||
#include "pixy.h"
|
||||
#include "tft.h"
|
||||
@@ -5,118 +18,113 @@
|
||||
|
||||
|
||||
|
||||
static int renderBA81(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
|
||||
static int saveBA81(FILE_HANDLE* handle, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
|
||||
static int renderBA81(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t* frame);
|
||||
static int saveBA81(FILE_HANDLE* handle, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t* frame);
|
||||
|
||||
|
||||
int pixy_render_full_frame(uint16_t x, uint16_t y) {
|
||||
return pixy_render_cropped_frame(x,y,0,0,320,200);
|
||||
}
|
||||
|
||||
|
||||
int pixy_render_cropped_frame(uint16_t x, uint16_t y, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height) {
|
||||
uint8_t* videodata;
|
||||
int32_t response;
|
||||
int32_t fourccc;
|
||||
int8_t renderflags;
|
||||
uint16_t xwidth;
|
||||
uint16_t ywidth;
|
||||
uint32_t size;
|
||||
|
||||
|
||||
int return_value = pixy_command("cam_getFrame", // String id for remote procedure
|
||||
INT8(0x21), // mode
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
&fourccc,
|
||||
&renderflags,
|
||||
&xwidth,
|
||||
&ywidth,
|
||||
&size,
|
||||
&videodata, // pointer to mem address for returned frame
|
||||
END_IN_ARGS);
|
||||
|
||||
if(return_value==0) {
|
||||
return_value = renderBA81(x,y,xwidth,ywidth,size,videodata);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
int pixy_save_full_frame(FILE_HANDLE* handle) {
|
||||
return pixy_save_cropped_frame(handle,0,0,320,200);
|
||||
}
|
||||
|
||||
int pixy_save_cropped_frame(FILE_HANDLE* handle, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height) {
|
||||
uint8_t* videodata;
|
||||
int32_t response;
|
||||
int32_t fourccc;
|
||||
int8_t renderflags;
|
||||
uint16_t xwidth;
|
||||
uint16_t ywidth;
|
||||
uint32_t size;
|
||||
|
||||
|
||||
int return_value = pixy_command("cam_getFrame", // String id for remote procedure
|
||||
INT8(0x21), // mode
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
&fourccc,
|
||||
&renderflags,
|
||||
&xwidth,
|
||||
&ywidth,
|
||||
&size,
|
||||
&videodata, // pointer to mem address for returned frame
|
||||
END_IN_ARGS);
|
||||
|
||||
if(return_value==0) {
|
||||
return_value = saveBA81(handle,xwidth,ywidth,size,videodata);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pixel, uint8_t* r, uint8_t* g, uint8_t* b)
|
||||
int pixy_render_full_frame(uint16_t x, uint16_t y)
|
||||
{
|
||||
if (y&1)
|
||||
{
|
||||
if (x&1)
|
||||
{
|
||||
*r = *pixel;
|
||||
*g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
|
||||
*b = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r = (*(pixel-1)+*(pixel+1))>>1;
|
||||
*g = *pixel;
|
||||
*b = (*(pixel-width)+*(pixel+width))>>1;
|
||||
}
|
||||
return pixy_render_cropped_frame(x, y, 0, 0, 320, 200);
|
||||
}
|
||||
|
||||
|
||||
int pixy_render_cropped_frame(uint16_t x, uint16_t y, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height)
|
||||
{
|
||||
uint8_t* videodata;
|
||||
int32_t response;
|
||||
int32_t fourccc;
|
||||
int8_t renderflags;
|
||||
uint16_t xwidth;
|
||||
uint16_t ywidth;
|
||||
uint32_t size;
|
||||
|
||||
|
||||
int return_value = pixy_command("cam_getFrame", // String id for remote procedure
|
||||
INT8(0x21), // mode
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
&fourccc,
|
||||
&renderflags,
|
||||
&xwidth,
|
||||
&ywidth,
|
||||
&size,
|
||||
&videodata, // pointer to mem address for returned frame
|
||||
END_IN_ARGS);
|
||||
|
||||
if (return_value == 0) {
|
||||
return_value = renderBA81(x, y, xwidth, ywidth, size, videodata);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x&1)
|
||||
{
|
||||
*r = (*(pixel-width)+*(pixel+width))>>1;
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
int pixy_save_full_frame(FILE_HANDLE* handle)
|
||||
{
|
||||
return pixy_save_cropped_frame(handle, 0, 0, 320, 200);
|
||||
}
|
||||
|
||||
int pixy_save_cropped_frame(FILE_HANDLE* handle, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height)
|
||||
{
|
||||
uint8_t* videodata;
|
||||
int32_t response;
|
||||
int32_t fourccc;
|
||||
int8_t renderflags;
|
||||
uint16_t xwidth;
|
||||
uint16_t ywidth;
|
||||
uint32_t size;
|
||||
|
||||
|
||||
int return_value = pixy_command("cam_getFrame", // String id for remote procedure
|
||||
INT8(0x21), // mode
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
&fourccc,
|
||||
&renderflags,
|
||||
&xwidth,
|
||||
&ywidth,
|
||||
&size,
|
||||
&videodata, // pointer to mem address for returned frame
|
||||
END_IN_ARGS);
|
||||
|
||||
if (return_value == 0) {
|
||||
return_value = saveBA81(handle, xwidth, ywidth, size, videodata);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t* pixel, uint8_t* r, uint8_t* g, uint8_t* b)
|
||||
{
|
||||
if (y & 1) {
|
||||
if (x & 1) {
|
||||
*r = *pixel;
|
||||
*g = (*(pixel - 1) + * (pixel + 1) + * (pixel + width) + * (pixel - width)) >> 2;
|
||||
*b = (*(pixel - width - 1) + * (pixel - width + 1) + * (pixel + width - 1) + * (pixel + width + 1)) >> 2;
|
||||
} else {
|
||||
*r = (*(pixel - 1) + * (pixel + 1)) >> 1;
|
||||
*g = *pixel;
|
||||
*b = (*(pixel-1)+*(pixel+1))>>1;
|
||||
*b = (*(pixel - width) + * (pixel + width)) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
|
||||
*g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
|
||||
} else {
|
||||
if (x & 1) {
|
||||
*r = (*(pixel - width) + * (pixel + width)) >> 1;
|
||||
*g = *pixel;
|
||||
*b = (*(pixel - 1) + * (pixel + 1)) >> 1;
|
||||
} else {
|
||||
*r = (*(pixel - width - 1) + * (pixel - width + 1) + * (pixel + width - 1) + * (pixel + width + 1)) >> 2;
|
||||
*g = (*(pixel - 1) + * (pixel + 1) + * (pixel + width) + * (pixel - width)) >> 2;
|
||||
*b = *pixel;
|
||||
}
|
||||
}
|
||||
@@ -128,7 +136,7 @@ static void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pi
|
||||
|
||||
|
||||
|
||||
static int renderBA81(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
|
||||
static int renderBA81(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t* frame)
|
||||
{
|
||||
uint16_t x, y;
|
||||
uint8_t r, g, b;
|
||||
@@ -140,102 +148,101 @@ static int renderBA81(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t hei
|
||||
// don't render top and bottom rows, and left and rightmost columns because of color
|
||||
// interpolation
|
||||
//uint32_t decodedimage[(width-2)*(height-2)];
|
||||
uint16_t* decodedimage = malloc(sizeof(uint16_t)*(width-2)*(height-2));
|
||||
uint16_t* decodedimage = malloc(sizeof(uint16_t) * (width - 2) * (height - 2));
|
||||
|
||||
if(decodedimage==NULL) { //not enough free space to decode image in memory
|
||||
if (decodedimage == NULL) { //not enough free space to decode image in memory
|
||||
//decode & render image pixel by pixel
|
||||
for (y=1; y<height-1; y++)
|
||||
{
|
||||
frame++;
|
||||
for (x=1; x<width-1; x++, frame++)
|
||||
{
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
tft_draw_pixel(xpos+x-1,ypos+y-1,RGB(r,g,b));
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
} else { //enough space
|
||||
uint16_t* line = decodedimage;
|
||||
for (y=1; y<height-1; y++)
|
||||
{
|
||||
//line = (unsigned int *)img.scanLine(y-1);
|
||||
frame++;
|
||||
for (x=1; x<width-1; x++, frame++)
|
||||
{
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
//*line++ = (0xff<<24) | (r<<16) | (g<<8) | (b<<0);
|
||||
*line++ = RGB(r,g,b);
|
||||
}
|
||||
frame++;
|
||||
for (y = 1; y < height - 1; y++) {
|
||||
frame++;
|
||||
|
||||
for (x = 1; x < width - 1; x++, frame++) {
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
tft_draw_pixel(xpos + x - 1, ypos + y - 1, RGB(r, g, b));
|
||||
}
|
||||
|
||||
tft_draw_bitmap_unscaled(xpos,ypos,width-2,height-2,decodedimage);
|
||||
frame++;
|
||||
}
|
||||
} else { //enough space
|
||||
uint16_t* line = decodedimage;
|
||||
|
||||
free(decodedimage);
|
||||
for (y = 1; y < height - 1; y++) {
|
||||
//line = (unsigned int *)img.scanLine(y-1);
|
||||
frame++;
|
||||
|
||||
for (x = 1; x < width - 1; x++, frame++) {
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
//*line++ = (0xff<<24) | (r<<16) | (g<<8) | (b<<0);
|
||||
*line++ = RGB(r, g, b);
|
||||
}
|
||||
|
||||
frame++;
|
||||
}
|
||||
|
||||
tft_draw_bitmap_unscaled(xpos, ypos, width - 2, height - 2, decodedimage);
|
||||
|
||||
free(decodedimage);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int saveBA81(FILE_HANDLE* handle, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
|
||||
static int saveBA81(FILE_HANDLE* handle, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t* frame)
|
||||
{
|
||||
uint16_t x, y;
|
||||
uint8_t r, g, b;
|
||||
|
||||
uint32_t fpos = handle->fpos;
|
||||
uint32_t row_size_padded = ((width-2)*3 + 3) & (~3); //row size aligned to 4 bytes
|
||||
uint32_t fpos_end = fpos + row_size_padded* (height-2);
|
||||
uint32_t row_size_padded = ((width - 2) * 3 + 3) & (~3); //row size aligned to 4 bytes
|
||||
uint32_t fpos_end = fpos + row_size_padded * (height - 2);
|
||||
|
||||
|
||||
// skip first line
|
||||
frame += width;
|
||||
|
||||
// don't render top and bottom rows, and left and rightmost columns because of color
|
||||
// interpolation
|
||||
// interpolation
|
||||
|
||||
for (y=1; y<height-1; y++)
|
||||
{
|
||||
frame++;
|
||||
uint8_t rowbuf[row_size_padded];
|
||||
for (y = 1; y < height - 1; y++) {
|
||||
frame++;
|
||||
uint8_t rowbuf[row_size_padded];
|
||||
|
||||
//Bitmaps are saved "bottom-up". Seek to the right row.
|
||||
if(filesystem_file_seek(handle,fpos_end-row_size_padded*y)!=F_OK) {
|
||||
return -1;
|
||||
}
|
||||
//Bitmaps are saved "bottom-up". Seek to the right row.
|
||||
if (filesystem_file_seek(handle, fpos_end - row_size_padded * y) != F_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (x=1; x<width-1; x++, frame++)
|
||||
{
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
//bitmaps are saved in 24bit b,g,r format
|
||||
rowbuf[(x-1)*3] = b;
|
||||
rowbuf[(x-1)*3+1] = g;
|
||||
rowbuf[(x-1)*3+2] = r;
|
||||
}
|
||||
for (x = 1; x < width - 1; x++, frame++) {
|
||||
interpolateBayer(width, x, y, frame, &r, &g, &b);
|
||||
//bitmaps are saved in 24bit b,g,r format
|
||||
rowbuf[(x - 1) * 3] = b;
|
||||
rowbuf[(x - 1) * 3 + 1] = g;
|
||||
rowbuf[(x - 1) * 3 + 2] = r;
|
||||
}
|
||||
|
||||
if(filesystem_file_write(handle,rowbuf,row_size_padded)!=F_OK) {
|
||||
return -1;
|
||||
}
|
||||
if (filesystem_file_write(handle, rowbuf, row_size_padded) != F_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
frame++;
|
||||
}
|
||||
return 0;
|
||||
frame++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pixy_cc_set_region(uint8_t signum, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height) {
|
||||
int32_t response;
|
||||
int pixy_cc_set_region(uint8_t signum, uint16_t xoffset, uint16_t yoffset, uint16_t width, uint16_t height)
|
||||
{
|
||||
int32_t response;
|
||||
|
||||
int return_value = pixy_command("cc_setSigRegion", // String id for remote procedure
|
||||
INT32(0), // type = normal color code
|
||||
INT8(signum),
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
END_IN_ARGS);
|
||||
return return_value;
|
||||
int return_value = pixy_command("cc_setSigRegion", // String id for remote procedure
|
||||
INT32(0), // type = normal color code
|
||||
INT8(signum),
|
||||
INT16(xoffset), // xoffset
|
||||
INT16(yoffset), // yoffset
|
||||
INT16(width), // width
|
||||
INT16(height), // height
|
||||
END_OUT_ARGS, // separator
|
||||
&response, // pointer to mem address for return value
|
||||
END_IN_ARGS);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/pixy_frame.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef PIXY_FRAME_H
|
||||
#define PIXY_FRAME_H
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_filetest.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-10 timolang@gmail.com 790f602 Added bitmap decoding/drawing example
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-15 timolang@gmail.com 85f1aee Changed filetest to use new bitmap draw method.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_filetest.h"
|
||||
#include "button.h"
|
||||
#include "tft.h"
|
||||
@@ -7,133 +24,132 @@
|
||||
|
||||
static BUTTON_STRUCT b_back;
|
||||
|
||||
static void b_back_cb(void* button) {
|
||||
gui_screen_back();
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
gui_screen_back();
|
||||
}
|
||||
|
||||
|
||||
static void image_test();
|
||||
|
||||
static void enter(void* screen) {
|
||||
tft_clear(HEX(0xBABECD));
|
||||
|
||||
//Back button
|
||||
b_back.base.x1=10; //Start X of Button
|
||||
b_back.base.y1=200; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //b_back.base.x1+160; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(HEX(0xBABECD));
|
||||
|
||||
//Back button
|
||||
b_back.base.x1 = 10; //Start X of Button
|
||||
b_back.base.y1 = 200; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //b_back.base.x1+160; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
/*
|
||||
//tft test
|
||||
tft_draw_pixel(0,0,BLACK);
|
||||
tft_draw_pixel(319,239,BLACK);
|
||||
tft_draw_pixel(10,210,BLUE);
|
||||
tft_draw_pixel(12,210,BLUE);
|
||||
tft_draw_rectangle(40,100,60,235,BLUE);
|
||||
tft_fill_rectangle(100,215,200,225,GREEN);
|
||||
tft_draw_line(10,50,310,225,RGB(0xFF,0,0xFF));
|
||||
tft_draw_circle(10,10,100, RED);
|
||||
tft_print_line(30, 130, RED, BLUE, 0, "Hallo");
|
||||
*/
|
||||
tft_draw_line(10, 30, 310, 30, BLACK);
|
||||
tft_print_line(10, 18, BLUE, TRANSPARENT, 0, "Name D H RO Date Time Size");
|
||||
|
||||
tft_draw_line(10,30,310,30,BLACK);
|
||||
tft_print_line(10,18,BLUE,TRANSPARENT,0,"Name D H RO Date Time Size");
|
||||
|
||||
int y = 33;
|
||||
|
||||
DIRECTORY_STRUCT* dir = filesystem_dir_open(".");
|
||||
if(dir==NULL) return;
|
||||
int y = 33;
|
||||
|
||||
for(int i=0; i<dir->num_files; i++) {
|
||||
FILE_STRUCT* file = &(dir->files[i]);
|
||||
tft_print_formatted(10,y,
|
||||
(file->fattrib&F_DIR)?GREEN:RED,
|
||||
TRANSPARENT,0,"%-13s%c %c %s %02u%02u%02u %02u:%02u:%02u %u",
|
||||
file->fname,
|
||||
(file->fattrib&F_DIR)?'D':' ',
|
||||
(file->fattrib&F_HID)?'H':' ',
|
||||
(file->fattrib&F_RDO)?"R ":"RW",
|
||||
file->fdate.day,
|
||||
file->fdate.month,
|
||||
(file->fdate.year+1980)%100,
|
||||
file->ftime.hour,
|
||||
file->ftime.min,
|
||||
file->ftime.sec*2,
|
||||
file->fsize);
|
||||
y+=14;
|
||||
}
|
||||
DIRECTORY_STRUCT* dir = filesystem_dir_open(".");
|
||||
|
||||
filesystem_dir_close(dir);
|
||||
if (dir == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
y+=14;
|
||||
for (int i = 0; i < dir->num_files; i++) {
|
||||
FILE_STRUCT* file = &(dir->files[i]);
|
||||
tft_print_formatted(10, y,
|
||||
(file->fattrib & F_DIR) ? GREEN : RED,
|
||||
TRANSPARENT, 0, "%-13s%c %c %s %02u%02u%02u %02u:%02u:%02u %u",
|
||||
file->fname,
|
||||
(file->fattrib & F_DIR) ? 'D' : ' ',
|
||||
(file->fattrib & F_HID) ? 'H' : ' ',
|
||||
(file->fattrib & F_RDO) ? "R " : "RW",
|
||||
file->fdate.day,
|
||||
file->fdate.month,
|
||||
(file->fdate.year + 1980) % 100,
|
||||
file->ftime.hour,
|
||||
file->ftime.min,
|
||||
file->ftime.sec * 2,
|
||||
file->fsize);
|
||||
y += 14;
|
||||
}
|
||||
|
||||
FILE_HANDLE* file = filesystem_file_open("test.txt");
|
||||
if(file==NULL) {
|
||||
tft_print_line(10,y,BLUE,TRANSPARENT,0,"Could not open test.txt");
|
||||
} else {
|
||||
char buf [30];
|
||||
int size = (file->fsize>30)?29:file->fsize-1;
|
||||
FILE_STATUS st = filesystem_file_read(file,buf,size);
|
||||
|
||||
if(st==F_OK) {
|
||||
buf[file->fpos]='\0';
|
||||
tft_print_formatted(10,y,BLUE,TRANSPARENT,0,"test.txt contains \"%s\"",buf);
|
||||
long num = strtol(&(buf[file->fpos-4]),NULL,0);
|
||||
num++;
|
||||
|
||||
y+=14;
|
||||
|
||||
if(filesystem_file_seek(file,file->fpos-4)!=F_OK) {
|
||||
tft_print_formatted(10,y,BLUE,TRANSPARENT,0,"Could not seek to %d",file->fpos-4);
|
||||
} else {
|
||||
sprintf(buf,"%04d",num);
|
||||
if(filesystem_file_write(file,buf,4) != F_OK) {
|
||||
tft_print_formatted(10,y,BLUE,TRANSPARENT,0,"Could not write new number %d",num);
|
||||
} else {
|
||||
tft_print_formatted(10,y,BLUE,TRANSPARENT,0,"New number written %d",num);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tft_print_line(10,y,BLUE,TRANSPARENT,0,"Could not read from test.txt");
|
||||
}
|
||||
filesystem_dir_close(dir);
|
||||
|
||||
}
|
||||
filesystem_file_close(file);
|
||||
y += 14;
|
||||
|
||||
image_test();
|
||||
FILE_HANDLE* file = filesystem_file_open("test.txt");
|
||||
|
||||
if (file == NULL) {
|
||||
tft_print_line(10, y, BLUE, TRANSPARENT, 0, "Could not open test.txt");
|
||||
} else {
|
||||
char buf [30];
|
||||
int size = (file->fsize > 30) ? 29 : file->fsize - 1;
|
||||
FILE_STATUS st = filesystem_file_read(file, buf, size);
|
||||
|
||||
if (st == F_OK) {
|
||||
buf[file->fpos] = '\0';
|
||||
tft_print_formatted(10, y, BLUE, TRANSPARENT, 0, "test.txt contains \"%s\"", buf);
|
||||
long num = strtol(&(buf[file->fpos - 4]), NULL, 0);
|
||||
num++;
|
||||
|
||||
y += 14;
|
||||
|
||||
if (filesystem_file_seek(file, file->fpos - 4) != F_OK) {
|
||||
tft_print_formatted(10, y, BLUE, TRANSPARENT, 0, "Could not seek to %d", file->fpos - 4);
|
||||
} else {
|
||||
sprintf(buf, "%04d", num);
|
||||
|
||||
if (filesystem_file_write(file, buf, 4) != F_OK) {
|
||||
tft_print_formatted(10, y, BLUE, TRANSPARENT, 0, "Could not write new number %d", num);
|
||||
} else {
|
||||
tft_print_formatted(10, y, BLUE, TRANSPARENT, 0, "New number written %d", num);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tft_print_line(10, y, BLUE, TRANSPARENT, 0, "Could not read from test.txt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
filesystem_file_close(file);
|
||||
|
||||
image_test();
|
||||
}
|
||||
|
||||
static void leave(void* screen) {
|
||||
gui_button_remove(&b_back);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
gui_button_remove(&b_back);
|
||||
}
|
||||
|
||||
static void update(void* screen) {
|
||||
static void update(void* screen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_filetest() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_filetest()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
static void image_test() {
|
||||
static void image_test()
|
||||
{
|
||||
|
||||
|
||||
if(!tft_draw_bitmap_file_unscaled(250,170,"cpu.bmp")) {
|
||||
tft_print_line(10,180,BLUE,TRANSPARENT,0,"Could not open cpu.bmp");
|
||||
}
|
||||
tft_draw_rectangle(250-1,170-1,250-1+64,170-1+64,BLACK);
|
||||
if (!tft_draw_bitmap_file_unscaled(250, 170, "cpu.bmp")) {
|
||||
tft_print_line(10, 180, BLUE, TRANSPARENT, 0, "Could not open cpu.bmp");
|
||||
}
|
||||
|
||||
tft_draw_rectangle(250 - 1, 170 - 1, 250 - 1 + 64, 170 - 1 + 64, BLACK);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_filetest.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_guitest.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-04-30 timolang@gmail.com 76ea9d8 Added num up down support.
|
||||
* 2015-05-09 timolang@gmail.com c652b6b Improved Emulator Gui
|
||||
* 2015-05-29 aaron@duckpond.ch 7d2d1a1 Implemented basic sampling and averaging of touch coordinates using timer7
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
* 2015-06-02 timolang@gmail.com da34bce Fixed all printf related problems on discovery using workarounds and newlib nano-instead of newlib
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_guitest.h"
|
||||
#include "button.h"
|
||||
#include "tft.h"
|
||||
@@ -9,127 +27,138 @@ static TOUCH_AREA_STRUCT a_area;
|
||||
static CHECKBOX_STRUCT c_cbox;
|
||||
static NUMUPDOWN_STRUCT n_updown;
|
||||
|
||||
static void checkboxCB(void *checkbox, bool checked) {
|
||||
printf("Checkbox %s\n",(checked?"checked":"unchecked"));
|
||||
static void checkboxCB(void* checkbox, bool checked)
|
||||
{
|
||||
printf("Checkbox %s\n", (checked ? "checked" : "unchecked"));
|
||||
}
|
||||
|
||||
static void b_back_cb(void* button) {
|
||||
gui_screen_back();
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
gui_screen_back();
|
||||
}
|
||||
|
||||
static void n_updown_cb(void* numupdown, int16_t value) {
|
||||
printf("New NumUpDown Value %d\n",value);
|
||||
static void n_updown_cb(void* numupdown, int16_t value)
|
||||
{
|
||||
printf("New NumUpDown Value %d\n", value);
|
||||
}
|
||||
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction) {
|
||||
|
||||
switch(triggeredAction) {
|
||||
case PEN_DOWN:
|
||||
printf("action PEN_DOWN\n");
|
||||
break;
|
||||
case PEN_UP:
|
||||
printf("action PEN_UP\n");
|
||||
break;
|
||||
case PEN_MOVE:
|
||||
printf("action PEN_MOVE\n");
|
||||
break;
|
||||
case PEN_ENTER:
|
||||
printf("action PEN_ENTER\n");
|
||||
break;
|
||||
case PEN_LEAVE:
|
||||
printf("action PEN_LEAVE\n");
|
||||
break;
|
||||
default:
|
||||
printf("action %s\n",triggeredAction);
|
||||
break;
|
||||
}
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
|
||||
switch (triggeredAction) {
|
||||
case PEN_DOWN:
|
||||
printf("action PEN_DOWN\n");
|
||||
break;
|
||||
|
||||
case PEN_UP:
|
||||
printf("action PEN_UP\n");
|
||||
break;
|
||||
|
||||
case PEN_MOVE:
|
||||
printf("action PEN_MOVE\n");
|
||||
break;
|
||||
|
||||
case PEN_ENTER:
|
||||
printf("action PEN_ENTER\n");
|
||||
break;
|
||||
|
||||
case PEN_LEAVE:
|
||||
printf("action PEN_LEAVE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("action %s\n", triggeredAction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void enter(void* screen) {
|
||||
tft_clear(HEX(0xA6FD9A));
|
||||
|
||||
//Back button
|
||||
b_back.base.x1=10; //Start X of Button
|
||||
b_back.base.y1=10; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //b_back.base.x1+160; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(HEX(0xA6FD9A));
|
||||
|
||||
//Back button
|
||||
b_back.base.x1 = 10; //Start X of Button
|
||||
b_back.base.y1 = 10; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //b_back.base.x1+160; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
|
||||
//tft test
|
||||
tft_draw_pixel(0,0,BLACK);
|
||||
tft_draw_pixel(319,239,BLACK);
|
||||
tft_draw_pixel(10,210,BLUE);
|
||||
tft_draw_pixel(12,210,BLUE);
|
||||
tft_draw_rectangle(40,100,60,235,BLUE);
|
||||
tft_fill_rectangle(100,215,200,225,GREEN);
|
||||
tft_draw_line(10,50,310,225,RGB(0xFF,0,0xFF));
|
||||
tft_draw_circle(10,10,100, RED);
|
||||
tft_print_line(30, 130, RED, BLUE, 0, "Hallo");
|
||||
|
||||
|
||||
|
||||
//Area test
|
||||
a_area.hookedActions = PEN_DOWN | PEN_UP | PEN_MOVE | PEN_ENTER | PEN_LEAVE;
|
||||
a_area.x1 = 130;
|
||||
a_area.y1 = 30;
|
||||
a_area.x2 = 200;
|
||||
a_area.y2 = 60;
|
||||
a_area.callback = touchCB;
|
||||
touch_register_area(&a_area);
|
||||
//tft test
|
||||
tft_draw_pixel(0, 0, BLACK);
|
||||
tft_draw_pixel(319, 239, BLACK);
|
||||
tft_draw_pixel(10, 210, BLUE);
|
||||
tft_draw_pixel(12, 210, BLUE);
|
||||
tft_draw_rectangle(40, 100, 60, 235, BLUE);
|
||||
tft_fill_rectangle(100, 215, 200, 225, GREEN);
|
||||
tft_draw_line(10, 50, 310, 225, RGB(0xFF, 0, 0xFF));
|
||||
tft_draw_circle(10, 10, 100, RED);
|
||||
tft_print_line(30, 130, RED, BLUE, 0, "Hallo");
|
||||
|
||||
|
||||
|
||||
//Checkbox test
|
||||
c_cbox.base.x1=220;
|
||||
c_cbox.base.y1=45;
|
||||
c_cbox.base.x2=c_cbox.base.x1+16;
|
||||
c_cbox.base.y2=c_cbox.base.y1+16;
|
||||
c_cbox.fgcolor = GREEN;
|
||||
c_cbox.checked = true;
|
||||
c_cbox.callback = checkboxCB;
|
||||
gui_checkbox_add(&c_cbox);
|
||||
|
||||
//Area test
|
||||
a_area.hookedActions = PEN_DOWN | PEN_UP | PEN_MOVE | PEN_ENTER | PEN_LEAVE;
|
||||
a_area.x1 = 130;
|
||||
a_area.y1 = 30;
|
||||
a_area.x2 = 200;
|
||||
a_area.y2 = 60;
|
||||
a_area.callback = touchCB;
|
||||
touch_register_area(&a_area);
|
||||
|
||||
//Num up down test
|
||||
n_updown.x=200;
|
||||
n_updown.y=120;
|
||||
n_updown.fgcolor=RED;
|
||||
n_updown.value = -3;
|
||||
n_updown.max=11;
|
||||
n_updown.min =-5;
|
||||
n_updown.callback=n_updown_cb;
|
||||
gui_numupdown_add(&n_updown);
|
||||
|
||||
|
||||
//Checkbox test
|
||||
c_cbox.base.x1 = 220;
|
||||
c_cbox.base.y1 = 45;
|
||||
c_cbox.base.x2 = c_cbox.base.x1 + 16;
|
||||
c_cbox.base.y2 = c_cbox.base.y1 + 16;
|
||||
c_cbox.fgcolor = GREEN;
|
||||
c_cbox.checked = true;
|
||||
c_cbox.callback = checkboxCB;
|
||||
gui_checkbox_add(&c_cbox);
|
||||
|
||||
|
||||
//Num up down test
|
||||
n_updown.x = 200;
|
||||
n_updown.y = 120;
|
||||
n_updown.fgcolor = RED;
|
||||
n_updown.value = -3;
|
||||
n_updown.max = 11;
|
||||
n_updown.min = -5;
|
||||
n_updown.callback = n_updown_cb;
|
||||
gui_numupdown_add(&n_updown);
|
||||
|
||||
}
|
||||
|
||||
static void leave(void* screen) {
|
||||
gui_button_remove(&b_back);
|
||||
gui_checkbox_remove(&c_cbox);
|
||||
gui_numupdown_remove(&n_updown);
|
||||
touch_unregister_area(&a_area);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
gui_button_remove(&b_back);
|
||||
gui_checkbox_remove(&c_cbox);
|
||||
gui_numupdown_remove(&n_updown);
|
||||
touch_unregister_area(&a_area);
|
||||
}
|
||||
|
||||
static void update(void* screen) {
|
||||
//gui_button_redraw(&b_back); //only needed if button is overdrawn by others
|
||||
//.... for the other elements as well
|
||||
static void update(void* screen)
|
||||
{
|
||||
//gui_button_redraw(&b_back); //only needed if button is overdrawn by others
|
||||
//.... for the other elements as well
|
||||
}
|
||||
|
||||
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_guitest() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_guitest()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_guitest.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_main.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-15 timolang@gmail.com 27c09ba Redesigned main menu. Moved stuff from pixytest to a new helper file and to the new "photo mode"-screen.
|
||||
* 2015-05-16 timolang@gmail.com e46314b Added Tracking Screen and implemented "Reference Tracking" and "Color Region Selection"
|
||||
* 2015-06-01 aaron@duckpond.ch caa7b5c Added IRQ for user button, fixed some touchproblems.
|
||||
* 2015-06-01 timolang@gmail.com 3155f42 Fixed mainscreen layout.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_main.h"
|
||||
#include "screen_guitest.h"
|
||||
#include "screen_pixytest.h"
|
||||
@@ -17,157 +35,165 @@ BUTTON_STRUCT b_ref_tracking;
|
||||
BUTTON_STRUCT b_photo_mode;
|
||||
|
||||
|
||||
static void b_our_tracking_cb(void* button) {
|
||||
tracking_set_mode(OUR_TRACKING);
|
||||
gui_screen_navigate(get_screen_tracking());
|
||||
static void b_our_tracking_cb(void* button)
|
||||
{
|
||||
tracking_set_mode(OUR_TRACKING);
|
||||
gui_screen_navigate(get_screen_tracking());
|
||||
}
|
||||
|
||||
static void b_ref_tracking_cb(void* button) {
|
||||
tracking_set_mode(REFERENCE_TRACKING);
|
||||
gui_screen_navigate(get_screen_tracking());
|
||||
static void b_ref_tracking_cb(void* button)
|
||||
{
|
||||
tracking_set_mode(REFERENCE_TRACKING);
|
||||
gui_screen_navigate(get_screen_tracking());
|
||||
}
|
||||
|
||||
static void b_photo_mode_cb(void* button) {
|
||||
gui_screen_navigate(get_screen_photomode());
|
||||
static void b_photo_mode_cb(void* button)
|
||||
{
|
||||
gui_screen_navigate(get_screen_photomode());
|
||||
}
|
||||
|
||||
static void b_guitest_cb(void* button) {
|
||||
gui_screen_navigate(get_screen_guitest());
|
||||
static void b_guitest_cb(void* button)
|
||||
{
|
||||
gui_screen_navigate(get_screen_guitest());
|
||||
}
|
||||
|
||||
static void b_filetest_cb(void* button) {
|
||||
gui_screen_navigate(get_screen_filetest());
|
||||
static void b_filetest_cb(void* button)
|
||||
{
|
||||
gui_screen_navigate(get_screen_filetest());
|
||||
}
|
||||
|
||||
static void b_pixytest_cb(void* button) {
|
||||
gui_screen_navigate(get_screen_pixytest());
|
||||
static void b_pixytest_cb(void* button)
|
||||
{
|
||||
gui_screen_navigate(get_screen_pixytest());
|
||||
}
|
||||
|
||||
|
||||
static void enter(void* screen) {
|
||||
tft_clear(WHITE);
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(WHITE);
|
||||
|
||||
//Heading
|
||||
tft_print_line(10,10,BLUE,TRANSPARENT,1,"Discoverpixy");
|
||||
tft_draw_line(0,40,319,40,BLACK);
|
||||
//Heading
|
||||
tft_print_line(10, 10, BLUE, TRANSPARENT, 1, "Discoverpixy");
|
||||
tft_draw_line(0, 40, 319, 40, BLACK);
|
||||
|
||||
#define X_TAB 97
|
||||
#define BUTTON_SPACING 7
|
||||
#define X_TAB 97
|
||||
#define BUTTON_SPACING 7
|
||||
|
||||
//First line of buttons
|
||||
#define Y_FIRST 60
|
||||
tft_print_line(10,Y_FIRST,BLACK,TRANSPARENT,0,"Tracking:");
|
||||
//First line of buttons
|
||||
#define Y_FIRST 60
|
||||
tft_print_line(10, Y_FIRST, BLACK, TRANSPARENT, 0, "Tracking:");
|
||||
|
||||
b_our_tracking.base.x1=X_TAB; //Start X of Button
|
||||
b_our_tracking.base.y1=Y_FIRST-3; //Start Y of Button
|
||||
b_our_tracking.base.x2=AUTO; //Auto Calculate X2 with String Width
|
||||
b_our_tracking.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_our_tracking.txtcolor=WHITE; //Set foreground color
|
||||
b_our_tracking.bgcolor=HEX(0xE30535); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_our_tracking.font=0; //Select Font
|
||||
b_our_tracking.text="Our Tracking"; //Set Text (For formatted strings take sprintf)
|
||||
b_our_tracking.callback=b_our_tracking_cb; //Call b_our_tracking when the button get's pressed
|
||||
gui_button_add(&b_our_tracking); //Register Button (and run the callback from now on)
|
||||
b_our_tracking.base.x1 = X_TAB; //Start X of Button
|
||||
b_our_tracking.base.y1 = Y_FIRST - 3; //Start Y of Button
|
||||
b_our_tracking.base.x2 = AUTO; //Auto Calculate X2 with String Width
|
||||
b_our_tracking.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_our_tracking.txtcolor = WHITE; //Set foreground color
|
||||
b_our_tracking.bgcolor = HEX(0xE30535); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_our_tracking.font = 0; //Select Font
|
||||
b_our_tracking.text = "Our Tracking"; //Set Text (For formatted strings take sprintf)
|
||||
b_our_tracking.callback = b_our_tracking_cb; //Call b_our_tracking when the button get's pressed
|
||||
gui_button_add(&b_our_tracking); //Register Button (and run the callback from now on)
|
||||
|
||||
|
||||
b_ref_tracking.base.x1=b_our_tracking.base.x2+BUTTON_SPACING;
|
||||
b_ref_tracking.base.y1=Y_FIRST-3;
|
||||
b_ref_tracking.base.x2=AUTO;
|
||||
b_ref_tracking.base.y2=AUTO;
|
||||
b_ref_tracking.txtcolor=WHITE;
|
||||
b_ref_tracking.bgcolor=HEX(0xFF2151);
|
||||
b_ref_tracking.font=0;
|
||||
b_ref_tracking.text="Ref Tracking";
|
||||
b_ref_tracking.callback=b_ref_tracking_cb;
|
||||
gui_button_add(&b_ref_tracking);
|
||||
b_ref_tracking.base.x1 = b_our_tracking.base.x2 + BUTTON_SPACING;
|
||||
b_ref_tracking.base.y1 = Y_FIRST - 3;
|
||||
b_ref_tracking.base.x2 = AUTO;
|
||||
b_ref_tracking.base.y2 = AUTO;
|
||||
b_ref_tracking.txtcolor = WHITE;
|
||||
b_ref_tracking.bgcolor = HEX(0xFF2151);
|
||||
b_ref_tracking.font = 0;
|
||||
b_ref_tracking.text = "Ref Tracking";
|
||||
b_ref_tracking.callback = b_ref_tracking_cb;
|
||||
gui_button_add(&b_ref_tracking);
|
||||
|
||||
//Second line of buttons
|
||||
#define Y_SECOND Y_FIRST+25
|
||||
tft_print_line(10,Y_SECOND,BLACK,TRANSPARENT,0,"Photo mode:");
|
||||
//Second line of buttons
|
||||
#define Y_SECOND Y_FIRST+25
|
||||
tft_print_line(10, Y_SECOND, BLACK, TRANSPARENT, 0, "Photo mode:");
|
||||
|
||||
b_photo_mode.base.x1=X_TAB;
|
||||
b_photo_mode.base.y1=Y_SECOND-3;
|
||||
b_photo_mode.base.x2=AUTO;
|
||||
b_photo_mode.base.y2=AUTO;
|
||||
b_photo_mode.txtcolor=WHITE;
|
||||
b_photo_mode.bgcolor=HEX(0x21B1FF);
|
||||
b_photo_mode.font=0;
|
||||
b_photo_mode.text="Photo Mode";
|
||||
b_photo_mode.callback=b_photo_mode_cb;
|
||||
gui_button_add(&b_photo_mode);
|
||||
b_photo_mode.base.x1 = X_TAB;
|
||||
b_photo_mode.base.y1 = Y_SECOND - 3;
|
||||
b_photo_mode.base.x2 = AUTO;
|
||||
b_photo_mode.base.y2 = AUTO;
|
||||
b_photo_mode.txtcolor = WHITE;
|
||||
b_photo_mode.bgcolor = HEX(0x21B1FF);
|
||||
b_photo_mode.font = 0;
|
||||
b_photo_mode.text = "Photo Mode";
|
||||
b_photo_mode.callback = b_photo_mode_cb;
|
||||
gui_button_add(&b_photo_mode);
|
||||
|
||||
|
||||
//Third line of buttons
|
||||
#define Y_THIRD Y_SECOND+25
|
||||
tft_print_line(10,Y_THIRD,BLACK,TRANSPARENT,0,"Tests:");
|
||||
//Third line of buttons
|
||||
#define Y_THIRD Y_SECOND+25
|
||||
tft_print_line(10, Y_THIRD, BLACK, TRANSPARENT, 0, "Tests:");
|
||||
|
||||
b_guitest.base.x1=X_TAB;
|
||||
b_guitest.base.y1=Y_THIRD-3;
|
||||
b_guitest.base.x2=AUTO;
|
||||
b_guitest.base.y2=AUTO;
|
||||
b_guitest.txtcolor=BLACK;
|
||||
b_guitest.bgcolor=HEX(0x00FA21);
|
||||
b_guitest.font=0;
|
||||
b_guitest.text="Gui & Tft";
|
||||
b_guitest.callback=b_guitest_cb;
|
||||
gui_button_add(&b_guitest);
|
||||
b_guitest.base.x1 = X_TAB;
|
||||
b_guitest.base.y1 = Y_THIRD - 3;
|
||||
b_guitest.base.x2 = AUTO;
|
||||
b_guitest.base.y2 = AUTO;
|
||||
b_guitest.txtcolor = BLACK;
|
||||
b_guitest.bgcolor = HEX(0x00FA21);
|
||||
b_guitest.font = 0;
|
||||
b_guitest.text = "Gui & Tft";
|
||||
b_guitest.callback = b_guitest_cb;
|
||||
gui_button_add(&b_guitest);
|
||||
|
||||
|
||||
b_pixytest.base.x1=b_guitest.base.x2+BUTTON_SPACING;
|
||||
b_pixytest.base.y1=Y_THIRD-3;
|
||||
b_pixytest.base.x2=AUTO;
|
||||
b_pixytest.base.y2=AUTO;
|
||||
b_pixytest.txtcolor=BLACK;
|
||||
b_pixytest.bgcolor=HEX(0x00FA96);
|
||||
b_pixytest.font=0;
|
||||
b_pixytest.text="Pixy";
|
||||
b_pixytest.callback=b_pixytest_cb;
|
||||
gui_button_add(&b_pixytest);
|
||||
b_pixytest.base.x1 = b_guitest.base.x2 + BUTTON_SPACING;
|
||||
b_pixytest.base.y1 = Y_THIRD - 3;
|
||||
b_pixytest.base.x2 = AUTO;
|
||||
b_pixytest.base.y2 = AUTO;
|
||||
b_pixytest.txtcolor = BLACK;
|
||||
b_pixytest.bgcolor = HEX(0x00FA96);
|
||||
b_pixytest.font = 0;
|
||||
b_pixytest.text = "Pixy";
|
||||
b_pixytest.callback = b_pixytest_cb;
|
||||
gui_button_add(&b_pixytest);
|
||||
|
||||
|
||||
b_filetest.base.x1=b_pixytest.base.x2+BUTTON_SPACING;
|
||||
b_filetest.base.y1=Y_THIRD-3;
|
||||
b_filetest.base.x2=AUTO;
|
||||
b_filetest.base.y2=AUTO;
|
||||
b_filetest.txtcolor=BLACK;
|
||||
b_filetest.bgcolor=HEX(0x00FAC4);
|
||||
b_filetest.font=0;
|
||||
b_filetest.text="File";
|
||||
b_filetest.callback=b_filetest_cb;
|
||||
gui_button_add(&b_filetest);
|
||||
b_filetest.base.x1 = b_pixytest.base.x2 + BUTTON_SPACING;
|
||||
b_filetest.base.y1 = Y_THIRD - 3;
|
||||
b_filetest.base.x2 = AUTO;
|
||||
b_filetest.base.y2 = AUTO;
|
||||
b_filetest.txtcolor = BLACK;
|
||||
b_filetest.bgcolor = HEX(0x00FAC4);
|
||||
b_filetest.font = 0;
|
||||
b_filetest.text = "File";
|
||||
b_filetest.callback = b_filetest_cb;
|
||||
gui_button_add(&b_filetest);
|
||||
|
||||
|
||||
//Bottom line
|
||||
tft_draw_line(0,145,319,145,BLACK);
|
||||
tft_print_line(10,150,BLUE,TRANSPARENT,0,"Powered by");
|
||||
tft_draw_bitmap_file_unscaled(10,165,"pixy_small.bmp");
|
||||
tft_draw_bitmap_file_unscaled(165,165,"stm_small.bmp");
|
||||
//Bottom line
|
||||
tft_draw_line(0, 145, 319, 145, BLACK);
|
||||
tft_print_line(10, 150, BLUE, TRANSPARENT, 0, "Powered by");
|
||||
tft_draw_bitmap_file_unscaled(10, 165, "pixy_small.bmp");
|
||||
tft_draw_bitmap_file_unscaled(165, 165, "stm_small.bmp");
|
||||
|
||||
}
|
||||
|
||||
static void leave(void* screen) {
|
||||
gui_button_remove(&b_our_tracking);
|
||||
gui_button_remove(&b_ref_tracking);
|
||||
gui_button_remove(&b_photo_mode);
|
||||
gui_button_remove(&b_guitest);
|
||||
gui_button_remove(&b_pixytest);
|
||||
gui_button_remove(&b_filetest);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
gui_button_remove(&b_our_tracking);
|
||||
gui_button_remove(&b_ref_tracking);
|
||||
gui_button_remove(&b_photo_mode);
|
||||
gui_button_remove(&b_guitest);
|
||||
gui_button_remove(&b_pixytest);
|
||||
gui_button_remove(&b_filetest);
|
||||
}
|
||||
|
||||
static void update(void* screen) {
|
||||
//gui_button_redraw(&b_guitest); //only needed if button is overdrawn by others
|
||||
static void update(void* screen)
|
||||
{
|
||||
//gui_button_redraw(&b_guitest); //only needed if button is overdrawn by others
|
||||
}
|
||||
|
||||
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_main() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_main()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_main.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-12 timolang@gmail.com 1402598 Added doxygen stuff for button module and some minor changes to touch, screen_main and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_photomode.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-15 timolang@gmail.com 27c09ba Redesigned main menu. Moved stuff from pixytest to a new helper file and to the new "photo mode"-screen.
|
||||
* 2015-05-16 timolang@gmail.com 62006e0 Documented pixy_helper and implemented/finished photo-mode screens! Snap some shots!
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_photomode.h"
|
||||
#include "screen_photomode_save.h"
|
||||
#include "button.h"
|
||||
@@ -12,155 +27,182 @@ static bool pixy_connected = false; //Whether or not the pixy cam is currently c
|
||||
static BUTTON_STRUCT b_back; //Button to navigate back
|
||||
static BUTTON_STRUCT b_save; //Button to save the current image
|
||||
static TOUCH_AREA_STRUCT a_area; //Touch Area, where the frame is drawn. Used to drag the image around
|
||||
static bool subMenu=false; //Whether or not we left the current screen for a submenu
|
||||
static bool subMenu = false; //Whether or not we left the current screen for a submenu
|
||||
|
||||
//Callback for when the user presses the "back" button
|
||||
static void b_back_cb(void* button) {
|
||||
subMenu = false; //we're not entering a submenu
|
||||
gui_screen_back(); //navigate back to the previous screen
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
subMenu = false; //we're not entering a submenu
|
||||
gui_screen_back(); //navigate back to the previous screen
|
||||
}
|
||||
|
||||
//Callback for when the user presses the "save" button
|
||||
static void b_save_cb(void* button) {
|
||||
subMenu = true; //we're entering a submenu
|
||||
gui_screen_navigate(get_screen_photomodesave()); //navigate to the save screen
|
||||
static void b_save_cb(void* button)
|
||||
{
|
||||
subMenu = true; //we're entering a submenu
|
||||
gui_screen_navigate(get_screen_photomodesave()); //navigate to the save screen
|
||||
}
|
||||
|
||||
static POINT_STRUCT pixy_pos; //The current position of pixy's servos
|
||||
static POINT_STRUCT old_pos; //The last touch position on the screen
|
||||
|
||||
//Callback for when the user drags the image around
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction) {
|
||||
POINT_STRUCT p = touch_get_last_point(); //get the last touched point
|
||||
switch(triggeredAction) {
|
||||
case PEN_ENTER:
|
||||
case PEN_DOWN:
|
||||
old_pos = p; //If the user "newly" enters the touch area, we set the "last" position to the current
|
||||
break;
|
||||
case PEN_MOVE: //the user is moving around, he entered the screen a while ago (old_pos is set)
|
||||
{
|
||||
int16_t deltaX = p.x - old_pos.x; //Calculate x difference between last and current touch
|
||||
int16_t deltaY = p.y - old_pos.y; //Calculate y difference between last and current touch
|
||||
old_pos=p; //store the current touch point for the next time
|
||||
//printf("%d %d\n",deltaX,deltaY);
|
||||
if(pixy_connected) {
|
||||
//Calculate new servo coordinates. 2 is just a proportional factor
|
||||
int16_t new_x = pixy_pos.x+deltaX*2;
|
||||
int16_t new_y = pixy_pos.y-deltaY*2;
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
POINT_STRUCT p = touch_get_last_point(); //get the last touched point
|
||||
|
||||
//check limits
|
||||
if(new_x<0) new_x=0;
|
||||
if(new_x>1000) new_x=1000;
|
||||
if(new_y<0) new_y=0;
|
||||
if(new_y>1000) new_y=1000;
|
||||
|
||||
//set pixy_pos so that the main routine can send it to the servos
|
||||
pixy_pos.x = new_x;
|
||||
pixy_pos.y= new_y;
|
||||
}
|
||||
}
|
||||
switch (triggeredAction) {
|
||||
case PEN_ENTER:
|
||||
case PEN_DOWN:
|
||||
old_pos = p; //If the user "newly" enters the touch area, we set the "last" position to the current
|
||||
break;
|
||||
case PEN_UP:
|
||||
case PEN_LEAVE:
|
||||
//printf("Leave/up\n");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
case PEN_MOVE: { //the user is moving around, he entered the screen a while ago (old_pos is set)
|
||||
int16_t deltaX = p.x - old_pos.x; //Calculate x difference between last and current touch
|
||||
int16_t deltaY = p.y - old_pos.y; //Calculate y difference between last and current touch
|
||||
old_pos = p; //store the current touch point for the next time
|
||||
|
||||
//printf("%d %d\n",deltaX,deltaY);
|
||||
if (pixy_connected) {
|
||||
//Calculate new servo coordinates. 2 is just a proportional factor
|
||||
int16_t new_x = pixy_pos.x + deltaX * 2;
|
||||
int16_t new_y = pixy_pos.y - deltaY * 2;
|
||||
|
||||
//check limits
|
||||
if (new_x < 0) {
|
||||
new_x = 0;
|
||||
}
|
||||
|
||||
if (new_x > 1000) {
|
||||
new_x = 1000;
|
||||
}
|
||||
|
||||
if (new_y < 0) {
|
||||
new_y = 0;
|
||||
}
|
||||
|
||||
if (new_y > 1000) {
|
||||
new_y = 1000;
|
||||
}
|
||||
|
||||
//set pixy_pos so that the main routine can send it to the servos
|
||||
pixy_pos.x = new_x;
|
||||
pixy_pos.y = new_y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PEN_UP:
|
||||
case PEN_LEAVE:
|
||||
//printf("Leave/up\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Callback for when the screen is entered/loaded
|
||||
static void enter(void* screen) {
|
||||
tft_clear(WHITE);
|
||||
|
||||
tft_print_line(5,5,BLACK,TRANSPARENT,0,"Drag the image around and ");
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(WHITE);
|
||||
|
||||
//Back button
|
||||
b_back.base.x1=5; //Start X of Button
|
||||
b_back.base.y1=19; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
tft_print_line(5, 5, BLACK, TRANSPARENT, 0, "Drag the image around and ");
|
||||
|
||||
//Save button
|
||||
b_save.base.x1=190;
|
||||
b_save.base.y1=3;
|
||||
b_save.base.x2=AUTO;
|
||||
b_save.base.y2=AUTO;
|
||||
b_save.txtcolor=WHITE;
|
||||
b_save.bgcolor=HEX(0x1010AE);
|
||||
b_save.font=0;
|
||||
b_save.text="Save it!";
|
||||
b_save.callback=b_save_cb;
|
||||
gui_button_add(&b_save);
|
||||
//Back button
|
||||
b_back.base.x1 = 5; //Start X of Button
|
||||
b_back.base.y1 = 19; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
//Frame Coordinates: topleft = (1,40); bottomright = (318,238)
|
||||
//Leave a 10px border for the area
|
||||
//Save button
|
||||
b_save.base.x1 = 190;
|
||||
b_save.base.y1 = 3;
|
||||
b_save.base.x2 = AUTO;
|
||||
b_save.base.y2 = AUTO;
|
||||
b_save.txtcolor = WHITE;
|
||||
b_save.bgcolor = HEX(0x1010AE);
|
||||
b_save.font = 0;
|
||||
b_save.text = "Save it!";
|
||||
b_save.callback = b_save_cb;
|
||||
gui_button_add(&b_save);
|
||||
|
||||
//Area to drag the image around
|
||||
a_area.hookedActions = PEN_DOWN | PEN_MOVE | PEN_ENTER | PEN_UP | PEN_LEAVE;
|
||||
a_area.x1 = 11;
|
||||
a_area.y1 = 50;
|
||||
a_area.x2 = 308;
|
||||
a_area.y2 = 228;
|
||||
a_area.callback = touchCB;
|
||||
touch_register_area(&a_area);
|
||||
//Frame Coordinates: topleft = (1,40); bottomright = (318,238)
|
||||
//Leave a 10px border for the area
|
||||
|
||||
//Pixy stuff
|
||||
pixy_connected = (pixy_init()==0); //try to connect to pixy
|
||||
if(pixy_connected && !subMenu) { //pixy is connected, but we are not coming from a submenu
|
||||
pixy_pos.x=pixy_pos.y=500; //reset servo positions to center
|
||||
}
|
||||
//Area to drag the image around
|
||||
a_area.hookedActions = PEN_DOWN | PEN_MOVE | PEN_ENTER | PEN_UP | PEN_LEAVE;
|
||||
a_area.x1 = 11;
|
||||
a_area.y1 = 50;
|
||||
a_area.x2 = 308;
|
||||
a_area.y2 = 228;
|
||||
a_area.callback = touchCB;
|
||||
touch_register_area(&a_area);
|
||||
|
||||
//Pixy stuff
|
||||
pixy_connected = (pixy_init() == 0); //try to connect to pixy
|
||||
|
||||
if (pixy_connected && !subMenu) { //pixy is connected, but we are not coming from a submenu
|
||||
pixy_pos.x = pixy_pos.y = 500; //reset servo positions to center
|
||||
}
|
||||
}
|
||||
|
||||
//Callback for when the screen is left/unloaded
|
||||
static void leave(void* screen) {
|
||||
//remove buttons and touch area.
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_save);
|
||||
touch_unregister_area(&a_area);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
//remove buttons and touch area.
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_save);
|
||||
touch_unregister_area(&a_area);
|
||||
}
|
||||
|
||||
//Callback for when the screen should be updated
|
||||
//This is the main loop of the screen. This method will be called repeatedly
|
||||
static void update(void* screen) {
|
||||
//Note: The only way to detect that pixy has been disconnected is if a command fails. There's no pixy_is_connected method yet :'(
|
||||
static void update(void* screen)
|
||||
{
|
||||
//Note: The only way to detect that pixy has been disconnected is if a command fails. There's no pixy_is_connected method yet :'(
|
||||
|
||||
if(!pixy_connected) { //Pixy not connected
|
||||
pixy_close(); //Ensure that all pixy resources are freed (failsafe)
|
||||
if(pixy_init()==0) { //try to connect to pixy
|
||||
pixy_connected=true;
|
||||
if(!subMenu) { //we're not coming from a submenu
|
||||
pixy_pos.x=pixy_pos.y=500; //reset servo positions to center
|
||||
}
|
||||
printf("pixy (re)initialized\n");
|
||||
}
|
||||
}
|
||||
if (!pixy_connected) { //Pixy not connected
|
||||
pixy_close(); //Ensure that all pixy resources are freed (failsafe)
|
||||
|
||||
if(pixy_connected) { //If we are connected (now)
|
||||
pixy_service(); //Handle pending pixy events (e.g. color info retrival)
|
||||
if (pixy_init() == 0) { //try to connect to pixy
|
||||
pixy_connected = true;
|
||||
|
||||
pixy_render_full_frame(1,40); //render the pixy video at point (1,40)
|
||||
|
||||
//set the servo positions to the coordinates form the touch interrupt
|
||||
pixy_rcs_set_position(0,pixy_pos.x);
|
||||
pixy_rcs_set_position(1,pixy_pos.y);
|
||||
}
|
||||
if (!subMenu) { //we're not coming from a submenu
|
||||
pixy_pos.x = pixy_pos.y = 500; //reset servo positions to center
|
||||
}
|
||||
|
||||
printf("pixy (re)initialized\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (pixy_connected) { //If we are connected (now)
|
||||
pixy_service(); //Handle pending pixy events (e.g. color info retrival)
|
||||
|
||||
pixy_render_full_frame(1, 40); //render the pixy video at point (1,40)
|
||||
|
||||
//set the servo positions to the coordinates form the touch interrupt
|
||||
pixy_rcs_set_position(0, pixy_pos.x);
|
||||
pixy_rcs_set_position(1, pixy_pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
//Declare screen callbacks
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_photomode() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_photomode()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_photomode.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-15 timolang@gmail.com 27c09ba Redesigned main menu. Moved stuff from pixytest to a new helper file and to the new "photo mode"-screen.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_photomode_save.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-16 timolang@gmail.com 62006e0 Documented pixy_helper and implemented/finished photo-mode screens! Snap some shots!
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_photomode_save.h"
|
||||
#include "filesystem.h"
|
||||
#include "button.h"
|
||||
@@ -13,8 +27,9 @@ static BUTTON_STRUCT b_back; //Button to navigate back
|
||||
static TOUCH_AREA_STRUCT a_area; //Touch area to select the save-file
|
||||
|
||||
//Callback for when the user presses the "back" button
|
||||
static void b_back_cb(void* button) {
|
||||
gui_screen_back();
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
gui_screen_back();
|
||||
}
|
||||
|
||||
static int num_files_ok; //number of files into which we can write the image (size, flags ok)
|
||||
@@ -24,46 +39,51 @@ static int liststart; //The y-Coordinate of the Start of the File-List
|
||||
static const char* picked_file; //The filename picked by the user, to save the image to
|
||||
|
||||
//Linked list structure to save all files which are suitable for saving.
|
||||
typedef struct FILE_LIST_ENTRY_S{
|
||||
char* filename; //Name of the file
|
||||
struct FILE_LIST_ENTRY_S* next; //Pointer to the next entry in the list or NULL
|
||||
typedef struct FILE_LIST_ENTRY_S {
|
||||
char* filename; //Name of the file
|
||||
struct FILE_LIST_ENTRY_S* next; //Pointer to the next entry in the list or NULL
|
||||
} FILE_LIST_ENTRY;
|
||||
|
||||
static FILE_LIST_ENTRY* files_ok; //Pointer to the head of the list
|
||||
|
||||
//Callback for when the user selects a file to save the image into
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction) {
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
|
||||
int y = touch_get_last_point().y-liststart; //Calculate the y-Coordinate of the touch point relative to the start of the file-list
|
||||
int elem = y/fontheight; //Calculate the file index
|
||||
if(elem<0 | elem>= num_files_ok) return; //Check if the file index is valid (0,1,..,num_files_ok-1)
|
||||
int y = touch_get_last_point().y - liststart; //Calculate the y-Coordinate of the touch point relative to the start of the file-list
|
||||
int elem = y / fontheight; //Calculate the file index
|
||||
|
||||
//Search for the corresponding entry in the linked list
|
||||
FILE_LIST_ENTRY* current_entry = files_ok; //Start walking through the list, starting by the head of the list
|
||||
for(int i=0; i<elem; i++) { //Until we have reached the file (index)
|
||||
current_entry= current_entry->next; //traverse to the next file
|
||||
}
|
||||
if (elem < 0 | elem >= num_files_ok) {
|
||||
return; //Check if the file index is valid (0,1,..,num_files_ok-1)
|
||||
}
|
||||
|
||||
picked_file = current_entry->filename; //save the picked filename. It will be used by the statemachine in the main loop
|
||||
touch_unregister_area(&a_area); //unregister the touch area, we no longer need it. No more interrupts will be fired.
|
||||
state=saving; //Change the state of the statemachine
|
||||
//Search for the corresponding entry in the linked list
|
||||
FILE_LIST_ENTRY* current_entry = files_ok; //Start walking through the list, starting by the head of the list
|
||||
|
||||
for (int i = 0; i < elem; i++) { //Until we have reached the file (index)
|
||||
current_entry = current_entry->next; //traverse to the next file
|
||||
}
|
||||
|
||||
picked_file = current_entry->filename; //save the picked filename. It will be used by the statemachine in the main loop
|
||||
touch_unregister_area(&a_area); //unregister the touch area, we no longer need it. No more interrupts will be fired.
|
||||
state = saving; //Change the state of the statemachine
|
||||
}
|
||||
|
||||
//Text-Lines to show if we have no matching files (num_files_ok==0)
|
||||
static const char* nomatch_text [] = {
|
||||
"Due to limitations of the filesystem",
|
||||
"implementation you can only write to",
|
||||
"existing files.",
|
||||
"",
|
||||
"The files need to have a .bmp",
|
||||
"extension and must be at least",
|
||||
"189410 bytes (185kb) large.",
|
||||
"Unfortunately there were no such",
|
||||
"files found in the root directory.",
|
||||
"",
|
||||
"Please create some files and come",
|
||||
"back again.",
|
||||
NULL
|
||||
"Due to limitations of the filesystem",
|
||||
"implementation you can only write to",
|
||||
"existing files.",
|
||||
"",
|
||||
"The files need to have a .bmp",
|
||||
"extension and must be at least",
|
||||
"189410 bytes (185kb) large.",
|
||||
"Unfortunately there were no such",
|
||||
"files found in the root directory.",
|
||||
"",
|
||||
"Please create some files and come",
|
||||
"back again.",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -71,231 +91,251 @@ static const char* nomatch_text [] = {
|
||||
//This header has been taken from a white bitmap saved with gimp.
|
||||
//Wikipedia has a pretty good description on the header: http://de.wikipedia.org/wiki/Windows_Bitmap
|
||||
static unsigned char bmpheader_data[0x7A] = {
|
||||
0x42, 0x4d, 0xe2, 0xe3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00,
|
||||
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0xc6, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xe3,
|
||||
0x02, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
0x42, 0x4d, 0xe2, 0xe3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00,
|
||||
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0xc6, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xe3,
|
||||
0x02, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
//Callback for when the screen is entered/loaded
|
||||
static void enter(void* screen) {
|
||||
tft_clear(WHITE);
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(WHITE);
|
||||
|
||||
|
||||
#define X_OFS 5
|
||||
#define X_OFS 5
|
||||
|
||||
//Back button
|
||||
b_back.base.x1=X_OFS; //Start X of Button
|
||||
b_back.base.y1=210; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
//Back button
|
||||
b_back.base.x1 = X_OFS; //Start X of Button
|
||||
b_back.base.y1 = 210; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
state =init; //Start with the init state
|
||||
fontheight = tft_font_height(0)+2; //Save the height of the used font, for fast access
|
||||
files_ok = NULL; //initialize the linked list with 0 elements
|
||||
num_files_ok = 0; //we have zero! elements
|
||||
state = init; //Start with the init state
|
||||
fontheight = tft_font_height(0) + 2; //Save the height of the used font, for fast access
|
||||
files_ok = NULL; //initialize the linked list with 0 elements
|
||||
num_files_ok = 0; //we have zero! elements
|
||||
}
|
||||
|
||||
//Callback for when the screen should be updated
|
||||
//This is the main loop of the screen. This method will be called repeatedly
|
||||
static void update(void* screen) {
|
||||
switch(state) {
|
||||
case init: //Init State: The user just entered the screen
|
||||
{
|
||||
DIRECTORY_STRUCT* dir = filesystem_dir_open("."); //open root directory
|
||||
if(dir==NULL) { //error while opening root directory
|
||||
tft_print_line(X_OFS,5,BLACK,TRANSPARENT,0,"Error accessing Filesystem");
|
||||
state=error;
|
||||
break;
|
||||
}
|
||||
static void update(void* screen)
|
||||
{
|
||||
switch (state) {
|
||||
case init: { //Init State: The user just entered the screen
|
||||
DIRECTORY_STRUCT* dir = filesystem_dir_open("."); //open root directory
|
||||
|
||||
bool nomatch= true; //whether or not we have zero files which are suitable for saving
|
||||
if (dir == NULL) { //error while opening root directory
|
||||
tft_print_line(X_OFS, 5, BLACK, TRANSPARENT, 0, "Error accessing Filesystem");
|
||||
state = error;
|
||||
break;
|
||||
}
|
||||
|
||||
for(int i=0; i<dir->num_files; i++) { //walk through all files in the directory
|
||||
FILE_STRUCT* file = &(dir->files[i]); //Pointer to the current file/subdirectory
|
||||
bool nomatch = true; //whether or not we have zero files which are suitable for saving
|
||||
|
||||
//Ignore directories, archives, hidden files, system files and files we cannot write to
|
||||
if(file->fattrib&(F_SYS|F_HID|F_ARC|F_DIR|F_RDO)) continue;
|
||||
for (int i = 0; i < dir->num_files; i++) { //walk through all files in the directory
|
||||
FILE_STRUCT* file = &(dir->files[i]); //Pointer to the current file/subdirectory
|
||||
|
||||
//ignore files which are not large enough
|
||||
if(file->fsize<189410) continue; //size taken from an example bitmap (318x198x24)
|
||||
//Ignore directories, archives, hidden files, system files and files we cannot write to
|
||||
if (file->fattrib & (F_SYS | F_HID | F_ARC | F_DIR | F_RDO)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nomatch=false; //at least one file matches
|
||||
break;
|
||||
}
|
||||
//ignore files which are not large enough
|
||||
if (file->fsize < 189410) {
|
||||
continue; //size taken from an example bitmap (318x198x24)
|
||||
}
|
||||
|
||||
if(nomatch) { //not one file is suitable for writing
|
||||
int y=5; //y-Coordinate where to start writing the error text
|
||||
int i=0;
|
||||
while(nomatch_text[i]!=NULL) { //for every line in the big error array
|
||||
//Write the line's text and go to the next line
|
||||
tft_print_line(X_OFS,y+i*fontheight,BLACK,TRANSPARENT,0,nomatch_text[i]);
|
||||
i++;
|
||||
}
|
||||
state = error;
|
||||
} else { //we have a least one suitable file
|
||||
state = showlist;
|
||||
}
|
||||
nomatch = false; //at least one file matches
|
||||
break;
|
||||
}
|
||||
|
||||
filesystem_dir_close(dir); //free directory struct
|
||||
}
|
||||
break;
|
||||
if (nomatch) { //not one file is suitable for writing
|
||||
int y = 5; //y-Coordinate where to start writing the error text
|
||||
int i = 0;
|
||||
|
||||
case showlist: //Show List State: Where we load and present the suitable file's to the user in a list
|
||||
{
|
||||
DIRECTORY_STRUCT* dir2 = filesystem_dir_open("."); //Open the directory again
|
||||
if(dir2==NULL) return; //Error on opening? This should never happen, since it's handled in the previous state
|
||||
while (nomatch_text[i] != NULL) { //for every line in the big error array
|
||||
//Write the line's text and go to the next line
|
||||
tft_print_line(X_OFS, y + i * fontheight, BLACK, TRANSPARENT, 0, nomatch_text[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
int y = 5; //y-Coordinate where to start drawing/writing text/list-elements
|
||||
state = error;
|
||||
} else { //we have a least one suitable file
|
||||
state = showlist;
|
||||
}
|
||||
|
||||
tft_print_line(X_OFS,y,BLACK,TRANSPARENT,0,"Pick a file to save the image to");
|
||||
y+=fontheight+5;
|
||||
filesystem_dir_close(dir); //free directory struct
|
||||
}
|
||||
break;
|
||||
|
||||
tft_print_line(X_OFS,y,BLUE,TRANSPARENT,0,"Name Modified Size");
|
||||
y+=fontheight;
|
||||
case showlist: { //Show List State: Where we load and present the suitable file's to the user in a list
|
||||
DIRECTORY_STRUCT* dir2 = filesystem_dir_open("."); //Open the directory again
|
||||
|
||||
liststart = y; //store the y coordinate of the start of the list away (used in toucharea callback)
|
||||
num_files_ok = 0; //we start with 0 matching files
|
||||
if (dir2 == NULL) {
|
||||
return; //Error on opening? This should never happen, since it's handled in the previous state
|
||||
}
|
||||
|
||||
FILE_LIST_ENTRY* current_entry = NULL; //We start with an empty list
|
||||
for(int i=0; i<dir2->num_files && num_files_ok<10; i++) { //go through all the files of the directory, abort if we have 10 matches
|
||||
FILE_STRUCT* file = &(dir2->files[i]);
|
||||
int y = 5; //y-Coordinate where to start drawing/writing text/list-elements
|
||||
|
||||
//Ignore directories, archives, hidden files, system files and files we cannot write to
|
||||
if(file->fattrib&(F_SYS|F_HID|F_ARC|F_DIR|F_RDO)) continue;
|
||||
tft_print_line(X_OFS, y, BLACK, TRANSPARENT, 0, "Pick a file to save the image to");
|
||||
y += fontheight + 5;
|
||||
|
||||
//ignore files which are not large enough
|
||||
if(file->fsize<189410) continue; //size taken from an example bitmap (318x198x24)
|
||||
tft_print_line(X_OFS, y, BLUE, TRANSPARENT, 0, "Name Modified Size");
|
||||
y += fontheight;
|
||||
|
||||
//Print out filename, modified date,time and file size
|
||||
tft_print_formatted(X_OFS,y,BLACK,
|
||||
TRANSPARENT,0,"%-16s %02u.%02u.%02u %02u:%02u:%02u %u",
|
||||
file->fname,
|
||||
file->fdate.day,
|
||||
file->fdate.month,
|
||||
(file->fdate.year+1980)%100,
|
||||
file->ftime.hour,
|
||||
file->ftime.min,
|
||||
file->ftime.sec*2,
|
||||
file->fsize);
|
||||
liststart = y; //store the y coordinate of the start of the list away (used in toucharea callback)
|
||||
num_files_ok = 0; //we start with 0 matching files
|
||||
|
||||
if(current_entry==NULL) { //The list is empty
|
||||
current_entry = malloc(sizeof(FILE_LIST_ENTRY)); //create new entry
|
||||
files_ok = current_entry; //assign it to the list head
|
||||
} else { //there's a least one entry in the list
|
||||
current_entry->next = malloc(sizeof(FILE_LIST_ENTRY)); //append entry to previous entry
|
||||
current_entry = current_entry->next; //newly created entry is the current now.
|
||||
}
|
||||
current_entry->next = NULL; //we're at the end of the list (for now)
|
||||
current_entry->filename = malloc(strlen(file->fname)+1); //allocate space for the filename + zero-termination
|
||||
strcpy(current_entry->filename,file->fname); //copy filename (so that we can close the directory after scanning)
|
||||
FILE_LIST_ENTRY* current_entry = NULL; //We start with an empty list
|
||||
|
||||
//since we have found a suitable file we need to increment the position in the list
|
||||
num_files_ok++;
|
||||
y+=fontheight;
|
||||
}
|
||||
for (int i = 0; i < dir2->num_files && num_files_ok < 10; i++) { //go through all the files of the directory, abort if we have 10 matches
|
||||
FILE_STRUCT* file = &(dir2->files[i]);
|
||||
|
||||
//Touch area for file-selection (in the list)
|
||||
a_area.hookedActions = PEN_UP; //we're only interested in PEN_UP events
|
||||
a_area.x1 = X_OFS; //Left border
|
||||
a_area.y1 = liststart; //Start where the list started
|
||||
a_area.x2 = 320-X_OFS; //Right border
|
||||
a_area.y2 = liststart+fontheight*num_files_ok; //stop at the end of the list
|
||||
a_area.callback = touchCB; //execute our callback when PEN_UP occurs
|
||||
touch_register_area(&a_area); //register the touch area and receive events from now on
|
||||
//Ignore directories, archives, hidden files, system files and files we cannot write to
|
||||
if (file->fattrib & (F_SYS | F_HID | F_ARC | F_DIR | F_RDO)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filesystem_dir_close(dir2); //we no longer need the directory struct, since we have our own linked list now
|
||||
//ignore files which are not large enough
|
||||
if (file->fsize < 189410) {
|
||||
continue; //size taken from an example bitmap (318x198x24)
|
||||
}
|
||||
|
||||
state=picking;
|
||||
}
|
||||
break;
|
||||
//Print out filename, modified date,time and file size
|
||||
tft_print_formatted(X_OFS, y, BLACK,
|
||||
TRANSPARENT, 0, "%-16s %02u.%02u.%02u %02u:%02u:%02u %u",
|
||||
file->fname,
|
||||
file->fdate.day,
|
||||
file->fdate.month,
|
||||
(file->fdate.year + 1980) % 100,
|
||||
file->ftime.hour,
|
||||
file->ftime.min,
|
||||
file->ftime.sec * 2,
|
||||
file->fsize);
|
||||
|
||||
case picking: //Picking State: Where we wait on the users file choice
|
||||
pixy_service(); //Handle pending pixy events
|
||||
//do nothing and wait on user to pick a file
|
||||
break;
|
||||
if (current_entry == NULL) { //The list is empty
|
||||
current_entry = malloc(sizeof(FILE_LIST_ENTRY)); //create new entry
|
||||
files_ok = current_entry; //assign it to the list head
|
||||
} else { //there's a least one entry in the list
|
||||
current_entry->next = malloc(sizeof(FILE_LIST_ENTRY)); //append entry to previous entry
|
||||
current_entry = current_entry->next; //newly created entry is the current now.
|
||||
}
|
||||
|
||||
case saving: //Saving State: Where we save the image to the selected file
|
||||
{
|
||||
FILE_HANDLE* file = filesystem_file_open(picked_file); //try to open the selected file
|
||||
if(file==NULL) { //opening the file failed
|
||||
tft_print_formatted(X_OFS,190,BLUE,TRANSPARENT,0,"Could not open %s",picked_file);
|
||||
state=error;
|
||||
break;
|
||||
}
|
||||
current_entry->next = NULL; //we're at the end of the list (for now)
|
||||
current_entry->filename = malloc(strlen(file->fname) + 1); //allocate space for the filename + zero-termination
|
||||
strcpy(current_entry->filename, file->fname); //copy filename (so that we can close the directory after scanning)
|
||||
|
||||
filesystem_file_seek(file,0); //seek to the start of the file (optional?)
|
||||
if(filesystem_file_write(file,bmpheader_data,0x7A)!=F_OK) { //Writing the header failed
|
||||
tft_print_formatted(X_OFS,190,BLUE,TRANSPARENT,0,"Error while writing to %s",picked_file);
|
||||
filesystem_file_close(file);
|
||||
state=error;
|
||||
break;
|
||||
}
|
||||
//since we have found a suitable file we need to increment the position in the list
|
||||
num_files_ok++;
|
||||
y += fontheight;
|
||||
}
|
||||
|
||||
if(pixy_save_full_frame(file)!=0) { //Writing the imagedata failed
|
||||
tft_print_formatted(X_OFS,190,BLUE,TRANSPARENT,0,"Error while writing to %s",picked_file);
|
||||
filesystem_file_close(file);
|
||||
state=error;
|
||||
break;
|
||||
}
|
||||
//Touch area for file-selection (in the list)
|
||||
a_area.hookedActions = PEN_UP; //we're only interested in PEN_UP events
|
||||
a_area.x1 = X_OFS; //Left border
|
||||
a_area.y1 = liststart; //Start where the list started
|
||||
a_area.x2 = 320 - X_OFS; //Right border
|
||||
a_area.y2 = liststart + fontheight * num_files_ok; //stop at the end of the list
|
||||
a_area.callback = touchCB; //execute our callback when PEN_UP occurs
|
||||
touch_register_area(&a_area); //register the touch area and receive events from now on
|
||||
|
||||
//if we reach this point, we have written all data out successfully
|
||||
filesystem_dir_close(dir2); //we no longer need the directory struct, since we have our own linked list now
|
||||
|
||||
filesystem_file_close(file); //close/finalize the file
|
||||
tft_print_formatted(X_OFS,190,BLUE,TRANSPARENT,0,"Image saved to %s",picked_file);
|
||||
state = done;
|
||||
}
|
||||
break;
|
||||
state = picking;
|
||||
}
|
||||
break;
|
||||
|
||||
case error: //Error State: Where we show an error message and leave the user no other choice than to click the backbutton
|
||||
case done: //Done State: When saving the file was successful
|
||||
pixy_service(); //Handle pending pixy events
|
||||
//wait on user to click the back button
|
||||
break;
|
||||
case picking: //Picking State: Where we wait on the users file choice
|
||||
pixy_service(); //Handle pending pixy events
|
||||
//do nothing and wait on user to pick a file
|
||||
break;
|
||||
|
||||
}
|
||||
case saving: { //Saving State: Where we save the image to the selected file
|
||||
FILE_HANDLE* file = filesystem_file_open(picked_file); //try to open the selected file
|
||||
|
||||
if (file == NULL) { //opening the file failed
|
||||
tft_print_formatted(X_OFS, 190, BLUE, TRANSPARENT, 0, "Could not open %s", picked_file);
|
||||
state = error;
|
||||
break;
|
||||
}
|
||||
|
||||
filesystem_file_seek(file, 0); //seek to the start of the file (optional?)
|
||||
|
||||
if (filesystem_file_write(file, bmpheader_data, 0x7A) != F_OK) { //Writing the header failed
|
||||
tft_print_formatted(X_OFS, 190, BLUE, TRANSPARENT, 0, "Error while writing to %s", picked_file);
|
||||
filesystem_file_close(file);
|
||||
state = error;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pixy_save_full_frame(file) != 0) { //Writing the imagedata failed
|
||||
tft_print_formatted(X_OFS, 190, BLUE, TRANSPARENT, 0, "Error while writing to %s", picked_file);
|
||||
filesystem_file_close(file);
|
||||
state = error;
|
||||
break;
|
||||
}
|
||||
|
||||
//if we reach this point, we have written all data out successfully
|
||||
|
||||
filesystem_file_close(file); //close/finalize the file
|
||||
tft_print_formatted(X_OFS, 190, BLUE, TRANSPARENT, 0, "Image saved to %s", picked_file);
|
||||
state = done;
|
||||
}
|
||||
break;
|
||||
|
||||
case error: //Error State: Where we show an error message and leave the user no other choice than to click the backbutton
|
||||
case done: //Done State: When saving the file was successful
|
||||
pixy_service(); //Handle pending pixy events
|
||||
//wait on user to click the back button
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Callback for when the screen is left/unloaded
|
||||
static void leave(void* screen) {
|
||||
gui_button_remove(&b_back); //Remove/Free the back button
|
||||
static void leave(void* screen)
|
||||
{
|
||||
gui_button_remove(&b_back); //Remove/Free the back button
|
||||
|
||||
if(state==picking){ //The user left the screen in the "picking"-phase
|
||||
touch_unregister_area(&a_area); //remove the touch area (for the list)
|
||||
}
|
||||
if (state == picking) { //The user left the screen in the "picking"-phase
|
||||
touch_unregister_area(&a_area); //remove the touch area (for the list)
|
||||
}
|
||||
|
||||
if(state==picking|| state==saving || state==done) { //the user left the screen after we created the linked list
|
||||
//Iterate through the linked list and free all resources
|
||||
FILE_LIST_ENTRY* current_entry = files_ok; //start with the list head
|
||||
while(current_entry!=NULL) { //while we're not at the end
|
||||
FILE_LIST_ENTRY* temp = current_entry->next; //save the next pointer because we free the current element on the next line
|
||||
free((void*)(current_entry->filename)); //free filename
|
||||
free(current_entry); //free element itself
|
||||
current_entry= temp; //advance
|
||||
}
|
||||
}
|
||||
if (state == picking || state == saving || state == done) { //the user left the screen after we created the linked list
|
||||
//Iterate through the linked list and free all resources
|
||||
FILE_LIST_ENTRY* current_entry = files_ok; //start with the list head
|
||||
|
||||
while (current_entry != NULL) { //while we're not at the end
|
||||
FILE_LIST_ENTRY* temp = current_entry->next; //save the next pointer because we free the current element on the next line
|
||||
free((void*)(current_entry->filename)); //free filename
|
||||
free(current_entry); //free element itself
|
||||
current_entry = temp; //advance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Declare screen callbacks
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
SCREEN_STRUCT* get_screen_photomodesave() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_photomodesave()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_photomode_save.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-16 timolang@gmail.com 62006e0 Documented pixy_helper and implemented/finished photo-mode screens! Snap some shots!
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
@@ -20,4 +33,3 @@ SCREEN_STRUCT* get_screen_photomodesave();
|
||||
|
||||
/*@}*/
|
||||
/*@}*/
|
||||
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_pixytest.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-02 timolang@gmail.com 3281616 Added some more touch functions. Improved pixy test. Drag the Image around!
|
||||
* 2015-05-09 timolang@gmail.com 0b5173e Added reference tracking.
|
||||
* 2015-05-15 timolang@gmail.com 27c09ba Redesigned main menu. Moved stuff from pixytest to a new helper file and to the new "photo mode"-screen.
|
||||
* 2015-05-25 timolang@gmail.com 6a61769 Reimplemented pixytest screen. Added a lot of Test-Buttons.
|
||||
* 2015-06-01 aaron@duckpond.ch caa7b5c Added IRQ for user button, fixed some touchproblems.
|
||||
* 2015-06-03 timolang@gmail.com 74aa186 Made pixy_test screen working again. Had to disable pixy_service. Recalibrated initial touch values.
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_pixytest.h"
|
||||
#include "button.h"
|
||||
#include "numupdown.h"
|
||||
@@ -7,7 +27,7 @@
|
||||
#include "system.h"
|
||||
#include "pixy_frame.h"
|
||||
|
||||
static volatile enum {detecting, idle,update_servos, update_ledcolor, update_ledcurrent} state; //Current state of the screen state machine
|
||||
static volatile enum {detecting, idle, update_servos, update_ledcolor, update_ledcurrent} state; //Current state of the screen state machine
|
||||
|
||||
static BUTTON_STRUCT b_back;
|
||||
|
||||
@@ -30,313 +50,328 @@ static uint32_t led_maxcurrent;
|
||||
static NUMUPDOWN_STRUCT n_led_powerlimit;
|
||||
|
||||
|
||||
static void b_back_cb(void* button) {
|
||||
gui_screen_back();
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
gui_screen_back();
|
||||
}
|
||||
|
||||
static void b_servos_center_cb(void* button) {
|
||||
if(state==idle) {
|
||||
servo_x=500;
|
||||
servo_y=500;
|
||||
state=update_servos;
|
||||
}
|
||||
static void b_servos_center_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
servo_x = 500;
|
||||
servo_y = 500;
|
||||
state = update_servos;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_servos_topleft_cb(void* button) {
|
||||
if(state==idle) {
|
||||
servo_x=0;
|
||||
servo_y=0;
|
||||
state=update_servos;
|
||||
}
|
||||
static void b_servos_topleft_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
servo_x = 0;
|
||||
servo_y = 0;
|
||||
state = update_servos;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_servos_topright_cb(void* button) {
|
||||
if(state==idle) {
|
||||
servo_x=1000;
|
||||
servo_y=0;
|
||||
state=update_servos;
|
||||
}
|
||||
static void b_servos_topright_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
servo_x = 1000;
|
||||
servo_y = 0;
|
||||
state = update_servos;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_servos_bottomleft_cb(void* button) {
|
||||
if(state==idle) {
|
||||
servo_x=0;
|
||||
servo_y=1000;
|
||||
state=update_servos;
|
||||
}
|
||||
static void b_servos_bottomleft_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
servo_x = 0;
|
||||
servo_y = 1000;
|
||||
state = update_servos;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_servos_bottomright_cb(void* button) {
|
||||
if(state==idle) {
|
||||
servo_x=1000;
|
||||
servo_y=1000;
|
||||
state=update_servos;
|
||||
}
|
||||
static void b_servos_bottomright_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
servo_x = 1000;
|
||||
servo_y = 1000;
|
||||
state = update_servos;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_led_off_cb(void* button) {
|
||||
if(state==idle) {
|
||||
led_color=0x000000;
|
||||
state=update_ledcolor;
|
||||
}
|
||||
static void b_led_off_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_color = 0x000000;
|
||||
state = update_ledcolor;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_led_white_cb(void* button) {
|
||||
if(state==idle) {
|
||||
led_color=0xFFFFFF;
|
||||
state=update_ledcolor;
|
||||
}
|
||||
static void b_led_white_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_color = 0xFFFFFF;
|
||||
state = update_ledcolor;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_led_red_cb(void* button) {
|
||||
if(state==idle) {
|
||||
led_color=0xFF0000;
|
||||
state=update_ledcolor;
|
||||
}
|
||||
static void b_led_red_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_color = 0xFF0000;
|
||||
state = update_ledcolor;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_led_green_cb(void* button) {
|
||||
if(state==idle) {
|
||||
led_color=0x00FF00;
|
||||
state=update_ledcolor;
|
||||
}
|
||||
static void b_led_green_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_color = 0x00FF00;
|
||||
state = update_ledcolor;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_led_blue_cb(void* button) {
|
||||
if(state==idle) {
|
||||
led_color=0x0000FF;
|
||||
state=update_ledcolor;
|
||||
}
|
||||
static void b_led_blue_cb(void* button)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_color = 0x0000FF;
|
||||
state = update_ledcolor;
|
||||
}
|
||||
}
|
||||
|
||||
static void n_led_powerlimit_cb(void* numupdown, int16_t value) {
|
||||
if(state==idle) {
|
||||
led_maxcurrent=value;
|
||||
state=update_ledcurrent;
|
||||
}
|
||||
static void n_led_powerlimit_cb(void* numupdown, int16_t value)
|
||||
{
|
||||
if (state == idle) {
|
||||
led_maxcurrent = value;
|
||||
state = update_ledcurrent;
|
||||
}
|
||||
}
|
||||
|
||||
static void enter(void* screen) {
|
||||
tft_clear(WHITE);
|
||||
|
||||
//Back button
|
||||
b_back.base.x1=10; //Start X of Button
|
||||
b_back.base.y1=210; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(WHITE);
|
||||
|
||||
//Back button
|
||||
b_back.base.x1 = 10; //Start X of Button
|
||||
b_back.base.y1 = 210; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
|
||||
//Servo stuff
|
||||
#define SERVO_BUTTON_Y 10
|
||||
#define SERVO_BUTTON_SPACING 5
|
||||
tft_print_line(5,SERVO_BUTTON_Y,BLACK,TRANSPARENT,0,"Servos:");
|
||||
//Servo stuff
|
||||
#define SERVO_BUTTON_Y 10
|
||||
#define SERVO_BUTTON_SPACING 5
|
||||
tft_print_line(5, SERVO_BUTTON_Y, BLACK, TRANSPARENT, 0, "Servos:");
|
||||
|
||||
b_servos_center.base.x1=55;
|
||||
b_servos_center.base.y1=SERVO_BUTTON_Y-3;
|
||||
b_servos_center.base.x2=AUTO;
|
||||
b_servos_center.base.y2=AUTO;
|
||||
b_servos_center.txtcolor=WHITE;
|
||||
b_servos_center.bgcolor=HEX(0xAE1010);
|
||||
b_servos_center.font=0;
|
||||
b_servos_center.text="Center";
|
||||
b_servos_center.callback=b_servos_center_cb;
|
||||
gui_button_add(&b_servos_center);
|
||||
b_servos_center.base.x1 = 55;
|
||||
b_servos_center.base.y1 = SERVO_BUTTON_Y - 3;
|
||||
b_servos_center.base.x2 = AUTO;
|
||||
b_servos_center.base.y2 = AUTO;
|
||||
b_servos_center.txtcolor = WHITE;
|
||||
b_servos_center.bgcolor = HEX(0xAE1010);
|
||||
b_servos_center.font = 0;
|
||||
b_servos_center.text = "Center";
|
||||
b_servos_center.callback = b_servos_center_cb;
|
||||
gui_button_add(&b_servos_center);
|
||||
|
||||
b_servos_topleft.base.x1=b_servos_center.base.x2+SERVO_BUTTON_SPACING;
|
||||
b_servos_topleft.base.y1=SERVO_BUTTON_Y-3;
|
||||
b_servos_topleft.base.x2=AUTO;
|
||||
b_servos_topleft.base.y2=AUTO;
|
||||
b_servos_topleft.txtcolor=WHITE;
|
||||
b_servos_topleft.bgcolor=HEX(0xAE1010);
|
||||
b_servos_topleft.font=0;
|
||||
b_servos_topleft.text="ToLe";
|
||||
b_servos_topleft.callback=b_servos_topleft_cb;
|
||||
gui_button_add(&b_servos_topleft);
|
||||
b_servos_topleft.base.x1 = b_servos_center.base.x2 + SERVO_BUTTON_SPACING;
|
||||
b_servos_topleft.base.y1 = SERVO_BUTTON_Y - 3;
|
||||
b_servos_topleft.base.x2 = AUTO;
|
||||
b_servos_topleft.base.y2 = AUTO;
|
||||
b_servos_topleft.txtcolor = WHITE;
|
||||
b_servos_topleft.bgcolor = HEX(0xAE1010);
|
||||
b_servos_topleft.font = 0;
|
||||
b_servos_topleft.text = "ToLe";
|
||||
b_servos_topleft.callback = b_servos_topleft_cb;
|
||||
gui_button_add(&b_servos_topleft);
|
||||
|
||||
b_servos_topright.base.x1=b_servos_topleft.base.x2+SERVO_BUTTON_SPACING;
|
||||
b_servos_topright.base.y1=SERVO_BUTTON_Y-3;
|
||||
b_servos_topright.base.x2=AUTO;
|
||||
b_servos_topright.base.y2=AUTO;
|
||||
b_servos_topright.txtcolor=WHITE;
|
||||
b_servos_topright.bgcolor=HEX(0xAE1010);
|
||||
b_servos_topright.font=0;
|
||||
b_servos_topright.text="ToRi";
|
||||
b_servos_topright.callback=b_servos_topright_cb;
|
||||
gui_button_add(&b_servos_topright);
|
||||
b_servos_topright.base.x1 = b_servos_topleft.base.x2 + SERVO_BUTTON_SPACING;
|
||||
b_servos_topright.base.y1 = SERVO_BUTTON_Y - 3;
|
||||
b_servos_topright.base.x2 = AUTO;
|
||||
b_servos_topright.base.y2 = AUTO;
|
||||
b_servos_topright.txtcolor = WHITE;
|
||||
b_servos_topright.bgcolor = HEX(0xAE1010);
|
||||
b_servos_topright.font = 0;
|
||||
b_servos_topright.text = "ToRi";
|
||||
b_servos_topright.callback = b_servos_topright_cb;
|
||||
gui_button_add(&b_servos_topright);
|
||||
|
||||
b_servos_bottomleft.base.x1=b_servos_topright.base.x2+SERVO_BUTTON_SPACING;
|
||||
b_servos_bottomleft.base.y1=SERVO_BUTTON_Y-3;
|
||||
b_servos_bottomleft.base.x2=AUTO;
|
||||
b_servos_bottomleft.base.y2=AUTO;
|
||||
b_servos_bottomleft.txtcolor=WHITE;
|
||||
b_servos_bottomleft.bgcolor=HEX(0xAE1010);
|
||||
b_servos_bottomleft.font=0;
|
||||
b_servos_bottomleft.text="BoLe";
|
||||
b_servos_bottomleft.callback=b_servos_bottomleft_cb;
|
||||
gui_button_add(&b_servos_bottomleft);
|
||||
b_servos_bottomleft.base.x1 = b_servos_topright.base.x2 + SERVO_BUTTON_SPACING;
|
||||
b_servos_bottomleft.base.y1 = SERVO_BUTTON_Y - 3;
|
||||
b_servos_bottomleft.base.x2 = AUTO;
|
||||
b_servos_bottomleft.base.y2 = AUTO;
|
||||
b_servos_bottomleft.txtcolor = WHITE;
|
||||
b_servos_bottomleft.bgcolor = HEX(0xAE1010);
|
||||
b_servos_bottomleft.font = 0;
|
||||
b_servos_bottomleft.text = "BoLe";
|
||||
b_servos_bottomleft.callback = b_servos_bottomleft_cb;
|
||||
gui_button_add(&b_servos_bottomleft);
|
||||
|
||||
b_servos_bottomright.base.x1=b_servos_bottomleft.base.x2+SERVO_BUTTON_SPACING;
|
||||
b_servos_bottomright.base.y1=SERVO_BUTTON_Y-3;
|
||||
b_servos_bottomright.base.x2=AUTO;
|
||||
b_servos_bottomright.base.y2=AUTO;
|
||||
b_servos_bottomright.txtcolor=WHITE;
|
||||
b_servos_bottomright.bgcolor=HEX(0xAE1010);
|
||||
b_servos_bottomright.font=0;
|
||||
b_servos_bottomright.text="BoRi";
|
||||
b_servos_bottomright.callback=b_servos_bottomright_cb;
|
||||
gui_button_add(&b_servos_bottomright);
|
||||
b_servos_bottomright.base.x1 = b_servos_bottomleft.base.x2 + SERVO_BUTTON_SPACING;
|
||||
b_servos_bottomright.base.y1 = SERVO_BUTTON_Y - 3;
|
||||
b_servos_bottomright.base.x2 = AUTO;
|
||||
b_servos_bottomright.base.y2 = AUTO;
|
||||
b_servos_bottomright.txtcolor = WHITE;
|
||||
b_servos_bottomright.bgcolor = HEX(0xAE1010);
|
||||
b_servos_bottomright.font = 0;
|
||||
b_servos_bottomright.text = "BoRi";
|
||||
b_servos_bottomright.callback = b_servos_bottomright_cb;
|
||||
gui_button_add(&b_servos_bottomright);
|
||||
|
||||
//Led Color stuff
|
||||
#define LED_COLOR_BUTTON_Y 35
|
||||
#define LED_COLOR_BUTTON_SPACING 5
|
||||
tft_print_line(5,LED_COLOR_BUTTON_Y,BLACK,TRANSPARENT,0,"Led Color:");
|
||||
//Led Color stuff
|
||||
#define LED_COLOR_BUTTON_Y 35
|
||||
#define LED_COLOR_BUTTON_SPACING 5
|
||||
tft_print_line(5, LED_COLOR_BUTTON_Y, BLACK, TRANSPARENT, 0, "Led Color:");
|
||||
|
||||
b_led_off.base.x1=85;
|
||||
b_led_off.base.y1=LED_COLOR_BUTTON_Y-3;
|
||||
b_led_off.base.x2=AUTO;
|
||||
b_led_off.base.y2=AUTO;
|
||||
b_led_off.txtcolor=WHITE;
|
||||
b_led_off.bgcolor=BLACK;
|
||||
b_led_off.font=0;
|
||||
b_led_off.text="Off";
|
||||
b_led_off.callback=b_led_off_cb;
|
||||
gui_button_add(&b_led_off);
|
||||
b_led_off.base.x1 = 85;
|
||||
b_led_off.base.y1 = LED_COLOR_BUTTON_Y - 3;
|
||||
b_led_off.base.x2 = AUTO;
|
||||
b_led_off.base.y2 = AUTO;
|
||||
b_led_off.txtcolor = WHITE;
|
||||
b_led_off.bgcolor = BLACK;
|
||||
b_led_off.font = 0;
|
||||
b_led_off.text = "Off";
|
||||
b_led_off.callback = b_led_off_cb;
|
||||
gui_button_add(&b_led_off);
|
||||
|
||||
b_led_white.base.x1=b_led_off.base.x2+LED_COLOR_BUTTON_SPACING;
|
||||
b_led_white.base.y1=LED_COLOR_BUTTON_Y-3;
|
||||
b_led_white.base.x2=AUTO;
|
||||
b_led_white.base.y2=AUTO;
|
||||
b_led_white.txtcolor=BLACK;
|
||||
b_led_white.bgcolor=HEX(0xEEEEEE);
|
||||
b_led_white.font=0;
|
||||
b_led_white.text="White";
|
||||
b_led_white.callback=b_led_white_cb;
|
||||
gui_button_add(&b_led_white);
|
||||
b_led_white.base.x1 = b_led_off.base.x2 + LED_COLOR_BUTTON_SPACING;
|
||||
b_led_white.base.y1 = LED_COLOR_BUTTON_Y - 3;
|
||||
b_led_white.base.x2 = AUTO;
|
||||
b_led_white.base.y2 = AUTO;
|
||||
b_led_white.txtcolor = BLACK;
|
||||
b_led_white.bgcolor = HEX(0xEEEEEE);
|
||||
b_led_white.font = 0;
|
||||
b_led_white.text = "White";
|
||||
b_led_white.callback = b_led_white_cb;
|
||||
gui_button_add(&b_led_white);
|
||||
|
||||
b_led_red.base.x1=b_led_white.base.x2+LED_COLOR_BUTTON_SPACING;
|
||||
b_led_red.base.y1=LED_COLOR_BUTTON_Y-3;
|
||||
b_led_red.base.x2=AUTO;
|
||||
b_led_red.base.y2=AUTO;
|
||||
b_led_red.txtcolor=WHITE;
|
||||
b_led_red.bgcolor=HEX(0xEE0000);
|
||||
b_led_red.font=0;
|
||||
b_led_red.text="Red";
|
||||
b_led_red.callback=b_led_red_cb;
|
||||
gui_button_add(&b_led_red);
|
||||
b_led_red.base.x1 = b_led_white.base.x2 + LED_COLOR_BUTTON_SPACING;
|
||||
b_led_red.base.y1 = LED_COLOR_BUTTON_Y - 3;
|
||||
b_led_red.base.x2 = AUTO;
|
||||
b_led_red.base.y2 = AUTO;
|
||||
b_led_red.txtcolor = WHITE;
|
||||
b_led_red.bgcolor = HEX(0xEE0000);
|
||||
b_led_red.font = 0;
|
||||
b_led_red.text = "Red";
|
||||
b_led_red.callback = b_led_red_cb;
|
||||
gui_button_add(&b_led_red);
|
||||
|
||||
b_led_green.base.x1=b_led_red.base.x2+LED_COLOR_BUTTON_SPACING;
|
||||
b_led_green.base.y1=LED_COLOR_BUTTON_Y-3;
|
||||
b_led_green.base.x2=AUTO;
|
||||
b_led_green.base.y2=AUTO;
|
||||
b_led_green.txtcolor=WHITE;
|
||||
b_led_green.bgcolor=HEX(0x00EE00);
|
||||
b_led_green.font=0;
|
||||
b_led_green.text="Green";
|
||||
b_led_green.callback=b_led_green_cb;
|
||||
gui_button_add(&b_led_green);
|
||||
b_led_green.base.x1 = b_led_red.base.x2 + LED_COLOR_BUTTON_SPACING;
|
||||
b_led_green.base.y1 = LED_COLOR_BUTTON_Y - 3;
|
||||
b_led_green.base.x2 = AUTO;
|
||||
b_led_green.base.y2 = AUTO;
|
||||
b_led_green.txtcolor = WHITE;
|
||||
b_led_green.bgcolor = HEX(0x00EE00);
|
||||
b_led_green.font = 0;
|
||||
b_led_green.text = "Green";
|
||||
b_led_green.callback = b_led_green_cb;
|
||||
gui_button_add(&b_led_green);
|
||||
|
||||
b_led_blue.base.x1=b_led_green.base.x2+LED_COLOR_BUTTON_SPACING;
|
||||
b_led_blue.base.y1=LED_COLOR_BUTTON_Y-3;
|
||||
b_led_blue.base.x2=AUTO;
|
||||
b_led_blue.base.y2=AUTO;
|
||||
b_led_blue.txtcolor=WHITE;
|
||||
b_led_blue.bgcolor=HEX(0x0000EE);
|
||||
b_led_blue.font=0;
|
||||
b_led_blue.text="Blue";
|
||||
b_led_blue.callback=b_led_blue_cb;
|
||||
gui_button_add(&b_led_blue);
|
||||
b_led_blue.base.x1 = b_led_green.base.x2 + LED_COLOR_BUTTON_SPACING;
|
||||
b_led_blue.base.y1 = LED_COLOR_BUTTON_Y - 3;
|
||||
b_led_blue.base.x2 = AUTO;
|
||||
b_led_blue.base.y2 = AUTO;
|
||||
b_led_blue.txtcolor = WHITE;
|
||||
b_led_blue.bgcolor = HEX(0x0000EE);
|
||||
b_led_blue.font = 0;
|
||||
b_led_blue.text = "Blue";
|
||||
b_led_blue.callback = b_led_blue_cb;
|
||||
gui_button_add(&b_led_blue);
|
||||
|
||||
//Led MaxPower stuff
|
||||
#define LED_POWER_BUTTON_Y 70
|
||||
tft_print_line(5,LED_POWER_BUTTON_Y,BLACK,TRANSPARENT,0,"Led Maximum Current:");
|
||||
//Led MaxPower stuff
|
||||
#define LED_POWER_BUTTON_Y 70
|
||||
tft_print_line(5, LED_POWER_BUTTON_Y, BLACK, TRANSPARENT, 0, "Led Maximum Current:");
|
||||
|
||||
//Num up down test
|
||||
n_led_powerlimit.x=160;
|
||||
n_led_powerlimit.y=LED_POWER_BUTTON_Y-7;
|
||||
n_led_powerlimit.fgcolor=WHITE;
|
||||
n_led_powerlimit.value = 10;
|
||||
n_led_powerlimit.max=40;
|
||||
n_led_powerlimit.min =0;
|
||||
n_led_powerlimit.callback=n_led_powerlimit_cb;
|
||||
gui_numupdown_add(&n_led_powerlimit);
|
||||
//Num up down test
|
||||
n_led_powerlimit.x = 160;
|
||||
n_led_powerlimit.y = LED_POWER_BUTTON_Y - 7;
|
||||
n_led_powerlimit.fgcolor = WHITE;
|
||||
n_led_powerlimit.value = 10;
|
||||
n_led_powerlimit.max = 40;
|
||||
n_led_powerlimit.min = 0;
|
||||
n_led_powerlimit.callback = n_led_powerlimit_cb;
|
||||
gui_numupdown_add(&n_led_powerlimit);
|
||||
|
||||
|
||||
|
||||
state=detecting;
|
||||
state = detecting;
|
||||
}
|
||||
|
||||
static void leave(void* screen) {
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_servos_center);
|
||||
gui_button_remove(&b_servos_topleft);
|
||||
gui_button_remove(&b_servos_topright);
|
||||
gui_button_remove(&b_servos_bottomleft);
|
||||
gui_button_remove(&b_servos_bottomright);
|
||||
gui_button_remove(&b_led_off);
|
||||
gui_button_remove(&b_led_white);
|
||||
gui_button_remove(&b_led_red);
|
||||
gui_button_remove(&b_led_green);
|
||||
gui_button_remove(&b_led_blue);
|
||||
gui_numupdown_remove(&n_led_powerlimit);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_servos_center);
|
||||
gui_button_remove(&b_servos_topleft);
|
||||
gui_button_remove(&b_servos_topright);
|
||||
gui_button_remove(&b_servos_bottomleft);
|
||||
gui_button_remove(&b_servos_bottomright);
|
||||
gui_button_remove(&b_led_off);
|
||||
gui_button_remove(&b_led_white);
|
||||
gui_button_remove(&b_led_red);
|
||||
gui_button_remove(&b_led_green);
|
||||
gui_button_remove(&b_led_blue);
|
||||
gui_numupdown_remove(&n_led_powerlimit);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void update(void* screen) {
|
||||
switch(state) {
|
||||
case detecting: //Detecting State: Where we try to connect to the pixy
|
||||
if(pixy_init()==0) { //Pixy connection ok
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
pixy_led_set_max_current(10);
|
||||
static void update(void* screen)
|
||||
{
|
||||
switch (state) {
|
||||
case detecting: //Detecting State: Where we try to connect to the pixy
|
||||
if (pixy_init() == 0) { //Pixy connection ok
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
pixy_led_set_max_current(10);
|
||||
|
||||
state = idle; //Go to next state
|
||||
}
|
||||
break;
|
||||
case idle:
|
||||
pixy_service();
|
||||
break;
|
||||
case update_servos:
|
||||
pixy_rcs_set_position(0,servo_x);
|
||||
pixy_rcs_set_position(1,servo_y);
|
||||
state = idle;
|
||||
break;
|
||||
state = idle; //Go to next state
|
||||
}
|
||||
|
||||
case update_ledcolor:
|
||||
{
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("led_set", INT32(led_color), END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
state = idle;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case update_ledcurrent:
|
||||
pixy_led_set_max_current(led_maxcurrent);
|
||||
state = idle;
|
||||
break;
|
||||
}
|
||||
case idle:
|
||||
pixy_service();
|
||||
break;
|
||||
|
||||
case update_servos:
|
||||
pixy_rcs_set_position(0, servo_x);
|
||||
pixy_rcs_set_position(1, servo_y);
|
||||
state = idle;
|
||||
break;
|
||||
|
||||
case update_ledcolor: {
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("led_set", INT32(led_color), END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
state = idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case update_ledcurrent:
|
||||
pixy_led_set_max_current(led_maxcurrent);
|
||||
state = idle;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_pixytest() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_pixytest()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_pixytest.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_tracking.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-16 timolang@gmail.com e46314b Added Tracking Screen and implemented "Reference Tracking" and "Color Region Selection"
|
||||
* 2015-05-25 timolang@gmail.com 8088014 Updated Tracking Screen so that the implementations are separated into different method groups.
|
||||
* 2015-06-06 aaron@duckpond.ch 8c264c2 Comment refactoring, updated PID values
|
||||
* 2015-06-06 aaron@duckpond.ch a04cda9 Refactured comments and implemented a bugfix for the PID controller
|
||||
* 2015-06-07 aaron@duckpond.ch 802d3df Fixed pid controller and refactored code
|
||||
* 2015-06-07 aaron@duckpond.ch 3d98ca9 Minor changes
|
||||
* 2015-06-07 timolang@gmail.com c87220d Renamed pixy_helper to pixy_frame. Updated docu of appliaction. added doxygen comments to pixy_{frame,control}.h
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_tracking.h"
|
||||
#include "pixy_control.h"
|
||||
#include "button.h"
|
||||
@@ -14,14 +33,16 @@ static CHECKBOX_STRUCT c_frame_toggle; //Checkbox to toggle video data on/off
|
||||
static TOUCH_AREA_STRUCT a_area; //Touch area for the color region selection
|
||||
|
||||
//Callback for when the user presses the "back" button
|
||||
static void b_back_cb(void* button) {
|
||||
gui_screen_back(); //navigate back to the previous screen
|
||||
static void b_back_cb(void* button)
|
||||
{
|
||||
gui_screen_back(); //navigate back to the previous screen
|
||||
}
|
||||
|
||||
static volatile bool frame_visible = false; //Whether or not the video data should be displayed
|
||||
static void c_frame_toggle_cb(void *checkbox, bool checked) {
|
||||
frame_visible=checked; //Set the visibility of the frame to the checked state of the checkbox
|
||||
//Frame will be drawn in the main loop below
|
||||
static void c_frame_toggle_cb(void* checkbox, bool checked)
|
||||
{
|
||||
frame_visible = checked; //Set the visibility of the frame to the checked state of the checkbox
|
||||
//Frame will be drawn in the main loop below
|
||||
}
|
||||
|
||||
static enum {detecting, init, tracking, preselecting, abortselecting, selecting, selected, error} state; //Current state of the screen state machine
|
||||
@@ -31,12 +52,13 @@ static POINT_STRUCT point2; //End point of the rectangle selected by the user (c
|
||||
static bool point1_valid; //Whether or not we have a valid first point
|
||||
|
||||
//Callback for when the user presses the "select color" button
|
||||
static void b_select_cb(void* button) {
|
||||
if(state==selecting) { //we're currently selecting a color region
|
||||
state = abortselecting; //Abort selecting!!
|
||||
} else if (state==tracking) { //we're currently watching the tracking
|
||||
state = preselecting; //start selecting
|
||||
}
|
||||
static void b_select_cb(void* button)
|
||||
{
|
||||
if (state == selecting) { //we're currently selecting a color region
|
||||
state = abortselecting; //Abort selecting!!
|
||||
} else if (state == tracking) { //we're currently watching the tracking
|
||||
state = preselecting; //start selecting
|
||||
}
|
||||
}
|
||||
|
||||
//Video Region properties
|
||||
@@ -50,34 +72,38 @@ static void b_select_cb(void* button) {
|
||||
|
||||
//Callback for when the user touches the frame area to select a color region.
|
||||
//Note: It doesn't matter in which direction the user draws the rectangle, we'll normalize the coordinates later
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction) {
|
||||
POINT_STRUCT p = touch_get_last_point();
|
||||
switch(triggeredAction) {
|
||||
case PEN_DOWN: //The user just put down the pen
|
||||
point1.x = p.x-FRAME_START_X; //Calculate x-Coordinate relative to frame start
|
||||
point1.y = p.y-FRAME_START_Y; //Calculate y-Coordinate relative to frame start
|
||||
point1_valid= true; //The point1 is now valid
|
||||
break;
|
||||
case PEN_UP: //The user took the pen away
|
||||
if(point1_valid) { //only execute if point1 is valid
|
||||
point2.x = p.x-FRAME_START_X; //Calculate x-Coordinate relative to frame start
|
||||
point2.y = p.y-FRAME_START_Y; //Calculate y-Coordinate relative to frame start
|
||||
state = selected;
|
||||
}
|
||||
break;
|
||||
}
|
||||
static void touchCB(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
POINT_STRUCT p = touch_get_last_point();
|
||||
|
||||
switch (triggeredAction) {
|
||||
case PEN_DOWN: //The user just put down the pen
|
||||
point1.x = p.x - FRAME_START_X; //Calculate x-Coordinate relative to frame start
|
||||
point1.y = p.y - FRAME_START_Y; //Calculate y-Coordinate relative to frame start
|
||||
point1_valid = true; //The point1 is now valid
|
||||
break;
|
||||
|
||||
case PEN_UP: //The user took the pen away
|
||||
if (point1_valid) { //only execute if point1 is valid
|
||||
point2.x = p.x - FRAME_START_X; //Calculate x-Coordinate relative to frame start
|
||||
point2.y = p.y - FRAME_START_Y; //Calculate y-Coordinate relative to frame start
|
||||
state = selected;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Prototype for tracking start/stop methods
|
||||
typedef void (*TRACKING_VOID_CALLBACK)(void* tracking_config);
|
||||
//Prototype for tracking update method
|
||||
typedef void (*TRACKING_BLOCK_CALLBACK)(void* tracking_config, struct Block* blocks, int num_blocks );
|
||||
typedef void (*TRACKING_BLOCK_CALLBACK)(void* tracking_config, struct Block* blocks, int num_blocks);
|
||||
|
||||
//Structure to save callbacks and settings of a tracking implementation
|
||||
typedef struct {
|
||||
TRACKING_VOID_CALLBACK start;
|
||||
TRACKING_VOID_CALLBACK stop;
|
||||
TRACKING_BLOCK_CALLBACK update;
|
||||
TRACKING_VOID_CALLBACK start;
|
||||
TRACKING_VOID_CALLBACK stop;
|
||||
TRACKING_BLOCK_CALLBACK update;
|
||||
} TRACKING_CONFIG_STRUCT;
|
||||
|
||||
//Methods for our tracking implementation ahead
|
||||
@@ -85,45 +111,48 @@ 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;
|
||||
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(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);
|
||||
}
|
||||
|
||||
//Method/Callback to stop our tracking
|
||||
void tracking_our_stop(void* tracking_config) {
|
||||
//Stop pixy's data send programm
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
void tracking_our_stop(void* tracking_config)
|
||||
{
|
||||
//Stop pixy's data send programm
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
|
||||
if(num_blocks <= 0){ // Check if there are blocks available
|
||||
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 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
|
||||
|
||||
@@ -136,245 +165,257 @@ void tracking_our_update(void* tracking_config, struct Block* blocks, int num_bl
|
||||
|
||||
//Variable which stores all the callbacks and settings for our tracking implementation
|
||||
static TRACKING_CONFIG_STRUCT tracking_our = {
|
||||
tracking_our_start,
|
||||
tracking_our_stop,
|
||||
tracking_our_update
|
||||
tracking_our_start,
|
||||
tracking_our_stop,
|
||||
tracking_our_update
|
||||
};
|
||||
|
||||
//Methods for reference tracking implementation ahead
|
||||
|
||||
//Method/Callback to start reference tracking
|
||||
void tracking_reference_start(void* tracking_config) {
|
||||
//Run reference tracking
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("runprog", INT8(2), END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
void tracking_reference_start(void* tracking_config)
|
||||
{
|
||||
//Run reference tracking
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("runprog", INT8(2), END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
}
|
||||
|
||||
//Method/Callback to stop reference tracking
|
||||
void tracking_reference_stop(void* tracking_config) {
|
||||
//Stop reference tracking
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
void tracking_reference_stop(void* tracking_config)
|
||||
{
|
||||
//Stop reference tracking
|
||||
int32_t response;
|
||||
int return_value;
|
||||
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
|
||||
}
|
||||
|
||||
//Method/Callback to calculate one step of the reference tracking
|
||||
void tracking_reference_update(void* tracking_config, struct Block* blocks, int num_blocks) {
|
||||
//Nothing to do here. Pixy does it all.
|
||||
void tracking_reference_update(void* tracking_config, struct Block* blocks, int num_blocks)
|
||||
{
|
||||
//Nothing to do here. Pixy does it all.
|
||||
}
|
||||
|
||||
//Variable which stores all the callbacks and settings for the reference tracking implementation
|
||||
static TRACKING_CONFIG_STRUCT tracking_reference = {
|
||||
tracking_reference_start,
|
||||
tracking_reference_stop,
|
||||
tracking_reference_update
|
||||
tracking_reference_start,
|
||||
tracking_reference_stop,
|
||||
tracking_reference_update
|
||||
};
|
||||
|
||||
//Pointer to the currently active tracking implementation. See also tracking_set_mode
|
||||
static TRACKING_CONFIG_STRUCT* tracking_current;
|
||||
|
||||
//Method to set the current tracking implementation. This function is exported and should be called before getting the screen
|
||||
void tracking_set_mode(enum Tracking_Implementation impl) {
|
||||
//Depending on the enum value let tracking_current point to a different setting/callback structure
|
||||
switch(impl) {
|
||||
case OUR_TRACKING:
|
||||
tracking_current = &tracking_our;
|
||||
break;
|
||||
case REFERENCE_TRACKING:
|
||||
tracking_current = &tracking_reference;
|
||||
break;
|
||||
default:
|
||||
tracking_current=NULL;
|
||||
break;
|
||||
}
|
||||
void tracking_set_mode(enum Tracking_Implementation impl)
|
||||
{
|
||||
//Depending on the enum value let tracking_current point to a different setting/callback structure
|
||||
switch (impl) {
|
||||
case OUR_TRACKING:
|
||||
tracking_current = &tracking_our;
|
||||
break;
|
||||
|
||||
case REFERENCE_TRACKING:
|
||||
tracking_current = &tracking_reference;
|
||||
break;
|
||||
|
||||
default:
|
||||
tracking_current = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Callback for when the screen is entered/loaded
|
||||
static void enter(void* screen) {
|
||||
tft_clear(WHITE);
|
||||
|
||||
//"Back" button
|
||||
b_back.base.x1=5; //Start X of Button
|
||||
b_back.base.y1=5; //Start Y of Button
|
||||
b_back.base.x2=AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2=AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor=WHITE; //Set foreground color
|
||||
b_back.bgcolor=HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font=0; //Select Font
|
||||
b_back.text="Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback=b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(WHITE);
|
||||
|
||||
//"Back" button
|
||||
b_back.base.x1 = 5; //Start X of Button
|
||||
b_back.base.y1 = 5; //Start Y of Button
|
||||
b_back.base.x2 = AUTO; //Auto Calculate X2 with String Width
|
||||
b_back.base.y2 = AUTO; //Auto Calculate Y2 with String Height
|
||||
b_back.txtcolor = WHITE; //Set foreground color
|
||||
b_back.bgcolor = HEX(0xAE1010); //Set background color (Don't take 255 or 0 on at least one channel, to make shadows possible)
|
||||
b_back.font = 0; //Select Font
|
||||
b_back.text = "Back"; //Set Text (For formatted strings take sprintf)
|
||||
b_back.callback = b_back_cb; //Call b_back_cb as Callback
|
||||
gui_button_add(&b_back); //Register Button (and run the callback from now on)
|
||||
|
||||
|
||||
//"Select color" button
|
||||
b_select.base.x1=150;
|
||||
b_select.base.y1=5;
|
||||
b_select.base.x2=AUTO;
|
||||
b_select.base.y2=AUTO;
|
||||
b_select.txtcolor=WHITE;
|
||||
b_select.bgcolor=HEX(0xAE1010);
|
||||
b_select.font=0;
|
||||
b_select.text="Select Color";
|
||||
b_select.callback=b_select_cb;
|
||||
gui_button_add(&b_select);
|
||||
//"Select color" button
|
||||
b_select.base.x1 = 150;
|
||||
b_select.base.y1 = 5;
|
||||
b_select.base.x2 = AUTO;
|
||||
b_select.base.y2 = AUTO;
|
||||
b_select.txtcolor = WHITE;
|
||||
b_select.bgcolor = HEX(0xAE1010);
|
||||
b_select.font = 0;
|
||||
b_select.text = "Select Color";
|
||||
b_select.callback = b_select_cb;
|
||||
gui_button_add(&b_select);
|
||||
|
||||
//"Frame visible" checkbox
|
||||
c_frame_toggle.base.x1 = 50;
|
||||
c_frame_toggle.base.x2 = 50+16;
|
||||
c_frame_toggle.base.y1 = 5;
|
||||
c_frame_toggle.base.y2 = 5+16;
|
||||
c_frame_toggle.checked = frame_visible;
|
||||
c_frame_toggle.fgcolor = CHECKBOX_WIN_FG_COLOR;
|
||||
c_frame_toggle.callback = c_frame_toggle_cb;
|
||||
gui_checkbox_add(&c_frame_toggle);
|
||||
tft_print_line(73,8,BLACK,TRANSPARENT,0,"Show Video");
|
||||
//"Frame visible" checkbox
|
||||
c_frame_toggle.base.x1 = 50;
|
||||
c_frame_toggle.base.x2 = 50 + 16;
|
||||
c_frame_toggle.base.y1 = 5;
|
||||
c_frame_toggle.base.y2 = 5 + 16;
|
||||
c_frame_toggle.checked = frame_visible;
|
||||
c_frame_toggle.fgcolor = CHECKBOX_WIN_FG_COLOR;
|
||||
c_frame_toggle.callback = c_frame_toggle_cb;
|
||||
gui_checkbox_add(&c_frame_toggle);
|
||||
tft_print_line(73, 8, BLACK, TRANSPARENT, 0, "Show Video");
|
||||
|
||||
|
||||
//Area to select a "color region"
|
||||
a_area.hookedActions = PEN_DOWN | PEN_UP;
|
||||
a_area.x1 = FRAME_START_X;
|
||||
a_area.y1 = FRAME_START_Y;
|
||||
a_area.x2 = FRAME_END_X;
|
||||
a_area.y2 = FRAME_END_Y;
|
||||
a_area.callback = touchCB;
|
||||
//Area to select a "color region"
|
||||
a_area.hookedActions = PEN_DOWN | PEN_UP;
|
||||
a_area.x1 = FRAME_START_X;
|
||||
a_area.y1 = FRAME_START_Y;
|
||||
a_area.x2 = FRAME_END_X;
|
||||
a_area.y2 = FRAME_END_Y;
|
||||
a_area.callback = touchCB;
|
||||
//Do not register it here, we do that later
|
||||
|
||||
if(tracking_current==NULL) {
|
||||
state = error;
|
||||
} else {
|
||||
state = detecting; //Start with the detecting state
|
||||
}
|
||||
if (tracking_current == NULL) {
|
||||
state = error;
|
||||
} else {
|
||||
state = detecting; //Start with the detecting state
|
||||
}
|
||||
}
|
||||
|
||||
//Callback for when the screen is left/unloaded
|
||||
static void leave(void* screen) {
|
||||
//Remove buttons and checkbox
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_select);
|
||||
gui_checkbox_remove(&c_frame_toggle);
|
||||
static void leave(void* screen)
|
||||
{
|
||||
//Remove buttons and checkbox
|
||||
gui_button_remove(&b_back);
|
||||
gui_button_remove(&b_select);
|
||||
gui_checkbox_remove(&c_frame_toggle);
|
||||
|
||||
if(state==selecting) { //the user left the screen in the "selecting" phase
|
||||
touch_unregister_area(&a_area); //remove the touch area
|
||||
}
|
||||
if (state == selecting) { //the user left the screen in the "selecting" phase
|
||||
touch_unregister_area(&a_area); //remove the touch area
|
||||
}
|
||||
|
||||
if(state==tracking) { //the user left the screen in the "tracking" phase
|
||||
tracking_current->stop(tracking_current); //stop tracking
|
||||
pixy_led_set_RGB(0,0,0);
|
||||
}
|
||||
if (state == tracking) { //the user left the screen in the "tracking" phase
|
||||
tracking_current->stop(tracking_current); //stop tracking
|
||||
pixy_led_set_RGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//Callback for when the screen should be updated
|
||||
//This is the main loop of the screen. This method will be called repeatedly
|
||||
static void update(void* screen) {
|
||||
switch(state) {
|
||||
case detecting: //Detecting State: Where we try to connect to the pixy
|
||||
if(pixy_init()==0) { //Pixy connection ok
|
||||
state = init; //Go to next state
|
||||
}
|
||||
break;
|
||||
static void update(void* screen)
|
||||
{
|
||||
switch (state) {
|
||||
case detecting: //Detecting State: Where we try to connect to the pixy
|
||||
if (pixy_init() == 0) { //Pixy connection ok
|
||||
state = init; //Go to next state
|
||||
}
|
||||
|
||||
case init: //Init State: Where we start the tracking
|
||||
tracking_current->start(tracking_current);
|
||||
state=tracking;
|
||||
break;
|
||||
break;
|
||||
|
||||
case tracking: //Tracking state: Where we render the frame and the tracked objects
|
||||
pixy_service(); //Receive events (e.g. block-data) from pixy
|
||||
case init: //Init State: Where we start the tracking
|
||||
tracking_current->start(tracking_current);
|
||||
state = tracking;
|
||||
break;
|
||||
|
||||
if(pixy_blocks_are_new()) { //There are new blocks available
|
||||
if(frame_visible) { //If the user want's us to draw the video data
|
||||
pixy_render_full_frame(FRAME_START_X,FRAME_START_Y);
|
||||
} else { //the user want's a colored background
|
||||
tft_fill_rectangle(FRAME_START_X,FRAME_START_Y,FRAME_END_X,FRAME_END_Y,RGB(200,200,200));
|
||||
}
|
||||
case tracking: //Tracking state: Where we render the frame and the tracked objects
|
||||
pixy_service(); //Receive events (e.g. block-data) from pixy
|
||||
|
||||
#define BLOCK_BUFFER_SIZE 5 //The maximum amount of blocks that we want to receive
|
||||
struct Block blocks[BLOCK_BUFFER_SIZE]; //Storage to receive blocks from pixy
|
||||
int blocks_received= pixy_get_blocks(BLOCK_BUFFER_SIZE,blocks); //Try to receive up to BLOCK_BUFFER_SIZE Blocks from pixy
|
||||
if (pixy_blocks_are_new()) { //There are new blocks available
|
||||
if (frame_visible) { //If the user want's us to draw the video data
|
||||
pixy_render_full_frame(FRAME_START_X, FRAME_START_Y);
|
||||
} else { //the user want's a colored background
|
||||
tft_fill_rectangle(FRAME_START_X, FRAME_START_Y, FRAME_END_X, FRAME_END_Y, RGB(200, 200, 200));
|
||||
}
|
||||
|
||||
if(blocks_received>=0) { //block receiving ok
|
||||
tracking_current->update(tracking_current,blocks,blocks_received); //apply tracking
|
||||
#define BLOCK_BUFFER_SIZE 5 //The maximum amount of blocks that we want to receive
|
||||
struct Block blocks[BLOCK_BUFFER_SIZE]; //Storage to receive blocks from pixy
|
||||
int blocks_received = pixy_get_blocks(BLOCK_BUFFER_SIZE, blocks); //Try to receive up to BLOCK_BUFFER_SIZE Blocks from pixy
|
||||
|
||||
//Draw blocks
|
||||
for(int i=0; i<blocks_received; i++) { //for each received block
|
||||
struct Block* block = &(blocks[i]);
|
||||
//block.x and block.y are the center coordinates of the object relative to the camera origin.
|
||||
uint16_t x = block->x-1+FRAME_START_X -block->width/2; //Calculate x-Coordinate on the display
|
||||
uint16_t y = block->y-1+FRAME_START_Y -block->height/2; //Calculate y-Coordinate on the display
|
||||
tft_draw_rectangle(x,y,x+block->width-1, y+block->height-1,WHITE); //Draw a white rectangle
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (blocks_received >= 0) { //block receiving ok
|
||||
tracking_current->update(tracking_current, blocks, blocks_received); //apply tracking
|
||||
|
||||
case preselecting: //Pre-Selecting State: Where we set up the color region selection
|
||||
{
|
||||
tracking_current->stop(tracking_current); //Stop tracking
|
||||
//Draw blocks
|
||||
for (int i = 0; i < blocks_received; i++) { //for each received block
|
||||
struct Block* block = &(blocks[i]);
|
||||
//block.x and block.y are the center coordinates of the object relative to the camera origin.
|
||||
uint16_t x = block->x - 1 + FRAME_START_X - block->width / 2; //Calculate x-Coordinate on the display
|
||||
uint16_t y = block->y - 1 + FRAME_START_Y - block->height / 2; //Calculate y-Coordinate on the display
|
||||
tft_draw_rectangle(x, y, x + block->width - 1, y + block->height - 1, WHITE); //Draw a white rectangle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pixy_render_full_frame(FRAME_START_X,FRAME_START_Y); //Render one frame
|
||||
break;
|
||||
|
||||
touch_register_area(&a_area); //Register touch area and receive events from now on
|
||||
point1_valid=false; //we start with an invalid point1
|
||||
case preselecting: { //Pre-Selecting State: Where we set up the color region selection
|
||||
tracking_current->stop(tracking_current); //Stop tracking
|
||||
|
||||
b_select.text="Abort"; //Change the button text to "Abort"
|
||||
gui_button_redraw(&b_select); //redraw button
|
||||
pixy_render_full_frame(FRAME_START_X, FRAME_START_Y); //Render one frame
|
||||
|
||||
state = selecting; //The user can now select a region
|
||||
}
|
||||
break;
|
||||
touch_register_area(&a_area); //Register touch area and receive events from now on
|
||||
point1_valid = false; //we start with an invalid point1
|
||||
|
||||
case selected: //Selected State: Where we send the users selection to pixy
|
||||
{
|
||||
//Ensure that (x1,y1) represent the top-left point and (x2,y2) the bottom-right.
|
||||
unsigned int tmp;
|
||||
if(point1.x > point2.x){
|
||||
tmp = point1.x;
|
||||
point1.x = point2.x;
|
||||
point2.x = tmp;
|
||||
}
|
||||
b_select.text = "Abort"; //Change the button text to "Abort"
|
||||
gui_button_redraw(&b_select); //redraw button
|
||||
|
||||
if(point1.y > point2.y){
|
||||
tmp = point1.y;
|
||||
point1.y = point2.y;
|
||||
point2.y = tmp;
|
||||
}
|
||||
//Send pixy the selected region
|
||||
pixy_cc_set_region(1,point1.x,point1.y,point2.x-point1.x,point2.y-point1.y);
|
||||
}
|
||||
//no break here: We want the following code to be executed as well
|
||||
state = selecting; //The user can now select a region
|
||||
}
|
||||
break;
|
||||
|
||||
case abortselecting: //Abort-Selecting State: Where we deinitialize the stuff we used for region selection
|
||||
{
|
||||
touch_unregister_area(&a_area); //Remove the touch area. We'll no longer receive touch events
|
||||
case selected: { //Selected State: Where we send the users selection to pixy
|
||||
//Ensure that (x1,y1) represent the top-left point and (x2,y2) the bottom-right.
|
||||
unsigned int tmp;
|
||||
|
||||
b_select.text="Select Color"; //Change the button text back to "Select Color"
|
||||
gui_button_redraw(&b_select); //redraw button
|
||||
if (point1.x > point2.x) {
|
||||
tmp = point1.x;
|
||||
point1.x = point2.x;
|
||||
point2.x = tmp;
|
||||
}
|
||||
|
||||
tracking_current->start(tracking_current); //Start tracking again
|
||||
state=tracking;
|
||||
}
|
||||
break;
|
||||
if (point1.y > point2.y) {
|
||||
tmp = point1.y;
|
||||
point1.y = point2.y;
|
||||
point2.y = tmp;
|
||||
}
|
||||
|
||||
case selecting: //Selecting State: Where we wait on the user to select a color region
|
||||
pixy_service(); //receive pixy events
|
||||
//wait on user to select the image area
|
||||
break;
|
||||
//Send pixy the selected region
|
||||
pixy_cc_set_region(1, point1.x, point1.y, point2.x - point1.x, point2.y - point1.y);
|
||||
}
|
||||
|
||||
case error: //Error State: Where we show an error message and leave the user no other choice than to click the backbutton
|
||||
//wait on user to click the back button
|
||||
break;
|
||||
}
|
||||
//no break here: We want the following code to be executed as well
|
||||
|
||||
case abortselecting: { //Abort-Selecting State: Where we deinitialize the stuff we used for region selection
|
||||
touch_unregister_area(&a_area); //Remove the touch area. We'll no longer receive touch events
|
||||
|
||||
b_select.text = "Select Color"; //Change the button text back to "Select Color"
|
||||
gui_button_redraw(&b_select); //redraw button
|
||||
|
||||
tracking_current->start(tracking_current); //Start tracking again
|
||||
state = tracking;
|
||||
}
|
||||
break;
|
||||
|
||||
case selecting: //Selecting State: Where we wait on the user to select a color region
|
||||
pixy_service(); //receive pixy events
|
||||
//wait on user to select the image area
|
||||
break;
|
||||
|
||||
case error: //Error State: Where we show an error message and leave the user no other choice than to click the backbutton
|
||||
//wait on user to click the back button
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Declare screen callbacks
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_tracking() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_tracking()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/app/screen_tracking.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-16 timolang@gmail.com e46314b Added Tracking Screen and implemented "Reference Tracking" and "Color Region Selection"
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
@@ -16,8 +29,8 @@
|
||||
* Enum which contains the available tracking implementations
|
||||
*/
|
||||
enum Tracking_Implementation {
|
||||
OUR_TRACKING, //!< Our own tracking PID implementation
|
||||
REFERENCE_TRACKING//!< Pixy's internal tracking implementation
|
||||
OUR_TRACKING, //!< Our own tracking PID implementation
|
||||
REFERENCE_TRACKING//!< Pixy's internal tracking implementation
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,38 +1,56 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/filesystem/filesystem.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "ll_filesystem.h"
|
||||
|
||||
bool filesystem_init() {
|
||||
return ll_filesystem_init();
|
||||
bool filesystem_init()
|
||||
{
|
||||
return ll_filesystem_init();
|
||||
}
|
||||
|
||||
DIRECTORY_STRUCT* filesystem_dir_open(const char* path) {
|
||||
return ll_filesystem_dir_open(path);
|
||||
DIRECTORY_STRUCT* filesystem_dir_open(const char* path)
|
||||
{
|
||||
return ll_filesystem_dir_open(path);
|
||||
}
|
||||
|
||||
void filesystem_dir_close(DIRECTORY_STRUCT* dir) {
|
||||
ll_filesystem_dir_close(dir);
|
||||
void filesystem_dir_close(DIRECTORY_STRUCT* dir)
|
||||
{
|
||||
ll_filesystem_dir_close(dir);
|
||||
}
|
||||
|
||||
FILE_HANDLE* filesystem_file_open(const char* filename) {
|
||||
return ll_filesystem_file_open(filename);
|
||||
FILE_HANDLE* filesystem_file_open(const char* filename)
|
||||
{
|
||||
return ll_filesystem_file_open(filename);
|
||||
}
|
||||
|
||||
void filesystem_file_close(FILE_HANDLE* handle) {
|
||||
ll_filesystem_file_close(handle);
|
||||
void filesystem_file_close(FILE_HANDLE* handle)
|
||||
{
|
||||
ll_filesystem_file_close(handle);
|
||||
}
|
||||
|
||||
FILE_STATUS filesystem_file_seek(FILE_HANDLE* handle, uint32_t offset) {
|
||||
return ll_filesystem_file_seek(handle,offset);
|
||||
FILE_STATUS filesystem_file_seek(FILE_HANDLE* handle, uint32_t offset)
|
||||
{
|
||||
return ll_filesystem_file_seek(handle, offset);
|
||||
}
|
||||
|
||||
FILE_STATUS filesystem_file_read(FILE_HANDLE* handle, uint8_t* buf, uint32_t size) {
|
||||
return ll_filesystem_file_read(handle,buf,size);
|
||||
FILE_STATUS filesystem_file_read(FILE_HANDLE* handle, uint8_t* buf, uint32_t size)
|
||||
{
|
||||
return ll_filesystem_file_read(handle, buf, size);
|
||||
}
|
||||
|
||||
FILE_STATUS filesystem_file_write(FILE_HANDLE* handle, uint8_t* buf, uint32_t size) {
|
||||
return ll_filesystem_file_write(handle,buf,size);
|
||||
FILE_STATUS filesystem_file_write(FILE_HANDLE* handle, uint8_t* buf, uint32_t size)
|
||||
{
|
||||
return ll_filesystem_file_write(handle, buf, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/filesystem/filesystem.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
@@ -15,57 +30,57 @@
|
||||
* See http://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#attributes for detailed description
|
||||
*/
|
||||
typedef enum {
|
||||
F_RDO=0x01,//!< File is readonly. You cannot write to it
|
||||
F_HID=0x02,//!< File is hidden
|
||||
F_SYS=0x04,//!< File is a system file
|
||||
F_DIR=0x10,//!< It's a directory and not a file
|
||||
F_ARC=0x20 //!< File has the archive flag set (probably unused)
|
||||
F_RDO = 0x01, //!< File is readonly. You cannot write to it
|
||||
F_HID = 0x02, //!< File is hidden
|
||||
F_SYS = 0x04, //!< File is a system file
|
||||
F_DIR = 0x10, //!< It's a directory and not a file
|
||||
F_ARC = 0x20 //!< File has the archive flag set (probably unused)
|
||||
} FILE_ATTRIBUTES;
|
||||
|
||||
/**
|
||||
* Structure which represents last modified date of a file / directory
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned year : 7; //!< year from 1980 (0..127)
|
||||
unsigned month: 4; //!< month (1..12)
|
||||
unsigned day: 5; //!< day (1..31)
|
||||
unsigned year : 7; //!< year from 1980 (0..127)
|
||||
unsigned month: 4; //!< month (1..12)
|
||||
unsigned day: 5; //!< day (1..31)
|
||||
} FILE_DATE_STRUCT;
|
||||
|
||||
/**
|
||||
* Structure which represents last modified time of a file / directory
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned hour : 5; //!< hour (0..23)
|
||||
unsigned min: 6; //!< minute (0..59
|
||||
unsigned sec: 5; //!< second/2 (0..29)
|
||||
unsigned hour : 5; //!< hour (0..23)
|
||||
unsigned min: 6; //!< minute (0..59
|
||||
unsigned sec: 5; //!< second/2 (0..29)
|
||||
} FILE_TIME_STRUCT;
|
||||
|
||||
/**
|
||||
* Structure which represents a file/directory entry. \sa DIRECTORY_STRUCT
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t fsize; //!< File size in bytes. 0 for directories
|
||||
FILE_DATE_STRUCT fdate; //!< Last modified date
|
||||
FILE_TIME_STRUCT ftime; //!< Last modified time
|
||||
uint8_t fattrib; //!< File/Directory Attributes
|
||||
char* fname; //!< File/Directory name
|
||||
uint32_t fsize; //!< File size in bytes. 0 for directories
|
||||
FILE_DATE_STRUCT fdate; //!< Last modified date
|
||||
FILE_TIME_STRUCT ftime; //!< Last modified time
|
||||
uint8_t fattrib; //!< File/Directory Attributes
|
||||
char* fname; //!< File/Directory name
|
||||
} FILE_STRUCT;
|
||||
|
||||
/**
|
||||
* Structure which represents an open directory with all it's entries. \sa filesystem_dir_open
|
||||
*/
|
||||
typedef struct {
|
||||
const char* path; //!< Directory path (absolute)
|
||||
uint16_t num_files; //!< Number of files/directories in this directory
|
||||
FILE_STRUCT* files; //!< An array with \ref num_files FILE_STRUCT entries
|
||||
const char* path; //!< Directory path (absolute)
|
||||
uint16_t num_files; //!< Number of files/directories in this directory
|
||||
FILE_STRUCT* files; //!< An array with \ref num_files FILE_STRUCT entries
|
||||
} DIRECTORY_STRUCT;
|
||||
|
||||
/**
|
||||
* Structure which represents an open file. \sa filesystem_file_open
|
||||
*/
|
||||
typedef struct {
|
||||
const char* fname; //!< The absolute file name
|
||||
uint32_t fpos; //!< The current byte-position in the file. \sa filesystem_file_seek
|
||||
const char* fname; //!< The absolute file name
|
||||
uint32_t fpos; //!< The current byte-position in the file. \sa filesystem_file_seek
|
||||
uint32_t fsize; //!< The total file size in bytes
|
||||
} FILE_HANDLE;
|
||||
|
||||
@@ -73,11 +88,11 @@ typedef struct {
|
||||
* Enum to represent the success or error-code of the filesystem_file_* functions
|
||||
*/
|
||||
typedef enum {
|
||||
F_OK, //!< Everything ok
|
||||
F_EOF, //!< The write/read operation tried to write/read past the end of the file. This is not a fatal error.
|
||||
F_EACCESS, //!< The file can not be read/written due to access problems. This is a fatal error.
|
||||
F_INVALIDPARAM,//!< You passed invalid parameters to the function
|
||||
F_DISKERROR //!< A lowlevel disk-error occoured. This is a fatal error.
|
||||
F_OK, //!< Everything ok
|
||||
F_EOF, //!< The write/read operation tried to write/read past the end of the file. This is not a fatal error.
|
||||
F_EACCESS, //!< The file can not be read/written due to access problems. This is a fatal error.
|
||||
F_INVALIDPARAM,//!< You passed invalid parameters to the function
|
||||
F_DISKERROR //!< A lowlevel disk-error occoured. This is a fatal error.
|
||||
} FILE_STATUS;
|
||||
|
||||
/**
|
||||
@@ -144,4 +159,3 @@ FILE_STATUS filesystem_file_write(FILE_HANDLE* handle, uint8_t* buf, uint32_t si
|
||||
/*@}*/
|
||||
|
||||
#endif /* FILESYSTEM_H */
|
||||
|
||||
|
||||
@@ -1,154 +1,188 @@
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "button.h"
|
||||
#include <string.h>
|
||||
|
||||
/* The Idea is as follows:
|
||||
* When the user add's a button we create a touch area for that region and wait for PEN_DOWN events.
|
||||
* Once the user puts the pen down in this area we'll redraw the button with different shadows (feedback)
|
||||
* and we'll now wait on PEN_UP or PEN_LEAVE events.
|
||||
* If the user takes the pen away while in the area (PEN_UP), we call the provided user callback
|
||||
* Otherwise (PEN_LEAVE) we only restore the initial shadows
|
||||
*/
|
||||
|
||||
/* Possible improvements:
|
||||
* Move the button by 1 pixel while he is pressed, to create a "full 3d" experience
|
||||
* Add events for the case when the button is pressed for a long time, without release
|
||||
*/
|
||||
|
||||
//Method to calculate the shadow colors used to create the "3d" effect
|
||||
void calculate_shadows(uint16_t bgcolor, uint16_t* light_shadow, uint16_t* dark_shadow) {
|
||||
#define BRIGHTNESS_VAL 3 //How much the Brightness is in/decreased for button shadows (3 -> Add/Subtract 1/3 off Full Value)
|
||||
|
||||
uint16_t c_light,c_dark; //c_light and c_dark will be filled with a lighter and a darker color as the background color (for the shadows)
|
||||
uint8_t r,g,b;
|
||||
|
||||
//separate the channels of the 16-bit rgb565 color
|
||||
r=(bgcolor&0xF800)>>11;
|
||||
g=(bgcolor&0x07E0)>>5;
|
||||
b=(bgcolor&0x001F)>>0;
|
||||
|
||||
//For the light shadow color:
|
||||
if((r + 0x1F/BRIGHTNESS_VAL) > 0x1F) //Adding one third would exceed the maximum of the red channel
|
||||
c_light=0xF800; //Use full red
|
||||
else //adding one third to the red channel is fine
|
||||
c_light=(r+0x1F/BRIGHTNESS_VAL)<<11; //Use same red as in the background, but add one third
|
||||
if((g + 0x3F/BRIGHTNESS_VAL) > 0x3F) //same for the green channel
|
||||
c_light|=0x07E0;
|
||||
else
|
||||
c_light|=(g+0x3F/BRIGHTNESS_VAL)<<5;
|
||||
if((b + 0x1F/BRIGHTNESS_VAL) > 0x1F) //and the blue channel
|
||||
c_light|=0x0018;
|
||||
else
|
||||
c_light|=(b+0x1F/BRIGHTNESS_VAL)<<0;
|
||||
|
||||
//For the dark shadow color
|
||||
if(r > (0x1F/BRIGHTNESS_VAL)) //Subtracting one third would NOT exceed the minimum of the red channel
|
||||
c_dark=(r-0x1F/BRIGHTNESS_VAL)<<11; //Use same red as in the background, but subtract one third
|
||||
else //Subtracting one third would give us a number below zero
|
||||
c_dark=0x0000; //use no red channel
|
||||
if(g > (0x3F/BRIGHTNESS_VAL)) //Same for the green channel
|
||||
c_dark|=(g-0x3F/BRIGHTNESS_VAL)<<5;
|
||||
if(b > (0x1F/BRIGHTNESS_VAL)) //and the blue channel
|
||||
c_dark|=(b-0x1F/BRIGHTNESS_VAL)<<0;
|
||||
|
||||
//Assign the calculated shadows to out parameters
|
||||
if(light_shadow!=NULL) *light_shadow = c_light;
|
||||
if(dark_shadow!=NULL) *dark_shadow = c_dark;
|
||||
|
||||
}
|
||||
|
||||
//Callback which is called when the user touches the touch-area we created for the button
|
||||
void buttons_cb(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
TOUCH_AREA_STRUCT * area = (TOUCH_AREA_STRUCT*)touchArea;
|
||||
BUTTON_STRUCT* button = (BUTTON_STRUCT*)touchArea;
|
||||
|
||||
uint16_t c_light,c_dark; //c_light and c_dark will be filled with a lighter and a darker color as the background color (for the shadows)
|
||||
calculate_shadows(button->bgcolor,&c_light,&c_dark);
|
||||
|
||||
switch(triggeredAction)
|
||||
{
|
||||
case PEN_DOWN: //If the user touches the area for the "first time"
|
||||
area->hookedActions=PEN_UP|PEN_LEAVE; //for the future we only want PEN_UP and PEN_LEAVE events
|
||||
|
||||
//Draw shadows
|
||||
tft_draw_line(button->base.x1+1,button->base.y1,button->base.x2-1,button->base.y1,c_dark); //North
|
||||
tft_draw_line(button->base.x1,button->base.y1+1,button->base.x1,button->base.y2-1,c_dark);//West
|
||||
tft_draw_line(button->base.x1+1,button->base.y2,button->base.x2-1,button->base.y2,c_light); //South
|
||||
tft_draw_line(button->base.x2,button->base.y1+1,button->base.x2,button->base.y2-1,c_light); //East
|
||||
break;
|
||||
case PEN_UP: //If the user took the pen away, while in the area (=button pressed!)
|
||||
case PEN_LEAVE: //or the user "slided out" of the area
|
||||
area->hookedActions=PEN_DOWN; //for the future we only want PEN_DOWN events
|
||||
|
||||
//Draw inverse shadows
|
||||
tft_draw_line(button->base.x1+1,button->base.y1,button->base.x2-1,button->base.y1,c_light); //North
|
||||
tft_draw_line(button->base.x1,button->base.y1+1,button->base.x1,button->base.y2-1,c_light);//West
|
||||
tft_draw_line(button->base.x1+1,button->base.y2,button->base.x2-1,button->base.y2,c_dark); //South
|
||||
tft_draw_line(button->base.x2,button->base.y1+1,button->base.x2,button->base.y2-1,c_dark); //East
|
||||
|
||||
if(triggeredAction==PEN_UP && button->callback!=NULL) //If the button got "pressed" instead of left, and the user provided a callback
|
||||
button->callback(button); //execute the user callback
|
||||
break;
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gui_button_add(BUTTON_STRUCT* button)
|
||||
{
|
||||
if(touch_have_empty(1)) //Check if the touch module can handle one additional area
|
||||
{
|
||||
//Calculate width and height of the button text
|
||||
unsigned int strwidth=tft_font_width(button->font)*strlen(button->text);
|
||||
unsigned char strheight=tft_font_height(button->font);
|
||||
|
||||
button->base.hookedActions=PEN_DOWN; //At first we are interested in PEN_DOWN events
|
||||
button->base.callback = buttons_cb; //Use our own callback for the touch area events
|
||||
|
||||
if(button->base.x2==AUTO) { //The user wants us to calculate the button width automatically
|
||||
//Use string width + half of a character width as button width
|
||||
button->base.x2= button->base.x1 -1 + strwidth+(tft_font_width(button->font)/2);
|
||||
} else if((button->base.x2-button->base.x1+1)<(strwidth+2)) { //the provided width is too small to fit the entire text
|
||||
return false; //report error
|
||||
}
|
||||
|
||||
if(button->base.y2==AUTO) { //The user wants us to calculate the button height automatically
|
||||
//Use one and a half character heights as button height
|
||||
button->base.y2=button->base.y1 -1 +strheight+(strheight/2);
|
||||
} else if((button->base.y2-button->base.y1+1)<(strheight+2)) { //the provided height is too small to fit the text
|
||||
return false;
|
||||
}
|
||||
gui_button_redraw(button); //call the redraw method, which will take care of drawing the entire button
|
||||
return touch_register_area(&button->base); //Register the touch area and receive events for this button, from now on
|
||||
}
|
||||
|
||||
return false; //no more touch areas left
|
||||
}
|
||||
|
||||
void gui_button_redraw(BUTTON_STRUCT* button)
|
||||
{
|
||||
//Calculate text dimensions and shadow colors
|
||||
unsigned int strwidth=tft_font_width(button->font)*strlen(button->text);
|
||||
unsigned char strheight=tft_font_height(button->font);
|
||||
uint16_t c_light,c_dark;
|
||||
calculate_shadows(button->bgcolor,&c_light,&c_dark);
|
||||
|
||||
//Draw the background and the 4 lines (shadow colors)
|
||||
tft_fill_rectangle(button->base.x1+1,button->base.y1+1,button->base.x2-1,button->base.y2-1,button->bgcolor);
|
||||
tft_draw_line(button->base.x1+1,button->base.y1,button->base.x2-1,button->base.y1,c_light); //North
|
||||
tft_draw_line(button->base.x1,button->base.y1+1,button->base.x1,button->base.y2-1,c_light);//West
|
||||
tft_draw_line(button->base.x1+1,button->base.y2,button->base.x2-1,button->base.y2,c_dark); //South
|
||||
tft_draw_line(button->base.x2,button->base.y1+1,button->base.x2,button->base.y2-1,c_dark); //East
|
||||
|
||||
//Draw the text
|
||||
tft_print_line(button->base.x1+(button->base.x2-button->base.x1+1-strwidth)/2,button->base.y1+(button->base.y2-button->base.y1+1-strheight)/2,button->txtcolor,button->bgcolor,button->font,button->text);
|
||||
|
||||
}
|
||||
|
||||
void gui_button_remove(BUTTON_STRUCT* button)
|
||||
{
|
||||
//We only need to unregister the touch area, as we have not allocated anything else
|
||||
touch_unregister_area((TOUCH_AREA_STRUCT*)button);
|
||||
}
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/button.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com 7c9eabc Added button support.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "button.h"
|
||||
#include <string.h>
|
||||
|
||||
/* The Idea is as follows:
|
||||
* When the user add's a button we create a touch area for that region and wait for PEN_DOWN events.
|
||||
* Once the user puts the pen down in this area we'll redraw the button with different shadows (feedback)
|
||||
* and we'll now wait on PEN_UP or PEN_LEAVE events.
|
||||
* If the user takes the pen away while in the area (PEN_UP), we call the provided user callback
|
||||
* Otherwise (PEN_LEAVE) we only restore the initial shadows
|
||||
*/
|
||||
|
||||
/* Possible improvements:
|
||||
* Move the button by 1 pixel while he is pressed, to create a "full 3d" experience
|
||||
* Add events for the case when the button is pressed for a long time, without release
|
||||
*/
|
||||
|
||||
//Method to calculate the shadow colors used to create the "3d" effect
|
||||
void calculate_shadows(uint16_t bgcolor, uint16_t* light_shadow, uint16_t* dark_shadow)
|
||||
{
|
||||
#define BRIGHTNESS_VAL 3 //How much the Brightness is in/decreased for button shadows (3 -> Add/Subtract 1/3 off Full Value)
|
||||
|
||||
uint16_t c_light, c_dark; //c_light and c_dark will be filled with a lighter and a darker color as the background color (for the shadows)
|
||||
uint8_t r, g, b;
|
||||
|
||||
//separate the channels of the 16-bit rgb565 color
|
||||
r = (bgcolor & 0xF800) >> 11;
|
||||
g = (bgcolor & 0x07E0) >> 5;
|
||||
b = (bgcolor & 0x001F) >> 0;
|
||||
|
||||
//For the light shadow color:
|
||||
if ((r + 0x1F / BRIGHTNESS_VAL) > 0x1F) { //Adding one third would exceed the maximum of the red channel
|
||||
c_light = 0xF800; //Use full red
|
||||
} else { //adding one third to the red channel is fine
|
||||
c_light = (r + 0x1F / BRIGHTNESS_VAL) << 11; //Use same red as in the background, but add one third
|
||||
}
|
||||
|
||||
if ((g + 0x3F / BRIGHTNESS_VAL) > 0x3F) { //same for the green channel
|
||||
c_light |= 0x07E0;
|
||||
} else {
|
||||
c_light |= (g + 0x3F / BRIGHTNESS_VAL) << 5;
|
||||
}
|
||||
|
||||
if ((b + 0x1F / BRIGHTNESS_VAL) > 0x1F) { //and the blue channel
|
||||
c_light |= 0x0018;
|
||||
} else {
|
||||
c_light |= (b + 0x1F / BRIGHTNESS_VAL) << 0;
|
||||
}
|
||||
|
||||
//For the dark shadow color
|
||||
if (r > (0x1F / BRIGHTNESS_VAL)) { //Subtracting one third would NOT exceed the minimum of the red channel
|
||||
c_dark = (r - 0x1F / BRIGHTNESS_VAL) << 11; //Use same red as in the background, but subtract one third
|
||||
} else { //Subtracting one third would give us a number below zero
|
||||
c_dark = 0x0000; //use no red channel
|
||||
}
|
||||
|
||||
if (g > (0x3F / BRIGHTNESS_VAL)) { //Same for the green channel
|
||||
c_dark |= (g - 0x3F / BRIGHTNESS_VAL) << 5;
|
||||
}
|
||||
|
||||
if (b > (0x1F / BRIGHTNESS_VAL)) { //and the blue channel
|
||||
c_dark |= (b - 0x1F / BRIGHTNESS_VAL) << 0;
|
||||
}
|
||||
|
||||
//Assign the calculated shadows to out parameters
|
||||
if (light_shadow != NULL) {
|
||||
*light_shadow = c_light;
|
||||
}
|
||||
|
||||
if (dark_shadow != NULL) {
|
||||
*dark_shadow = c_dark;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Callback which is called when the user touches the touch-area we created for the button
|
||||
void buttons_cb(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
TOUCH_AREA_STRUCT* area = (TOUCH_AREA_STRUCT*)touchArea;
|
||||
BUTTON_STRUCT* button = (BUTTON_STRUCT*)touchArea;
|
||||
|
||||
uint16_t c_light, c_dark; //c_light and c_dark will be filled with a lighter and a darker color as the background color (for the shadows)
|
||||
calculate_shadows(button->bgcolor, &c_light, &c_dark);
|
||||
|
||||
switch (triggeredAction) {
|
||||
case PEN_DOWN: //If the user touches the area for the "first time"
|
||||
area->hookedActions = PEN_UP | PEN_LEAVE; //for the future we only want PEN_UP and PEN_LEAVE events
|
||||
|
||||
//Draw shadows
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y1, button->base.x2 - 1, button->base.y1, c_dark); //North
|
||||
tft_draw_line(button->base.x1, button->base.y1 + 1, button->base.x1, button->base.y2 - 1, c_dark); //West
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y2, button->base.x2 - 1, button->base.y2, c_light); //South
|
||||
tft_draw_line(button->base.x2, button->base.y1 + 1, button->base.x2, button->base.y2 - 1, c_light); //East
|
||||
break;
|
||||
|
||||
case PEN_UP: //If the user took the pen away, while in the area (=button pressed!)
|
||||
case PEN_LEAVE: //or the user "slided out" of the area
|
||||
area->hookedActions = PEN_DOWN; //for the future we only want PEN_DOWN events
|
||||
|
||||
//Draw inverse shadows
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y1, button->base.x2 - 1, button->base.y1, c_light); //North
|
||||
tft_draw_line(button->base.x1, button->base.y1 + 1, button->base.x1, button->base.y2 - 1, c_light); //West
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y2, button->base.x2 - 1, button->base.y2, c_dark); //South
|
||||
tft_draw_line(button->base.x2, button->base.y1 + 1, button->base.x2, button->base.y2 - 1, c_dark); //East
|
||||
|
||||
if (triggeredAction == PEN_UP && button->callback != NULL) { //If the button got "pressed" instead of left, and the user provided a callback
|
||||
button->callback(button); //execute the user callback
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gui_button_add(BUTTON_STRUCT* button)
|
||||
{
|
||||
if (touch_have_empty(1)) { //Check if the touch module can handle one additional area
|
||||
//Calculate width and height of the button text
|
||||
unsigned int strwidth = tft_font_width(button->font) * strlen(button->text);
|
||||
unsigned char strheight = tft_font_height(button->font);
|
||||
|
||||
button->base.hookedActions = PEN_DOWN; //At first we are interested in PEN_DOWN events
|
||||
button->base.callback = buttons_cb; //Use our own callback for the touch area events
|
||||
|
||||
if (button->base.x2 == AUTO) { //The user wants us to calculate the button width automatically
|
||||
//Use string width + half of a character width as button width
|
||||
button->base.x2 = button->base.x1 - 1 + strwidth + (tft_font_width(button->font) / 2);
|
||||
} else if ((button->base.x2 - button->base.x1 + 1) < (strwidth + 2)) { //the provided width is too small to fit the entire text
|
||||
return false; //report error
|
||||
}
|
||||
|
||||
if (button->base.y2 == AUTO) { //The user wants us to calculate the button height automatically
|
||||
//Use one and a half character heights as button height
|
||||
button->base.y2 = button->base.y1 - 1 + strheight + (strheight / 2);
|
||||
} else if ((button->base.y2 - button->base.y1 + 1) < (strheight + 2)) { //the provided height is too small to fit the text
|
||||
return false;
|
||||
}
|
||||
|
||||
gui_button_redraw(button); //call the redraw method, which will take care of drawing the entire button
|
||||
return touch_register_area(&button->base); //Register the touch area and receive events for this button, from now on
|
||||
}
|
||||
|
||||
return false; //no more touch areas left
|
||||
}
|
||||
|
||||
void gui_button_redraw(BUTTON_STRUCT* button)
|
||||
{
|
||||
//Calculate text dimensions and shadow colors
|
||||
unsigned int strwidth = tft_font_width(button->font) * strlen(button->text);
|
||||
unsigned char strheight = tft_font_height(button->font);
|
||||
uint16_t c_light, c_dark;
|
||||
calculate_shadows(button->bgcolor, &c_light, &c_dark);
|
||||
|
||||
//Draw the background and the 4 lines (shadow colors)
|
||||
tft_fill_rectangle(button->base.x1 + 1, button->base.y1 + 1, button->base.x2 - 1, button->base.y2 - 1, button->bgcolor);
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y1, button->base.x2 - 1, button->base.y1, c_light); //North
|
||||
tft_draw_line(button->base.x1, button->base.y1 + 1, button->base.x1, button->base.y2 - 1, c_light); //West
|
||||
tft_draw_line(button->base.x1 + 1, button->base.y2, button->base.x2 - 1, button->base.y2, c_dark); //South
|
||||
tft_draw_line(button->base.x2, button->base.y1 + 1, button->base.x2, button->base.y2 - 1, c_dark); //East
|
||||
|
||||
//Draw the text
|
||||
tft_print_line(button->base.x1 + (button->base.x2 - button->base.x1 + 1 - strwidth) / 2, button->base.y1 + (button->base.y2 - button->base.y1 + 1 - strheight) / 2, button->txtcolor, button->bgcolor, button->font, button->text);
|
||||
|
||||
}
|
||||
|
||||
void gui_button_remove(BUTTON_STRUCT* button)
|
||||
{
|
||||
//We only need to unregister the touch area, as we have not allocated anything else
|
||||
touch_unregister_area((TOUCH_AREA_STRUCT*)button);
|
||||
}
|
||||
|
||||
@@ -1,71 +1,89 @@
|
||||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
/**
|
||||
* @defgroup gui Gui
|
||||
* The Gui Module
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup button Button
|
||||
* The Button Gui-Element is a clickable, rectangular box with a label inside.
|
||||
* When it is pressed and released you will be notified via the provided callback.
|
||||
*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup button
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the button is pressed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param button The pointer to the BUTTON_STRUCT where to corresponding Button was pressed
|
||||
*/
|
||||
typedef void (*BUTTON_CALLBACK)(void *button);
|
||||
|
||||
|
||||
/**
|
||||
* Structure to configure the Button
|
||||
*/
|
||||
typedef struct {
|
||||
TOUCH_AREA_STRUCT base; //!< Basic geometry of the button. You only need to set the x1, y1, x2, y2 members of this struct.
|
||||
uint16_t bgcolor; //!< The 16-bit background color of the button
|
||||
BUTTON_CALLBACK callback; //!< Callback which is executed when the button is pressed
|
||||
uint16_t txtcolor; //!< The 16-bit text color
|
||||
uint8_t font; //!< The number of the font to use
|
||||
const char *text; //!< The label of the button
|
||||
} BUTTON_STRUCT;
|
||||
|
||||
|
||||
#define AUTO 0 //!< Use this value instead of x2, y2 in the BUTTON_STRUCT to autocalculate the button width/height
|
||||
|
||||
/**
|
||||
* Adds a button. Your Callback will be called from now on, if the button was pressed
|
||||
* @param button A Pointer to the preinitialized BUTTON_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_button_add(BUTTON_STRUCT* button);
|
||||
|
||||
/**
|
||||
* Removes the button. You will no longer receive events for this button. This function will not overdraw the region where the button was located.
|
||||
* @param button A Pointer to the BUTTON_STRUCT
|
||||
*/
|
||||
void gui_button_remove(BUTTON_STRUCT* button);
|
||||
|
||||
/**
|
||||
* Redraws the button. Call this method if you have to redraw the entire screen or if you want to draw a button on top of an image.
|
||||
* @param button A Pointer to the BUTTON_STRUCT
|
||||
*/
|
||||
void gui_button_redraw(BUTTON_STRUCT* button);
|
||||
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* BUTTON_H */
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/button.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com 7c9eabc Added button support.
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-12 timolang@gmail.com 1402598 Added doxygen stuff for button module and some minor changes to touch, screen_main and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
/**
|
||||
* @defgroup gui Gui
|
||||
* The Gui Module
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup button Button
|
||||
* The Button Gui-Element is a clickable, rectangular box with a label inside.
|
||||
* When it is pressed and released you will be notified via the provided callback.
|
||||
*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup button
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the button is pressed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param button The pointer to the BUTTON_STRUCT where to corresponding Button was pressed
|
||||
*/
|
||||
typedef void (*BUTTON_CALLBACK)(void* button);
|
||||
|
||||
|
||||
/**
|
||||
* Structure to configure the Button
|
||||
*/
|
||||
typedef struct {
|
||||
TOUCH_AREA_STRUCT base; //!< Basic geometry of the button. You only need to set the x1, y1, x2, y2 members of this struct.
|
||||
uint16_t bgcolor; //!< The 16-bit background color of the button
|
||||
BUTTON_CALLBACK callback; //!< Callback which is executed when the button is pressed
|
||||
uint16_t txtcolor; //!< The 16-bit text color
|
||||
uint8_t font; //!< The number of the font to use
|
||||
const char* text; //!< The label of the button
|
||||
} BUTTON_STRUCT;
|
||||
|
||||
|
||||
#define AUTO 0 //!< Use this value instead of x2, y2 in the BUTTON_STRUCT to autocalculate the button width/height
|
||||
|
||||
/**
|
||||
* Adds a button. Your Callback will be called from now on, if the button was pressed
|
||||
* @param button A Pointer to the preinitialized BUTTON_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_button_add(BUTTON_STRUCT* button);
|
||||
|
||||
/**
|
||||
* Removes the button. You will no longer receive events for this button. This function will not overdraw the region where the button was located.
|
||||
* @param button A Pointer to the BUTTON_STRUCT
|
||||
*/
|
||||
void gui_button_remove(BUTTON_STRUCT* button);
|
||||
|
||||
/**
|
||||
* Redraws the button. Call this method if you have to redraw the entire screen or if you want to draw a button on top of an image.
|
||||
* @param button A Pointer to the BUTTON_STRUCT
|
||||
*/
|
||||
void gui_button_redraw(BUTTON_STRUCT* button);
|
||||
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* BUTTON_H */
|
||||
|
||||
@@ -1,121 +1,144 @@
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "checkbox.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* The idea is as follows:
|
||||
* When the user creates a checkbox we create a touch area for that region and wait for PEN_DOWN events.
|
||||
* Once the user puts the pen down in this area we'll redraw the checkbox with different shadows (feedback)
|
||||
* and we'll now wait on PEN_UP or PEN_LEAVE events.
|
||||
* If the user takes the pen away while in the area (PEN_UP), we toggle the checkbox and we call the provided user callback
|
||||
* Otherwise (PEN_LEAVE) we only restore the initial shadows
|
||||
*/
|
||||
|
||||
|
||||
#define ACTIVE_COLOR RGB(251,208,123) //shadow color (inside of border)
|
||||
#define BORDER_COLOR RGB(29,82,129) //1px border color
|
||||
#define BACKGROUND_COLOR WHITE //Background color
|
||||
|
||||
//Callback which is called when the user touches the touch-area we created for the checkbox
|
||||
void checkboxes_cb(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
TOUCH_AREA_STRUCT * area = (TOUCH_AREA_STRUCT*)touchArea;
|
||||
CHECKBOX_STRUCT* checkbox = (CHECKBOX_STRUCT*)touchArea;
|
||||
switch(triggeredAction)
|
||||
{
|
||||
case PEN_DOWN: //If the user touches the area for the "first time"
|
||||
area->hookedActions=PEN_UP|PEN_LEAVE; //for the future we only want PEN_UP and PEN_LEAVE events
|
||||
|
||||
//Draw active shadows
|
||||
tft_draw_rectangle(checkbox->base.x1+1,checkbox->base.y1+1,checkbox->base.x2-1,checkbox->base.y2-1,ACTIVE_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1+2,checkbox->base.y1+2,checkbox->base.x2-2,checkbox->base.y2-2,ACTIVE_COLOR);
|
||||
break;
|
||||
case PEN_UP: //If the user took the pen away, while in the area (=toggle checkbox!)
|
||||
checkbox->checked=!checkbox->checked; //Toggle checkbox state
|
||||
gui_checkbox_update(checkbox); //redraw/overdraw tickmark
|
||||
if(checkbox->callback!=NULL) { //The user provided a callback
|
||||
checkbox->callback(checkbox,checkbox->checked); //Call the provided callback with the new checked state
|
||||
}
|
||||
// no break statement here!
|
||||
case PEN_LEAVE: //if the user "slided out" of the area
|
||||
area->hookedActions=PEN_DOWN; //for the future we only want PEN_DOWN events
|
||||
|
||||
//Draw inactive shadows
|
||||
tft_draw_rectangle(checkbox->base.x1+1,checkbox->base.y1+1,checkbox->base.x2-1,checkbox->base.y2-1,BACKGROUND_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1+2,checkbox->base.y1+2,checkbox->base.x2-2,checkbox->base.y2-2,BACKGROUND_COLOR);
|
||||
break;
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
|
||||
bool gui_checkbox_add(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
if(touch_have_empty(1)) //Check if the touch module can handle one additional area
|
||||
{
|
||||
unsigned char size=0;
|
||||
checkbox->base.hookedActions=PEN_DOWN; //At first we are interested in PEN_DOWN events
|
||||
checkbox->base.callback = checkboxes_cb; //Use our own callback for the touch area events
|
||||
|
||||
//Check the size of the checkbox
|
||||
if(checkbox->base.x2>checkbox->base.x1)
|
||||
size = checkbox->base.x2 - checkbox->base.x1; //use width a as size
|
||||
if(checkbox->base.y2>checkbox->base.y1)
|
||||
{
|
||||
if((checkbox->base.y2 - checkbox->base.y1)>size) //height is larger than size
|
||||
size = checkbox->base.y2 - checkbox->base.y1; //use height as size
|
||||
}
|
||||
if(size==0) { //no size found (maybe swap x2 and x1 or y2 and y1 ?)
|
||||
return false; //signal error
|
||||
}
|
||||
if((size&0x01)) //the size is an odd number
|
||||
size++; //make size an even number
|
||||
|
||||
//Correct x2,y2 so that the checkbox is quadratic
|
||||
checkbox->base.x2 = checkbox->base.x1 + size;
|
||||
checkbox->base.y2 = checkbox->base.y1 + size;
|
||||
|
||||
gui_checkbox_redraw(checkbox);//Call redraw method, which will take care of the drawing of the entire checkbox
|
||||
|
||||
return touch_register_area(&checkbox->base); //Register the touch area and receive events for this checkbox, from now on
|
||||
}
|
||||
|
||||
return false; //no more touch areas left
|
||||
}
|
||||
|
||||
void gui_checkbox_redraw(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
//Draw background and border
|
||||
tft_fill_rectangle(checkbox->base.x1+1,checkbox->base.y1+1,checkbox->base.x2-1,checkbox->base.y2-1,BACKGROUND_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1,checkbox->base.y1,checkbox->base.x2,checkbox->base.y2,BORDER_COLOR);
|
||||
|
||||
if(checkbox->checked) { //checkbox is currently checked
|
||||
gui_checkbox_update(checkbox); //Call update method which will draw the tickmark
|
||||
}
|
||||
}
|
||||
|
||||
void gui_checkbox_remove(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
//We only need to unregister the touch area, as we have not allocated anything else
|
||||
touch_unregister_area((TOUCH_AREA_STRUCT*)checkbox);
|
||||
}
|
||||
|
||||
void gui_checkbox_update(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
unsigned int c = (checkbox->checked)? checkbox->fgcolor:BACKGROUND_COLOR; //color to use for the tickmark
|
||||
|
||||
//helper points inside the checkbox
|
||||
unsigned int xcent = checkbox->base.x1+(checkbox->base.x2-checkbox->base.x1)*6/14;
|
||||
unsigned int yleft = checkbox->base.y2 - (xcent- checkbox->base.x1) - 1 ;
|
||||
unsigned int yright = checkbox->base.y2 - (checkbox->base.x2 - xcent) - 1 ;
|
||||
unsigned int ybot = checkbox->base.y2 - 4;
|
||||
|
||||
//Draw tickmark as a 3pixel wide line
|
||||
tft_draw_line(checkbox->base.x1+3,yleft-1,xcent,ybot -1,c);
|
||||
tft_draw_line(checkbox->base.x1+3,yleft,xcent,ybot ,c);
|
||||
tft_draw_line(checkbox->base.x1+3,yleft+1,xcent,ybot + 1,c);
|
||||
xcent++;
|
||||
ybot--;
|
||||
tft_draw_line(xcent,ybot-1,checkbox->base.x2-3,yright-1,c);
|
||||
tft_draw_line(xcent,ybot,checkbox->base.x2-3,yright+0,c);
|
||||
tft_draw_line(xcent,ybot+1,checkbox->base.x2-3,yright+1,c);
|
||||
}
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/checkbox.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com b300ac5 Added Checkbox support
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "checkbox.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* The idea is as follows:
|
||||
* When the user creates a checkbox we create a touch area for that region and wait for PEN_DOWN events.
|
||||
* Once the user puts the pen down in this area we'll redraw the checkbox with different shadows (feedback)
|
||||
* and we'll now wait on PEN_UP or PEN_LEAVE events.
|
||||
* If the user takes the pen away while in the area (PEN_UP), we toggle the checkbox and we call the provided user callback
|
||||
* Otherwise (PEN_LEAVE) we only restore the initial shadows
|
||||
*/
|
||||
|
||||
|
||||
#define ACTIVE_COLOR RGB(251,208,123) //shadow color (inside of border)
|
||||
#define BORDER_COLOR RGB(29,82,129) //1px border color
|
||||
#define BACKGROUND_COLOR WHITE //Background color
|
||||
|
||||
//Callback which is called when the user touches the touch-area we created for the checkbox
|
||||
void checkboxes_cb(void* touchArea, TOUCH_ACTION triggeredAction)
|
||||
{
|
||||
TOUCH_AREA_STRUCT* area = (TOUCH_AREA_STRUCT*)touchArea;
|
||||
CHECKBOX_STRUCT* checkbox = (CHECKBOX_STRUCT*)touchArea;
|
||||
|
||||
switch (triggeredAction) {
|
||||
case PEN_DOWN: //If the user touches the area for the "first time"
|
||||
area->hookedActions = PEN_UP | PEN_LEAVE; //for the future we only want PEN_UP and PEN_LEAVE events
|
||||
|
||||
//Draw active shadows
|
||||
tft_draw_rectangle(checkbox->base.x1 + 1, checkbox->base.y1 + 1, checkbox->base.x2 - 1, checkbox->base.y2 - 1, ACTIVE_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1 + 2, checkbox->base.y1 + 2, checkbox->base.x2 - 2, checkbox->base.y2 - 2, ACTIVE_COLOR);
|
||||
break;
|
||||
|
||||
case PEN_UP: //If the user took the pen away, while in the area (=toggle checkbox!)
|
||||
checkbox->checked = !checkbox->checked; //Toggle checkbox state
|
||||
gui_checkbox_update(checkbox); //redraw/overdraw tickmark
|
||||
|
||||
if (checkbox->callback != NULL) { //The user provided a callback
|
||||
checkbox->callback(checkbox, checkbox->checked); //Call the provided callback with the new checked state
|
||||
}
|
||||
|
||||
// no break statement here!
|
||||
case PEN_LEAVE: //if the user "slided out" of the area
|
||||
area->hookedActions = PEN_DOWN; //for the future we only want PEN_DOWN events
|
||||
|
||||
//Draw inactive shadows
|
||||
tft_draw_rectangle(checkbox->base.x1 + 1, checkbox->base.y1 + 1, checkbox->base.x2 - 1, checkbox->base.y2 - 1, BACKGROUND_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1 + 2, checkbox->base.y1 + 2, checkbox->base.x2 - 2, checkbox->base.y2 - 2, BACKGROUND_COLOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool gui_checkbox_add(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
if (touch_have_empty(1)) { //Check if the touch module can handle one additional area
|
||||
unsigned char size = 0;
|
||||
checkbox->base.hookedActions = PEN_DOWN; //At first we are interested in PEN_DOWN events
|
||||
checkbox->base.callback = checkboxes_cb; //Use our own callback for the touch area events
|
||||
|
||||
//Check the size of the checkbox
|
||||
if (checkbox->base.x2 > checkbox->base.x1) {
|
||||
size = checkbox->base.x2 - checkbox->base.x1; //use width a as size
|
||||
}
|
||||
|
||||
if (checkbox->base.y2 > checkbox->base.y1) {
|
||||
if ((checkbox->base.y2 - checkbox->base.y1) > size) { //height is larger than size
|
||||
size = checkbox->base.y2 - checkbox->base.y1; //use height as size
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0) { //no size found (maybe swap x2 and x1 or y2 and y1 ?)
|
||||
return false; //signal error
|
||||
}
|
||||
|
||||
if ((size & 0x01)) { //the size is an odd number
|
||||
size++; //make size an even number
|
||||
}
|
||||
|
||||
//Correct x2,y2 so that the checkbox is quadratic
|
||||
checkbox->base.x2 = checkbox->base.x1 + size;
|
||||
checkbox->base.y2 = checkbox->base.y1 + size;
|
||||
|
||||
gui_checkbox_redraw(checkbox);//Call redraw method, which will take care of the drawing of the entire checkbox
|
||||
|
||||
return touch_register_area(&checkbox->base); //Register the touch area and receive events for this checkbox, from now on
|
||||
}
|
||||
|
||||
return false; //no more touch areas left
|
||||
}
|
||||
|
||||
void gui_checkbox_redraw(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
//Draw background and border
|
||||
tft_fill_rectangle(checkbox->base.x1 + 1, checkbox->base.y1 + 1, checkbox->base.x2 - 1, checkbox->base.y2 - 1, BACKGROUND_COLOR);
|
||||
tft_draw_rectangle(checkbox->base.x1, checkbox->base.y1, checkbox->base.x2, checkbox->base.y2, BORDER_COLOR);
|
||||
|
||||
if (checkbox->checked) { //checkbox is currently checked
|
||||
gui_checkbox_update(checkbox); //Call update method which will draw the tickmark
|
||||
}
|
||||
}
|
||||
|
||||
void gui_checkbox_remove(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
//We only need to unregister the touch area, as we have not allocated anything else
|
||||
touch_unregister_area((TOUCH_AREA_STRUCT*)checkbox);
|
||||
}
|
||||
|
||||
void gui_checkbox_update(CHECKBOX_STRUCT* checkbox)
|
||||
{
|
||||
unsigned int c = (checkbox->checked) ? checkbox->fgcolor : BACKGROUND_COLOR; //color to use for the tickmark
|
||||
|
||||
//helper points inside the checkbox
|
||||
unsigned int xcent = checkbox->base.x1 + (checkbox->base.x2 - checkbox->base.x1) * 6 / 14;
|
||||
unsigned int yleft = checkbox->base.y2 - (xcent - checkbox->base.x1) - 1 ;
|
||||
unsigned int yright = checkbox->base.y2 - (checkbox->base.x2 - xcent) - 1 ;
|
||||
unsigned int ybot = checkbox->base.y2 - 4;
|
||||
|
||||
//Draw tickmark as a 3pixel wide line
|
||||
tft_draw_line(checkbox->base.x1 + 3, yleft - 1, xcent, ybot - 1, c);
|
||||
tft_draw_line(checkbox->base.x1 + 3, yleft, xcent, ybot , c);
|
||||
tft_draw_line(checkbox->base.x1 + 3, yleft + 1, xcent, ybot + 1, c);
|
||||
xcent++;
|
||||
ybot--;
|
||||
tft_draw_line(xcent, ybot - 1, checkbox->base.x2 - 3, yright - 1, c);
|
||||
tft_draw_line(xcent, ybot, checkbox->base.x2 - 3, yright + 0, c);
|
||||
tft_draw_line(xcent, ybot + 1, checkbox->base.x2 - 3, yright + 1, c);
|
||||
}
|
||||
|
||||
@@ -1,70 +1,86 @@
|
||||
#ifndef CHECKBOX_H
|
||||
#define CHECKBOX_H
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
/**
|
||||
* @addtogroup gui
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup checkbox Checkbox
|
||||
* The Checkbox Gui-Element is a clickable, rectangular box with an optional tickmark inside of it.
|
||||
* When the checkbox is pressed and released it's tick state changes and you will be notified via the provided callback.
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup checkbox
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the checkbox state has changed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param checkbox The pointer to the CHECKBOX_STRUCT where to corresponding Checkbox has changed the state
|
||||
* @param checked A boolean which indicates whether the checkbox is now checked or not.
|
||||
*/
|
||||
typedef void (*CHECKBOX_CALLBACK)(void *checkbox, bool checked);
|
||||
|
||||
/**
|
||||
* Structure to configure the Checkbox
|
||||
*/
|
||||
typedef struct {
|
||||
TOUCH_AREA_STRUCT base; //!< Basic geometry of the Checkbox. You only need to set the x1, y1, x2, y2 members of this struct.
|
||||
uint16_t fgcolor; //!< The 16-bit color of the tickmark
|
||||
bool checked; //!< A boolean which indicates whether or not the checkbox is currently checked.
|
||||
CHECKBOX_CALLBACK callback; //!< Callback which is executed when the checkbox changes state
|
||||
} CHECKBOX_STRUCT;
|
||||
|
||||
/**
|
||||
* Adds a checkbox. Your Callback will be called from now on, if the checkbox changes state
|
||||
* @param checkbox A Pointer to the preinitialized CHECKBOX_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_checkbox_add(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Removes the checkbox. You will no longer receive events for this checkbox. This function will not overdraw the region where the checkbox was located.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_remove(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Updates the checkbox. Call this function when you change the state of the checkbox through code.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_update(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Redraws the checkbox. Call this method if you have to redraw the entire screen or if you want to draw a checkbox on top of an image.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_redraw(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
#define CHECKBOX_WIN_FG_COLOR RGB(32,161,34)
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* CHECKBOX_H */
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/checkbox.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com b300ac5 Added Checkbox support
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef CHECKBOX_H
|
||||
#define CHECKBOX_H
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
/**
|
||||
* @addtogroup gui
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup checkbox Checkbox
|
||||
* The Checkbox Gui-Element is a clickable, rectangular box with an optional tickmark inside of it.
|
||||
* When the checkbox is pressed and released it's tick state changes and you will be notified via the provided callback.
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup checkbox
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the checkbox state has changed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param checkbox The pointer to the CHECKBOX_STRUCT where to corresponding Checkbox has changed the state
|
||||
* @param checked A boolean which indicates whether the checkbox is now checked or not.
|
||||
*/
|
||||
typedef void (*CHECKBOX_CALLBACK)(void* checkbox, bool checked);
|
||||
|
||||
/**
|
||||
* Structure to configure the Checkbox
|
||||
*/
|
||||
typedef struct {
|
||||
TOUCH_AREA_STRUCT base; //!< Basic geometry of the Checkbox. You only need to set the x1, y1, x2, y2 members of this struct.
|
||||
uint16_t fgcolor; //!< The 16-bit color of the tickmark
|
||||
bool checked; //!< A boolean which indicates whether or not the checkbox is currently checked.
|
||||
CHECKBOX_CALLBACK callback; //!< Callback which is executed when the checkbox changes state
|
||||
} CHECKBOX_STRUCT;
|
||||
|
||||
/**
|
||||
* Adds a checkbox. Your Callback will be called from now on, if the checkbox changes state
|
||||
* @param checkbox A Pointer to the preinitialized CHECKBOX_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_checkbox_add(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Removes the checkbox. You will no longer receive events for this checkbox. This function will not overdraw the region where the checkbox was located.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_remove(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Updates the checkbox. Call this function when you change the state of the checkbox through code.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_update(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
/**
|
||||
* Redraws the checkbox. Call this method if you have to redraw the entire screen or if you want to draw a checkbox on top of an image.
|
||||
* @param checkbox A Pointer to the CHECKBOX_STRUCT
|
||||
*/
|
||||
void gui_checkbox_redraw(CHECKBOX_STRUCT* checkbox);
|
||||
|
||||
#define CHECKBOX_WIN_FG_COLOR RGB(32,161,34)
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* CHECKBOX_H */
|
||||
|
||||
@@ -1,143 +1,169 @@
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "button.h"
|
||||
#include "numupdown.h"
|
||||
#include <stdio.h> //for sprintf
|
||||
#include <stddef.h> //for offsetof macro
|
||||
#include <stdlib.h> //for abs
|
||||
|
||||
/* The idea is as follows:
|
||||
* When the user add's a numupdown we create two buttons, one with a plus and one with a minus sign in it
|
||||
* When the user presses one of the buttons we check and increase the value and execute the provided user callback
|
||||
*/
|
||||
|
||||
|
||||
#define BASE_COLOR RGB(90,90,90) //Background color for the whole element
|
||||
|
||||
//Callback which is called when the user presses the "plus" button
|
||||
void button_up_cb(void* button)
|
||||
{
|
||||
//Get the pointer to the numupdown: subtract the offset of the buttonUp member in the struct from the button pointer
|
||||
NUMUPDOWN_STRUCT* element = button-offsetof(NUMUPDOWN_STRUCT,buttonUp);
|
||||
|
||||
if(element->value<element->max) { //old value lies below the maximum
|
||||
element->value++; //let's increase the value
|
||||
gui_numupdown_update(element); //and redraw everything
|
||||
if(element->callback!=NULL) { //the user provided a callback
|
||||
element->callback(element,element->value); //Call the user callback with the new value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Callback which is called when the user presses the "minus" button
|
||||
void button_down_cb(void* button)
|
||||
{
|
||||
//Get the pointer to the numupdown: subtract the offset of the buttonDown member in the struct from the button pointer
|
||||
NUMUPDOWN_STRUCT* element = button-offsetof(NUMUPDOWN_STRUCT,buttonDown);
|
||||
|
||||
if(element->value>element->min) { //old value lies above the minimum
|
||||
element->value--; //let's decrease the value
|
||||
gui_numupdown_update(element); //and redraw everything
|
||||
if(element->callback!=NULL) { //the user provided a callback
|
||||
element->callback(element,element->value); //Call the user callback with the new value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Method to calculate the number of characters needed to print the provided number in decimal notation (with optional sign)
|
||||
static uint8_t calc_text_width(int16_t val) {
|
||||
uint8_t width = 1 + (val<0); //1 if positive, 2 if negative (to let space for sign)
|
||||
val=abs(val); //Make the number positive
|
||||
while(val>=10) { //while we have two or more digits
|
||||
val/=10; //remove one digit
|
||||
width++; //add one character
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
bool gui_numupdown_add(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
if(touch_have_empty(2)) //Check if the touch module can handle two additional areas
|
||||
{
|
||||
if(numupdown->min > numupdown->max) { //min is bigger than max?
|
||||
return false; //invalid parameter
|
||||
}
|
||||
|
||||
if(numupdown->value < numupdown->min) { //value is smaller than min?
|
||||
numupdown->value = numupdown->min; //normalize value
|
||||
} else if(numupdown->value > numupdown->max) { //value is bigger than max?
|
||||
numupdown->value = numupdown->max; //normalize value
|
||||
}
|
||||
|
||||
uint8_t tw1 = calc_text_width(numupdown->max); //Calculate character width to render maximum value
|
||||
uint8_t tw2 = calc_text_width(numupdown->min); //Calculate character width to render minimum value
|
||||
if(tw2 > tw1) tw1 = tw2; //ensure tw1 contains the larger number of the two
|
||||
uint8_t width= tft_font_width(0)*(tw1+1); //Calculate width of the number area
|
||||
|
||||
//Add "minus" button to the left side of the number area
|
||||
numupdown->buttonDown.base.x1=numupdown->x;
|
||||
numupdown->buttonDown.base.y1=numupdown->y;
|
||||
numupdown->buttonDown.base.x2=AUTO;
|
||||
numupdown->buttonDown.base.y2=numupdown->y+tft_font_height(0)*2;
|
||||
numupdown->buttonDown.text="-";
|
||||
numupdown->buttonDown.font=0;
|
||||
numupdown->buttonDown.bgcolor=BASE_COLOR;
|
||||
numupdown->buttonDown.txtcolor=WHITE;
|
||||
numupdown->buttonDown.callback = button_down_cb;
|
||||
gui_button_add(&numupdown->buttonDown);
|
||||
|
||||
//Add "plus" button to the right side of the number area
|
||||
numupdown->buttonUp.base.x1=numupdown->buttonDown.base.x2+width+2;
|
||||
numupdown->buttonUp.base.y1=numupdown->y;
|
||||
numupdown->buttonUp.base.x2=AUTO;
|
||||
numupdown->buttonUp.base.y2=numupdown->y +tft_font_height(0)*2;
|
||||
numupdown->buttonUp.text="+";
|
||||
numupdown->buttonUp.font=0;
|
||||
numupdown->buttonUp.bgcolor=BASE_COLOR;
|
||||
numupdown->buttonUp.txtcolor=WHITE;
|
||||
numupdown->buttonUp.callback = button_up_cb;
|
||||
gui_button_add(&numupdown->buttonUp);
|
||||
|
||||
//Draw background and label of the number area
|
||||
tft_fill_rectangle(numupdown->buttonDown.base.x2+2,numupdown->y,numupdown->buttonDown.base.x2+width,numupdown->buttonUp.base.y2,BASE_COLOR);
|
||||
tft_print_formatted(numupdown->buttonDown.base.x2+2+tft_font_width(0)/2,numupdown->y+tft_font_height(0)/2,numupdown->fgcolor,BASE_COLOR,0,"%*d",tw1,numupdown->value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; //not enough touch areas left
|
||||
}
|
||||
|
||||
void gui_numupdown_remove(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//remove the two buttons, we have no other allocated resources
|
||||
gui_button_remove(&numupdown->buttonUp);
|
||||
gui_button_remove(&numupdown->buttonDown);
|
||||
}
|
||||
|
||||
|
||||
void gui_numupdown_redraw(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//redraw the two buttons
|
||||
gui_button_redraw(&numupdown->buttonUp);
|
||||
gui_button_redraw(&numupdown->buttonDown);
|
||||
|
||||
//call update method which will take care of the number-area rendering
|
||||
gui_numupdown_update(numupdown);
|
||||
}
|
||||
|
||||
void gui_numupdown_update(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//Calculate the number area width again (see above)
|
||||
uint8_t tw1 = calc_text_width(numupdown->max);
|
||||
uint8_t tw2 = calc_text_width(numupdown->min);
|
||||
if(tw2 > tw1) tw1 = tw2;
|
||||
uint8_t width= tft_font_width(0)*(tw1+1);
|
||||
|
||||
//Draw background and label of the number area
|
||||
tft_fill_rectangle(numupdown->buttonDown.base.x2+2,numupdown->y,numupdown->buttonDown.base.x2+width,numupdown->buttonUp.base.y2,BASE_COLOR);
|
||||
tft_print_formatted(numupdown->buttonDown.base.x2+2+tft_font_width(0)/2,numupdown->y+tft_font_height(0)/2,numupdown->fgcolor,BASE_COLOR,0,"%*d",tw1,numupdown->value);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/numupdown.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-30 timolang@gmail.com 76ea9d8 Added num up down support.
|
||||
* 2015-04-30 timolang@gmail.com b491b78 Made numupdown horizontal
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
#include "button.h"
|
||||
#include "numupdown.h"
|
||||
#include <stdio.h> //for sprintf
|
||||
#include <stddef.h> //for offsetof macro
|
||||
#include <stdlib.h> //for abs
|
||||
|
||||
/* The idea is as follows:
|
||||
* When the user add's a numupdown we create two buttons, one with a plus and one with a minus sign in it
|
||||
* When the user presses one of the buttons we check and increase the value and execute the provided user callback
|
||||
*/
|
||||
|
||||
|
||||
#define BASE_COLOR RGB(90,90,90) //Background color for the whole element
|
||||
|
||||
//Callback which is called when the user presses the "plus" button
|
||||
void button_up_cb(void* button)
|
||||
{
|
||||
//Get the pointer to the numupdown: subtract the offset of the buttonUp member in the struct from the button pointer
|
||||
NUMUPDOWN_STRUCT* element = button - offsetof(NUMUPDOWN_STRUCT, buttonUp);
|
||||
|
||||
if (element->value < element->max) { //old value lies below the maximum
|
||||
element->value++; //let's increase the value
|
||||
gui_numupdown_update(element); //and redraw everything
|
||||
|
||||
if (element->callback != NULL) { //the user provided a callback
|
||||
element->callback(element, element->value); //Call the user callback with the new value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Callback which is called when the user presses the "minus" button
|
||||
void button_down_cb(void* button)
|
||||
{
|
||||
//Get the pointer to the numupdown: subtract the offset of the buttonDown member in the struct from the button pointer
|
||||
NUMUPDOWN_STRUCT* element = button - offsetof(NUMUPDOWN_STRUCT, buttonDown);
|
||||
|
||||
if (element->value > element->min) { //old value lies above the minimum
|
||||
element->value--; //let's decrease the value
|
||||
gui_numupdown_update(element); //and redraw everything
|
||||
|
||||
if (element->callback != NULL) { //the user provided a callback
|
||||
element->callback(element, element->value); //Call the user callback with the new value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Method to calculate the number of characters needed to print the provided number in decimal notation (with optional sign)
|
||||
static uint8_t calc_text_width(int16_t val)
|
||||
{
|
||||
uint8_t width = 1 + (val < 0); //1 if positive, 2 if negative (to let space for sign)
|
||||
val = abs(val); //Make the number positive
|
||||
|
||||
while (val >= 10) { //while we have two or more digits
|
||||
val /= 10; //remove one digit
|
||||
width++; //add one character
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
bool gui_numupdown_add(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
if (touch_have_empty(2)) { //Check if the touch module can handle two additional areas
|
||||
if (numupdown->min > numupdown->max) { //min is bigger than max?
|
||||
return false; //invalid parameter
|
||||
}
|
||||
|
||||
if (numupdown->value < numupdown->min) { //value is smaller than min?
|
||||
numupdown->value = numupdown->min; //normalize value
|
||||
} else if (numupdown->value > numupdown->max) { //value is bigger than max?
|
||||
numupdown->value = numupdown->max; //normalize value
|
||||
}
|
||||
|
||||
uint8_t tw1 = calc_text_width(numupdown->max); //Calculate character width to render maximum value
|
||||
uint8_t tw2 = calc_text_width(numupdown->min); //Calculate character width to render minimum value
|
||||
|
||||
if (tw2 > tw1) {
|
||||
tw1 = tw2; //ensure tw1 contains the larger number of the two
|
||||
}
|
||||
|
||||
uint8_t width = tft_font_width(0) * (tw1 + 1); //Calculate width of the number area
|
||||
|
||||
//Add "minus" button to the left side of the number area
|
||||
numupdown->buttonDown.base.x1 = numupdown->x;
|
||||
numupdown->buttonDown.base.y1 = numupdown->y;
|
||||
numupdown->buttonDown.base.x2 = AUTO;
|
||||
numupdown->buttonDown.base.y2 = numupdown->y + tft_font_height(0) * 2;
|
||||
numupdown->buttonDown.text = "-";
|
||||
numupdown->buttonDown.font = 0;
|
||||
numupdown->buttonDown.bgcolor = BASE_COLOR;
|
||||
numupdown->buttonDown.txtcolor = WHITE;
|
||||
numupdown->buttonDown.callback = button_down_cb;
|
||||
gui_button_add(&numupdown->buttonDown);
|
||||
|
||||
//Add "plus" button to the right side of the number area
|
||||
numupdown->buttonUp.base.x1 = numupdown->buttonDown.base.x2 + width + 2;
|
||||
numupdown->buttonUp.base.y1 = numupdown->y;
|
||||
numupdown->buttonUp.base.x2 = AUTO;
|
||||
numupdown->buttonUp.base.y2 = numupdown->y + tft_font_height(0) * 2;
|
||||
numupdown->buttonUp.text = "+";
|
||||
numupdown->buttonUp.font = 0;
|
||||
numupdown->buttonUp.bgcolor = BASE_COLOR;
|
||||
numupdown->buttonUp.txtcolor = WHITE;
|
||||
numupdown->buttonUp.callback = button_up_cb;
|
||||
gui_button_add(&numupdown->buttonUp);
|
||||
|
||||
//Draw background and label of the number area
|
||||
tft_fill_rectangle(numupdown->buttonDown.base.x2 + 2, numupdown->y, numupdown->buttonDown.base.x2 + width, numupdown->buttonUp.base.y2, BASE_COLOR);
|
||||
tft_print_formatted(numupdown->buttonDown.base.x2 + 2 + tft_font_width(0) / 2, numupdown->y + tft_font_height(0) / 2, numupdown->fgcolor, BASE_COLOR, 0, "%*d", tw1, numupdown->value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; //not enough touch areas left
|
||||
}
|
||||
|
||||
void gui_numupdown_remove(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//remove the two buttons, we have no other allocated resources
|
||||
gui_button_remove(&numupdown->buttonUp);
|
||||
gui_button_remove(&numupdown->buttonDown);
|
||||
}
|
||||
|
||||
|
||||
void gui_numupdown_redraw(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//redraw the two buttons
|
||||
gui_button_redraw(&numupdown->buttonUp);
|
||||
gui_button_redraw(&numupdown->buttonDown);
|
||||
|
||||
//call update method which will take care of the number-area rendering
|
||||
gui_numupdown_update(numupdown);
|
||||
}
|
||||
|
||||
void gui_numupdown_update(NUMUPDOWN_STRUCT* numupdown)
|
||||
{
|
||||
//Calculate the number area width again (see above)
|
||||
uint8_t tw1 = calc_text_width(numupdown->max);
|
||||
uint8_t tw2 = calc_text_width(numupdown->min);
|
||||
|
||||
if (tw2 > tw1) {
|
||||
tw1 = tw2;
|
||||
}
|
||||
|
||||
uint8_t width = tft_font_width(0) * (tw1 + 1);
|
||||
|
||||
//Draw background and label of the number area
|
||||
tft_fill_rectangle(numupdown->buttonDown.base.x2 + 2, numupdown->y, numupdown->buttonDown.base.x2 + width, numupdown->buttonUp.base.y2, BASE_COLOR);
|
||||
tft_print_formatted(numupdown->buttonDown.base.x2 + 2 + tft_font_width(0) / 2, numupdown->y + tft_font_height(0) / 2, numupdown->fgcolor, BASE_COLOR, 0, "%*d", tw1, numupdown->value);
|
||||
}
|
||||
|
||||
@@ -1,73 +1,88 @@
|
||||
#ifndef NUMUPDOWN_H
|
||||
#define NUMUPDOWN_H
|
||||
|
||||
#include "button.h"
|
||||
|
||||
/**
|
||||
* @addtogroup gui
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup numupdown NummericUpDown
|
||||
* The NummericUpDown Gui Element
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup numupdown
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the NummericUpDown value has changed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param numupdown The pointer to the NUMUPDOWN_STRUCT where to corresponding NummericUpDown has changed it's value
|
||||
* @param value The new value of the NummericUpDown
|
||||
*/
|
||||
typedef void (*NUMUPDOWN_CALLBACK)(void *numupdown, int16_t value);
|
||||
|
||||
/**
|
||||
* Structure to configure the NummericUpDown
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t x; //!< The x-Coordinate of the Top-Left Starting Point.
|
||||
uint16_t y; //!< The y-Coordinate of the Top-Left Starting Point.
|
||||
uint16_t fgcolor; //!< The 16-bit color of the value-text
|
||||
int16_t value; //!< The current/default value
|
||||
int16_t min; //!< The minimum possible value (inclusive)
|
||||
int16_t max; //!< The maximum possible value (inclusive)
|
||||
NUMUPDOWN_CALLBACK callback; //!< Callback which is executed when the value changes
|
||||
|
||||
BUTTON_STRUCT buttonUp; //!< For internal use, don't change, don't initialize
|
||||
BUTTON_STRUCT buttonDown; //!< For internal use, don't change, don't initialize
|
||||
} NUMUPDOWN_STRUCT;
|
||||
|
||||
/**
|
||||
* Adds a NummericUpDown. Your Callback will be called from now on, if the numupdown's value changes
|
||||
* @param numupdown A Pointer to the preinitialized NUMUPDOWN_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_numupdown_add(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Removes the NummericUpDown. You will no longer receive events for this numupdown. This function will not overdraw the region where the numupdown was located.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_remove(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Updates the NummericUpDown. Call this function when you change the value/min/max of the numupdown through code.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_update(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Redraws the NummericUpDown. Call this method if you have to redraw the entire screen or if you want to draw a numupdown on top of an image.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_redraw(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* NUMUPDOWN_H */
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/numupdown.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-30 timolang@gmail.com 76ea9d8 Added num up down support.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef NUMUPDOWN_H
|
||||
#define NUMUPDOWN_H
|
||||
|
||||
#include "button.h"
|
||||
|
||||
/**
|
||||
* @addtogroup gui
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* @defgroup numupdown NummericUpDown
|
||||
* The NummericUpDown Gui Element
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup numupdown
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Prototype for Event Listeners (called when the NummericUpDown value has changed)
|
||||
* \note You should NOT execute long running things in this callback nor should you update the gui. But you can call gui_screen_navigate() for instance.
|
||||
* @param numupdown The pointer to the NUMUPDOWN_STRUCT where to corresponding NummericUpDown has changed it's value
|
||||
* @param value The new value of the NummericUpDown
|
||||
*/
|
||||
typedef void (*NUMUPDOWN_CALLBACK)(void* numupdown, int16_t value);
|
||||
|
||||
/**
|
||||
* Structure to configure the NummericUpDown
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t x; //!< The x-Coordinate of the Top-Left Starting Point.
|
||||
uint16_t y; //!< The y-Coordinate of the Top-Left Starting Point.
|
||||
uint16_t fgcolor; //!< The 16-bit color of the value-text
|
||||
int16_t value; //!< The current/default value
|
||||
int16_t min; //!< The minimum possible value (inclusive)
|
||||
int16_t max; //!< The maximum possible value (inclusive)
|
||||
NUMUPDOWN_CALLBACK callback; //!< Callback which is executed when the value changes
|
||||
|
||||
BUTTON_STRUCT buttonUp; //!< For internal use, don't change, don't initialize
|
||||
BUTTON_STRUCT buttonDown; //!< For internal use, don't change, don't initialize
|
||||
} NUMUPDOWN_STRUCT;
|
||||
|
||||
/**
|
||||
* Adds a NummericUpDown. Your Callback will be called from now on, if the numupdown's value changes
|
||||
* @param numupdown A Pointer to the preinitialized NUMUPDOWN_STRUCT
|
||||
* @return true on success
|
||||
*/
|
||||
bool gui_numupdown_add(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Removes the NummericUpDown. You will no longer receive events for this numupdown. This function will not overdraw the region where the numupdown was located.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_remove(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Updates the NummericUpDown. Call this function when you change the value/min/max of the numupdown through code.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_update(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/**
|
||||
* Redraws the NummericUpDown. Call this method if you have to redraw the entire screen or if you want to draw a numupdown on top of an image.
|
||||
* @param numupdown A Pointer to the NUMUPDOWN_STRUCT
|
||||
*/
|
||||
void gui_numupdown_redraw(NUMUPDOWN_STRUCT* numupdown);
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* NUMUPDOWN_H */
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/screen.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-04-27 timolang@gmail.com 77e6d0e Fixed screen implementation.
|
||||
* 2015-05-10 timolang@gmail.com b6ab7c8 Fixed compiler warning in tft and screen module.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
* 2015-06-06 timolang@gmail.com c06661d Fixed some outdated comments in source code. Documented Gui Module in docu.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/* The idea is as follows:
|
||||
@@ -14,62 +32,79 @@ static SCREEN_STRUCT* screen_list = NULL; //Head of the linked list which stores
|
||||
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
|
||||
|
||||
SCREEN_STRUCT* gui_screen_get_current() {
|
||||
return screen_current;
|
||||
SCREEN_STRUCT* gui_screen_get_current()
|
||||
{
|
||||
return screen_current;
|
||||
}
|
||||
|
||||
|
||||
void gui_screen_update() {
|
||||
if(screen_goto!=NULL) { //we received the task to switch the screen
|
||||
SCREEN_STRUCT* go = (SCREEN_STRUCT*) screen_goto; //Backup volatile variable
|
||||
screen_goto=NULL; //reset the "goto instruction", since we're processing it now
|
||||
if(go->next!=NULL) { //The screen is not the last in the list, so we're going back
|
||||
if(go->next!=screen_current) { //this condition should always be false
|
||||
return; //list corrupted?
|
||||
}
|
||||
screen_current->on_leave(screen_current); //let the current screen free/unregister it's resources
|
||||
go->next=NULL; //remove the current screen from the list
|
||||
} else { //we're going forward (to a new screen)
|
||||
if(screen_current!=NULL) { //this is not the first screen
|
||||
screen_current->on_leave(screen_current); //let the current screen free/unregister it's resources
|
||||
screen_current->next = go; //append the new screen to the end of the list
|
||||
} else { //first screen ever seen
|
||||
screen_list=go; //set the new screen as list-head
|
||||
}
|
||||
}
|
||||
go->on_enter(go); //let the new screen allocate/register it's resources
|
||||
screen_current = go; //the new screen is now the current screen. Transition done
|
||||
}
|
||||
void gui_screen_update()
|
||||
{
|
||||
if (screen_goto != NULL) { //we received the task to switch the screen
|
||||
SCREEN_STRUCT* go = (SCREEN_STRUCT*) screen_goto; //Backup volatile variable
|
||||
screen_goto = NULL; //reset the "goto instruction", since we're processing it now
|
||||
|
||||
if(screen_current!=NULL) { //A screen has been set
|
||||
screen_current->on_update(screen_current); //Update current screen
|
||||
}
|
||||
if (go->next != NULL) { //The screen is not the last in the list, so we're going back
|
||||
if (go->next != screen_current) { //this condition should always be false
|
||||
return; //list corrupted?
|
||||
}
|
||||
|
||||
screen_current->on_leave(screen_current); //let the current screen free/unregister it's resources
|
||||
go->next = NULL; //remove the current screen from the list
|
||||
} else { //we're going forward (to a new screen)
|
||||
if (screen_current != NULL) { //this is not the first screen
|
||||
screen_current->on_leave(screen_current); //let the current screen free/unregister it's resources
|
||||
screen_current->next = go; //append the new screen to the end of the list
|
||||
} else { //first screen ever seen
|
||||
screen_list = go; //set the new screen as list-head
|
||||
}
|
||||
}
|
||||
|
||||
go->on_enter(go); //let the new screen allocate/register it's resources
|
||||
screen_current = go; //the new screen is now the current screen. Transition done
|
||||
}
|
||||
|
||||
if (screen_current != NULL) { //A screen has been set
|
||||
screen_current->on_update(screen_current); //Update current screen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool gui_screen_navigate(SCREEN_STRUCT* screen) {
|
||||
if(screen==NULL || screen==screen_current || screen==screen_goto) { //invalid argument passed
|
||||
return false;
|
||||
}
|
||||
screen->next = NULL; //this will become the new tail of the list, so the next pointer must be NULL
|
||||
screen_goto=screen; //"send message" to main loop, to switch the screen
|
||||
return true;
|
||||
bool gui_screen_navigate(SCREEN_STRUCT* screen)
|
||||
{
|
||||
if (screen == NULL || screen == screen_current || screen == screen_goto) { //invalid argument passed
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->next = NULL; //this will become the new tail of the list, so the next pointer must be NULL
|
||||
screen_goto = screen; //"send message" to main loop, to switch the screen
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gui_screen_back() {
|
||||
if(screen_list==NULL) { //the list head is emtpy, nothing to go back to
|
||||
return false;
|
||||
}
|
||||
SCREEN_STRUCT* current = screen_list;
|
||||
SCREEN_STRUCT* last = NULL;
|
||||
//Find second last element in list
|
||||
while(current->next != NULL) {
|
||||
last = current;
|
||||
current = current->next;
|
||||
}
|
||||
if(last==NULL) return false; //There's only a single screen, there's no going back here
|
||||
if(current!=screen_current) return false; //The last entry in the list is not the current screen. List corrupted?
|
||||
screen_goto=last; //"send message" to main loop, to switch the screen
|
||||
return true;
|
||||
bool gui_screen_back()
|
||||
{
|
||||
if (screen_list == NULL) { //the list head is emtpy, nothing to go back to
|
||||
return false;
|
||||
}
|
||||
|
||||
SCREEN_STRUCT* current = screen_list;
|
||||
SCREEN_STRUCT* last = NULL;
|
||||
|
||||
//Find second last element in list
|
||||
while (current->next != NULL) {
|
||||
last = current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (last == NULL) {
|
||||
return false; //There's only a single screen, there's no going back here
|
||||
}
|
||||
|
||||
if (current != screen_current) {
|
||||
return false; //The last entry in the list is not the current screen. List corrupted?
|
||||
}
|
||||
|
||||
screen_goto = last; //"send message" to main loop, to switch the screen
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/gui/screen.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-04-27 timolang@gmail.com 77e6d0e Fixed screen implementation.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
* 2015-06-06 timolang@gmail.com c06661d Fixed some outdated comments in source code. Documented Gui Module in docu.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef SCREEN_H
|
||||
#define SCREEN_H
|
||||
|
||||
@@ -12,7 +30,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.
|
||||
*/
|
||||
/*@}*/
|
||||
@@ -31,12 +49,12 @@ typedef void (*SCREEN_CALLBACK)(void* screen);
|
||||
/**
|
||||
* Structure to configure the Screen
|
||||
*/
|
||||
typedef struct SCREEN_S{
|
||||
SCREEN_CALLBACK on_enter; //!< The Callback which is called when the screen is entered. Add/Register all UI-Elements here
|
||||
SCREEN_CALLBACK on_leave; //!< The Callback which is called when the screen is left. Remove/Unregister all UI-Elements here
|
||||
SCREEN_CALLBACK on_update; //!< The Callback which is called repeatedly when the screen should be updated. Update/Redraw all UI-Elements here
|
||||
typedef struct SCREEN_S {
|
||||
SCREEN_CALLBACK on_enter; //!< The Callback which is called when the screen is entered. Add/Register all UI-Elements here
|
||||
SCREEN_CALLBACK on_leave; //!< The Callback which is called when the screen is left. Remove/Unregister all UI-Elements here
|
||||
SCREEN_CALLBACK on_update; //!< The Callback which is called repeatedly when the screen should be updated. Update/Redraw all UI-Elements here
|
||||
|
||||
struct SCREEN_S* next; //!< Used internally. do not modify, do not initialize
|
||||
struct SCREEN_S* next; //!< Used internally. do not modify, do not initialize
|
||||
} SCREEN_STRUCT;
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/lowlevel/ll_filesystem.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-05-10 timolang@gmail.com e2bce8f Added filesystem module, tests and implementation for it in emulator.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "filesystem.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/lowlevel/ll_system.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com cab8609 Integrated pixy into emulator. Pixy is no longer in the common/libs folder but in emulator/libs and discovery/libs
|
||||
* 2015-04-03 timolang@gmail.com 9a1d12a Refactored discovery, to use new project structure. Almost ready.
|
||||
* 2015-04-25 timolang@gmail.com 3d1e4b2 Simplified code a bit. Emulator does not work stable when replugging pixy.
|
||||
* 2015-04-25 timolang@gmail.com 0858b0d Fixed some bugs when receiving large data.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/lowlevel/ll_tft.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com 9a1d12a Refactored discovery, to use new project structure. Almost ready.
|
||||
* 2015-04-03 timolang@gmail.com 1aa9194 Fixed Drawing of rects in Emulator. Got frames from pixy to emulator. Slooooow.
|
||||
* 2015-04-27 aaron@duckpond.ch aed90ef Drawcircle added (emulator)
|
||||
* 2015-04-27 timolang@gmail.com e249fb2 Added font support
|
||||
* 2015-04-27 aaron@duckpond.ch f0a6c3b Implemented init functions for gpio, fsmc and display
|
||||
* 2015-04-27 aaron@duckpond.ch 0b61f21 Fixed misplacement of prototypes in ll_tft.h and implemented a propper init function.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -24,10 +45,10 @@ bool ll_tft_init();
|
||||
// draw functions
|
||||
void ll_tft_clear(uint16_t color);
|
||||
void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
||||
void ll_tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color);
|
||||
void ll_tft_draw_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);
|
||||
void ll_tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *dat);
|
||||
void ll_tft_draw_pixel(uint16_t x, uint16_t y, uint16_t color);
|
||||
void ll_tft_draw_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);
|
||||
void ll_tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t* dat);
|
||||
void ll_tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color);
|
||||
|
||||
|
||||
@@ -37,5 +58,3 @@ uint8_t ll_tft_font_width(uint8_t fontnum);
|
||||
void ll_tft_draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, char c);
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/lowlevel/ll_touch.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com 259d446 Added touch support to emulator. Implemented basic touch function.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/system/system.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com cab8609 Integrated pixy into emulator. Pixy is no longer in the common/libs folder but in emulator/libs and discovery/libs
|
||||
* 2015-04-25 timolang@gmail.com 3d1e4b2 Simplified code a bit. Emulator does not work stable when replugging pixy.
|
||||
* 2015-04-25 timolang@gmail.com 0858b0d Fixed some bugs when receiving large data.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "system.h"
|
||||
#include "ll_system.h"
|
||||
|
||||
|
||||
bool system_init() {
|
||||
return ll_system_init();
|
||||
bool system_init()
|
||||
{
|
||||
return ll_system_init();
|
||||
}
|
||||
|
||||
void system_delay(uint32_t msec) {
|
||||
ll_system_delay(msec);
|
||||
void system_delay(uint32_t msec)
|
||||
{
|
||||
ll_system_delay(msec);
|
||||
}
|
||||
|
||||
void system_process() {
|
||||
ll_system_process();
|
||||
void system_process()
|
||||
{
|
||||
ll_system_process();
|
||||
}
|
||||
|
||||
void system_toggle_led() {
|
||||
ll_system_toggle_led();
|
||||
void system_toggle_led()
|
||||
{
|
||||
ll_system_toggle_led();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/system/system.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com cab8609 Integrated pixy into emulator. Pixy is no longer in the common/libs folder but in emulator/libs and discovery/libs
|
||||
* 2015-04-25 timolang@gmail.com 3d1e4b2 Simplified code a bit. Emulator does not work stable when replugging pixy.
|
||||
* 2015-04-25 timolang@gmail.com 0858b0d Fixed some bugs when receiving large data.
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
|
||||
204
common/tft/tft.c
204
common/tft/tft.c
@@ -1,3 +1,24 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/tft/tft.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com 1aa9194 Fixed Drawing of rects in Emulator. Got frames from pixy to emulator. Slooooow.
|
||||
* 2015-04-27 aaron@duckpond.ch aed90ef Drawcircle added (emulator)
|
||||
* 2015-04-27 timolang@gmail.com e249fb2 Added font support
|
||||
* 2015-04-30 timolang@gmail.com 76ea9d8 Added num up down support.
|
||||
* 2015-05-10 timolang@gmail.com b6ab7c8 Fixed compiler warning in tft and screen module.
|
||||
* 2015-05-15 timolang@gmail.com b08a897 Added tft method to draw a bmp from filesystem. Added another font to emulator.
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "tft.h"
|
||||
#include "ll_tft.h"
|
||||
#include <string.h>
|
||||
@@ -15,129 +36,148 @@
|
||||
* For formatted printing implement putchar, instead of writing into a buffer and drawing that buffer afterwards
|
||||
*/
|
||||
|
||||
bool tft_init() {
|
||||
return ll_tft_init();
|
||||
bool tft_init()
|
||||
{
|
||||
return ll_tft_init();
|
||||
|
||||
}
|
||||
|
||||
void tft_clear(uint16_t color) {
|
||||
ll_tft_clear(color);
|
||||
void tft_clear(uint16_t color)
|
||||
{
|
||||
ll_tft_clear(color);
|
||||
}
|
||||
|
||||
void tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
|
||||
ll_tft_draw_line(x1,y1,x2,y2,color);
|
||||
void tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
ll_tft_draw_line(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
|
||||
void tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color) {
|
||||
ll_tft_draw_pixel(x,y,color);
|
||||
void tft_draw_pixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
ll_tft_draw_pixel(x, y, color);
|
||||
}
|
||||
|
||||
void tft_draw_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color) {
|
||||
//could be implemented with 4 lines instead of introducing a ll func
|
||||
ll_tft_draw_rectangle(x1,y1,x2,y2,color);
|
||||
void tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
//could be implemented with 4 lines instead of introducing a ll func
|
||||
ll_tft_draw_rectangle(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
void tft_fill_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color) {
|
||||
ll_tft_fill_rectangle(x1,y1,x2,y2,color);
|
||||
void tft_fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
||||
{
|
||||
ll_tft_fill_rectangle(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
void tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t* dat) {
|
||||
ll_tft_draw_bitmap_unscaled(x,y,width,height,dat);
|
||||
void tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t* dat)
|
||||
{
|
||||
ll_tft_draw_bitmap_unscaled(x, y, width, height, dat);
|
||||
}
|
||||
|
||||
void tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) {
|
||||
void tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color)
|
||||
{
|
||||
ll_tft_draw_circle(x, y, r, color);
|
||||
}
|
||||
|
||||
uint8_t tft_num_fonts() {
|
||||
return ll_tft_num_fonts();
|
||||
uint8_t tft_num_fonts()
|
||||
{
|
||||
return ll_tft_num_fonts();
|
||||
}
|
||||
|
||||
uint8_t tft_font_height(uint8_t fontnum) {
|
||||
return ll_tft_font_height(fontnum);
|
||||
uint8_t tft_font_height(uint8_t fontnum)
|
||||
{
|
||||
return ll_tft_font_height(fontnum);
|
||||
}
|
||||
|
||||
uint8_t tft_font_width(uint8_t fontnum) {
|
||||
return ll_tft_font_width(fontnum);
|
||||
uint8_t tft_font_width(uint8_t fontnum)
|
||||
{
|
||||
return ll_tft_font_width(fontnum);
|
||||
}
|
||||
|
||||
//Print line can be done with multiple calls to draw_char
|
||||
void tft_print_line(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, const char* text) {
|
||||
if(font>=ll_tft_num_fonts()) return; //invalid font index
|
||||
for(int i=0; i<strlen(text); i++) { //for each char in the line
|
||||
ll_tft_draw_char(x,y,color,bgcolor, font, text[i]); //draw the char
|
||||
x+=ll_tft_font_width(font); //and increase the x position
|
||||
}
|
||||
void tft_print_line(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, const char* text)
|
||||
{
|
||||
if (font >= ll_tft_num_fonts()) {
|
||||
return; //invalid font index
|
||||
}
|
||||
|
||||
for (int i = 0; i < strlen(text); i++) { //for each char in the line
|
||||
ll_tft_draw_char(x, y, color, bgcolor, font, text[i]); //draw the char
|
||||
x += ll_tft_font_width(font); //and increase the x position
|
||||
}
|
||||
}
|
||||
|
||||
//Printing a formatted line can be done by printing the line in a buffer using "sprintf" and then calling print_line
|
||||
void tft_print_formatted(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, const char* format, ...) {
|
||||
static char buffer[128]; //buffer to save the formatted text into
|
||||
void tft_print_formatted(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t font, const char* format, ...)
|
||||
{
|
||||
static char buffer[128]; //buffer to save the formatted text into
|
||||
|
||||
//Since we have variable arguments, we need to forward them. We have to use vsprintf instead of sprintf for that.
|
||||
va_list args;
|
||||
va_start (args, format); //start the varg-list
|
||||
vsprintf(buffer,format,args); //let vsprintf render the formatted string
|
||||
tft_print_line(x,y,color,bgcolor,font,buffer); //print the string as normal text
|
||||
va_end(args); //end the varg-list
|
||||
//Since we have variable arguments, we need to forward them. We have to use vsprintf instead of sprintf for that.
|
||||
va_list args;
|
||||
va_start(args, format); //start the varg-list
|
||||
vsprintf(buffer, format, args); //let vsprintf render the formatted string
|
||||
tft_print_line(x, y, color, bgcolor, font, buffer); //print the string as normal text
|
||||
va_end(args); //end the varg-list
|
||||
}
|
||||
|
||||
bool tft_draw_bitmap_file_unscaled(uint16_t x, uint16_t y, const char* filename) {
|
||||
//This method reads a .bmp file from the filesystem and tries to draw it.
|
||||
//Note: The bmp implementation is not complete, it has some limitations and it makes assumptions. See doxygen comment for this method.
|
||||
//Source Copied and adapted from: http://stackoverflow.com/a/17040962/2606757
|
||||
bool tft_draw_bitmap_file_unscaled(uint16_t x, uint16_t y, const char* filename)
|
||||
{
|
||||
//This method reads a .bmp file from the filesystem and tries to draw it.
|
||||
//Note: The bmp implementation is not complete, it has some limitations and it makes assumptions. See doxygen comment for this method.
|
||||
//Source Copied and adapted from: http://stackoverflow.com/a/17040962/2606757
|
||||
|
||||
FILE_HANDLE* file = filesystem_file_open(filename); //try to open the file
|
||||
if(file==NULL) { //file opening failed
|
||||
return false;
|
||||
}
|
||||
FILE_HANDLE* file = filesystem_file_open(filename); //try to open the file
|
||||
|
||||
unsigned char info[54];
|
||||
if(filesystem_file_read(file,info,54)!=F_OK) { //try to read the 54 byte header
|
||||
filesystem_file_close(file);
|
||||
return false; //reading the header failed
|
||||
}
|
||||
if (file == NULL) { //file opening failed
|
||||
return false;
|
||||
}
|
||||
|
||||
// extract image height and width from header
|
||||
uint32_t width = *(uint32_t*)&info[18]; //width in pixel
|
||||
uint32_t height = *(uint32_t*)&info[22]; //height in pixel
|
||||
uint16_t depth = *(uint16_t*)&info[28]; //bit's per pixel (color depth)
|
||||
depth/=8; //we want the number of bytes per pixel
|
||||
unsigned char info[54];
|
||||
|
||||
filesystem_file_seek(file,*(uint32_t*)&info[10]); //seek to the place where img data begins
|
||||
if (filesystem_file_read(file, info, 54) != F_OK) { //try to read the 54 byte header
|
||||
filesystem_file_close(file);
|
||||
return false; //reading the header failed
|
||||
}
|
||||
|
||||
uint32_t row_padded = (width*depth + 3) & (~3); //row size must be aligned to 4 bytes
|
||||
// extract image height and width from header
|
||||
uint32_t width = *(uint32_t*)&info[18]; //width in pixel
|
||||
uint32_t height = *(uint32_t*)&info[22]; //height in pixel
|
||||
uint16_t depth = *(uint16_t*)&info[28]; //bit's per pixel (color depth)
|
||||
depth /= 8; //we want the number of bytes per pixel
|
||||
|
||||
unsigned char data [row_padded]; //allocate space for one row (incl. padding)
|
||||
filesystem_file_seek(file, *(uint32_t*)&info[10]); //seek to the place where img data begins
|
||||
|
||||
for(int i = 0; i < height; i++) //for each row
|
||||
{
|
||||
filesystem_file_read(file,data,row_padded); //read row into buffer
|
||||
for(int j = 0; j < width*depth; j += depth) //for each pixel
|
||||
{
|
||||
unsigned char a,r,g,b;
|
||||
if(depth==4) { //a,r,g,b 8bit each
|
||||
a = data[j];
|
||||
r = data[j+1];
|
||||
g = data[j+2];
|
||||
b = data[j+3];
|
||||
} else if (depth==3) { // b,g,r, 8bit each
|
||||
a = 255;
|
||||
r = data[j+2];
|
||||
g = data[j+1];
|
||||
b = data[j];
|
||||
}
|
||||
uint32_t row_padded = (width * depth + 3) & (~3); //row size must be aligned to 4 bytes
|
||||
|
||||
if(a!=0) {
|
||||
//bmp's are stored "bottom-up", so we start drawing at the bottom
|
||||
tft_draw_pixel(x+j/depth,y+height-1-i,RGB(r,g,b));
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned char data [row_padded]; //allocate space for one row (incl. padding)
|
||||
|
||||
filesystem_file_close(file);
|
||||
for (int i = 0; i < height; i++) { //for each row
|
||||
filesystem_file_read(file, data, row_padded); //read row into buffer
|
||||
|
||||
return true;
|
||||
for (int j = 0; j < width * depth; j += depth) { //for each pixel
|
||||
unsigned char a, r, g, b;
|
||||
|
||||
if (depth == 4) { //a,r,g,b 8bit each
|
||||
a = data[j];
|
||||
r = data[j + 1];
|
||||
g = data[j + 2];
|
||||
b = data[j + 3];
|
||||
} else if (depth == 3) { // b,g,r, 8bit each
|
||||
a = 255;
|
||||
r = data[j + 2];
|
||||
g = data[j + 1];
|
||||
b = data[j];
|
||||
}
|
||||
|
||||
if (a != 0) {
|
||||
//bmp's are stored "bottom-up", so we start drawing at the bottom
|
||||
tft_draw_pixel(x + j / depth, y + height - 1 - i, RGB(r, g, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filesystem_file_close(file);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/tft/tft.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-04-03 timolang@gmail.com 1f2af9f Added more tft functions to common and emulator. Fixed eventloop.
|
||||
* 2015-04-03 timolang@gmail.com 1aa9194 Fixed Drawing of rects in Emulator. Got frames from pixy to emulator. Slooooow.
|
||||
* 2015-04-27 aaron@duckpond.ch aed90ef Drawcircle added (emulator)
|
||||
* 2015-04-27 timolang@gmail.com e249fb2 Added font support
|
||||
* 2015-04-30 timolang@gmail.com 76ea9d8 Added num up down support.
|
||||
* 2015-05-04 aaron@duckpond.ch c224d40 Changed display init
|
||||
* 2015-05-10 timolang@gmail.com 21edc56 Added doxyfile (doxygen) for the common folder. Started with doxygen comments for app and tft module.
|
||||
* 2015-05-11 timolang@gmail.com a175a2f Added doxygen docu for touch module
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-12 timolang@gmail.com 1402598 Added doxygen stuff for button module and some minor changes to touch, screen_main and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-05-15 timolang@gmail.com b08a897 Added tft method to draw a bmp from filesystem. Added another font to emulator.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef TFT_H
|
||||
#define TFT_H
|
||||
|
||||
@@ -69,7 +94,7 @@ void tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t
|
||||
* @param y The y-Coordinate of the pixel
|
||||
* @param color The 16-bit color to draw the pixel with
|
||||
*/
|
||||
void tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color);
|
||||
void tft_draw_pixel(uint16_t x, uint16_t y, uint16_t color);
|
||||
|
||||
/**
|
||||
* Draws the outline of a rectangle onto the display.
|
||||
@@ -80,7 +105,7 @@ void tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color);
|
||||
* @param y2 The y-Coordinate of the end-point
|
||||
* @param color The 16-bit color to draw the pixel with
|
||||
*/
|
||||
void tft_draw_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color);
|
||||
void tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
||||
|
||||
/**
|
||||
* Draws a filled rectangle onto the display. The start,end points are inclusive
|
||||
@@ -90,7 +115,7 @@ void tft_draw_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_
|
||||
* @param y2 The y-Coordinate of the end-point
|
||||
* @param color The 16-bit color to draw the pixel with
|
||||
*/
|
||||
void tft_fill_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color);
|
||||
void tft_fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
||||
|
||||
/**
|
||||
* Draws a bitmap onto the display without scaling/cropping.
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/touch/screen_calibrate.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-01 timolang@gmail.com 06227da Added calibrate screen (WIP). fixed bug in emulator drawing.
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen_calibrate.h"
|
||||
#include "tft.h"
|
||||
#include "touch.h"
|
||||
@@ -6,90 +20,102 @@
|
||||
extern volatile bool calibration; //from touch.c
|
||||
|
||||
|
||||
static void enter(void* screen) {
|
||||
tft_clear(BLACK);
|
||||
static void enter(void* screen)
|
||||
{
|
||||
tft_clear(BLACK);
|
||||
}
|
||||
|
||||
static void leave(void* screen) {
|
||||
static void leave(void* screen)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void update(void* screen) {
|
||||
int x1,y1,x2,y2,dx,dy;
|
||||
static void update(void* screen)
|
||||
{
|
||||
int x1, y1, x2, y2, dx, dy;
|
||||
|
||||
|
||||
tft_print_line(50,50,WHITE,BLACK,1,"Calibration:");
|
||||
tft_print_line(50,120,WHITE,BLACK,0,"Hit the markers exactly!");
|
||||
//-----------------First Point--------------------
|
||||
tft_draw_line(CCENTER,CBEGIN,CCENTER,CEND,WHITE); //Draw Cross
|
||||
tft_draw_line(CBEGIN,CCENTER,CEND,CCENTER,WHITE); //Draw Cross
|
||||
calibration=1; //TouchX + TouchY Values will not be converted to Pixels
|
||||
while(calibration); //Wait on PenUp
|
||||
POINT_STRUCT p1 = touch_get_last_point();
|
||||
x1=p1.x;
|
||||
y1=p1.y;
|
||||
tft_fill_rectangle(CBEGIN,CBEGIN,CEND,CEND,BLACK); //Clear Cross
|
||||
tft_print_line(50, 50, WHITE, BLACK, 1, "Calibration:");
|
||||
tft_print_line(50, 120, WHITE, BLACK, 0, "Hit the markers exactly!");
|
||||
//-----------------First Point--------------------
|
||||
tft_draw_line(CCENTER, CBEGIN, CCENTER, CEND, WHITE); //Draw Cross
|
||||
tft_draw_line(CBEGIN, CCENTER, CEND, CCENTER, WHITE); //Draw Cross
|
||||
calibration = 1; //TouchX + TouchY Values will not be converted to Pixels
|
||||
|
||||
//-----------------Second Point-------------------
|
||||
tft_draw_line(DWIDTH-CCENTER,DHEIGHT-CBEGIN,DWIDTH-CCENTER,DHEIGHT-CEND,WHITE);
|
||||
tft_draw_line(DWIDTH-CBEGIN,DHEIGHT-CCENTER,DWIDTH-CEND,DHEIGHT-CCENTER,WHITE);
|
||||
calibration=1;
|
||||
while(calibration);
|
||||
POINT_STRUCT p2 = touch_get_last_point();
|
||||
x2=p2.x;
|
||||
y2=p2.y;
|
||||
tft_fill_rectangle(DWIDTH-CBEGIN,DHEIGHT-CBEGIN,DWIDTH-CEND,DHEIGHT-CEND,BLACK);
|
||||
while (calibration); //Wait on PenUp
|
||||
|
||||
//-----------------Third Point--------------------
|
||||
tft_draw_line(CCENTER,DHEIGHT-CBEGIN,CCENTER,DHEIGHT-CEND,WHITE);
|
||||
tft_draw_line(CBEGIN,DHEIGHT-CCENTER,CEND,DHEIGHT-CCENTER,WHITE);
|
||||
calibration=1;
|
||||
while(calibration);
|
||||
POINT_STRUCT p3 = touch_get_last_point();
|
||||
x1+=p3.x; //Add(!) values. We'll build the average later
|
||||
y2+=p3.y;
|
||||
tft_fill_rectangle(CBEGIN,DHEIGHT-CBEGIN,CEND,DHEIGHT-CEND,BLACK);
|
||||
POINT_STRUCT p1 = touch_get_last_point();
|
||||
x1 = p1.x;
|
||||
y1 = p1.y;
|
||||
tft_fill_rectangle(CBEGIN, CBEGIN, CEND, CEND, BLACK); //Clear Cross
|
||||
|
||||
//------------------4. Point---------------------
|
||||
tft_draw_line(DWIDTH-CCENTER,CBEGIN,DWIDTH-CCENTER,CEND,WHITE);
|
||||
tft_draw_line(DWIDTH-CBEGIN,CCENTER,DWIDTH-CEND,CCENTER,WHITE);
|
||||
calibration=1;
|
||||
while(calibration);
|
||||
POINT_STRUCT p4 = touch_get_last_point();
|
||||
x2+=p4.x;
|
||||
y1+=p4.y;
|
||||
tft_fill_rectangle(DWIDTH-CBEGIN,CBEGIN,DWIDTH-CEND,CEND,BLACK);
|
||||
//-------------------Calculation---------------------
|
||||
x1++; //Add 1 and divide by 2 later = +0.5 (for correct rounding)
|
||||
y1++;
|
||||
x2++;
|
||||
y2++;
|
||||
x1>>=1; //Divide by 2
|
||||
y1>>=1;
|
||||
x2>>=1;
|
||||
y2>>=1;
|
||||
dx = (x2-x1); //Build the Difference
|
||||
dy = (y2-y1);
|
||||
//-----------------Second Point-------------------
|
||||
tft_draw_line(DWIDTH - CCENTER, DHEIGHT - CBEGIN, DWIDTH - CCENTER, DHEIGHT - CEND, WHITE);
|
||||
tft_draw_line(DWIDTH - CBEGIN, DHEIGHT - CCENTER, DWIDTH - CEND, DHEIGHT - CCENTER, WHITE);
|
||||
calibration = 1;
|
||||
|
||||
touch_set_calibration_values(x1,dx,y1,dy);
|
||||
tft_print_line(50,120,WHITE,BLACK,0,"Calibration Done. Press anywhere");
|
||||
while (calibration);
|
||||
|
||||
calibration=1;
|
||||
while(calibration);
|
||||
gui_screen_back();
|
||||
POINT_STRUCT p2 = touch_get_last_point();
|
||||
x2 = p2.x;
|
||||
y2 = p2.y;
|
||||
tft_fill_rectangle(DWIDTH - CBEGIN, DHEIGHT - CBEGIN, DWIDTH - CEND, DHEIGHT - CEND, BLACK);
|
||||
|
||||
//-----------------Third Point--------------------
|
||||
tft_draw_line(CCENTER, DHEIGHT - CBEGIN, CCENTER, DHEIGHT - CEND, WHITE);
|
||||
tft_draw_line(CBEGIN, DHEIGHT - CCENTER, CEND, DHEIGHT - CCENTER, WHITE);
|
||||
calibration = 1;
|
||||
|
||||
while (calibration);
|
||||
|
||||
POINT_STRUCT p3 = touch_get_last_point();
|
||||
x1 += p3.x; //Add(!) values. We'll build the average later
|
||||
y2 += p3.y;
|
||||
tft_fill_rectangle(CBEGIN, DHEIGHT - CBEGIN, CEND, DHEIGHT - CEND, BLACK);
|
||||
|
||||
//------------------4. Point---------------------
|
||||
tft_draw_line(DWIDTH - CCENTER, CBEGIN, DWIDTH - CCENTER, CEND, WHITE);
|
||||
tft_draw_line(DWIDTH - CBEGIN, CCENTER, DWIDTH - CEND, CCENTER, WHITE);
|
||||
calibration = 1;
|
||||
|
||||
while (calibration);
|
||||
|
||||
POINT_STRUCT p4 = touch_get_last_point();
|
||||
x2 += p4.x;
|
||||
y1 += p4.y;
|
||||
tft_fill_rectangle(DWIDTH - CBEGIN, CBEGIN, DWIDTH - CEND, CEND, BLACK);
|
||||
//-------------------Calculation---------------------
|
||||
x1++; //Add 1 and divide by 2 later = +0.5 (for correct rounding)
|
||||
y1++;
|
||||
x2++;
|
||||
y2++;
|
||||
x1 >>= 1; //Divide by 2
|
||||
y1 >>= 1;
|
||||
x2 >>= 1;
|
||||
y2 >>= 1;
|
||||
dx = (x2 - x1); //Build the Difference
|
||||
dy = (y2 - y1);
|
||||
|
||||
touch_set_calibration_values(x1, dx, y1, dy);
|
||||
tft_print_line(50, 120, WHITE, BLACK, 0, "Calibration Done. Press anywhere");
|
||||
|
||||
calibration = 1;
|
||||
|
||||
while (calibration);
|
||||
|
||||
gui_screen_back();
|
||||
|
||||
}
|
||||
|
||||
|
||||
static SCREEN_STRUCT screen = {
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
enter,
|
||||
leave,
|
||||
update
|
||||
};
|
||||
|
||||
|
||||
SCREEN_STRUCT* get_screen_calibrate() {
|
||||
return &screen;
|
||||
SCREEN_STRUCT* get_screen_calibrate()
|
||||
{
|
||||
return &screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/touch/screen_calibrate.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-06-01 timolang@gmail.com 06227da Added calibrate screen (WIP). fixed bug in emulator drawing.
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/touch/touch.c
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-27 timolang@gmail.com 259d446 Added touch support to emulator. Implemented basic touch function.
|
||||
* 2015-05-02 timolang@gmail.com 3281616 Added some more touch functions. Improved pixy test. Drag the Image around!
|
||||
* 2015-05-17 timolang@gmail.com 2d46336 Improved comments in implementation of button, checkbox, numupdown, tft, touch and screen modules/submodules.
|
||||
* 2015-06-01 timolang@gmail.com 06227da Added calibrate screen (WIP). fixed bug in emulator drawing.
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
* 2015-06-06 timolang@gmail.com c06661d Fixed some outdated comments in source code. Documented Gui Module in docu.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#include "touch.h"
|
||||
#include "ll_touch.h"
|
||||
#include "screen_calibrate.h"
|
||||
@@ -18,184 +36,179 @@
|
||||
TOUCH_AREA_STRUCT* areas[NUM_AREAS] = {NULL}; //list with pointers to all managed touch area's
|
||||
|
||||
volatile POINT_STRUCT pos; //the last touch point
|
||||
volatile TOUCH_STATE oldState=TOUCH_UP; //the last touch state
|
||||
volatile TOUCH_STATE oldState = TOUCH_UP; //the last touch state
|
||||
volatile bool calibration = false; //whether or not we're currently calibrating
|
||||
|
||||
bool use_calibration=false; //Whether or not the current platform needs calibration and recalc of the values
|
||||
bool use_calibration = false; //Whether or not the current platform needs calibration and recalc of the values
|
||||
|
||||
//Calibration parameters (dummy values).
|
||||
int cal_xs=10;
|
||||
int cal_dx=100;
|
||||
int cal_ys=10;
|
||||
int cal_dy=100;
|
||||
int cal_xs = 10;
|
||||
int cal_dx = 100;
|
||||
int cal_ys = 10;
|
||||
int cal_dy = 100;
|
||||
|
||||
|
||||
void touch_set_calibration_values(int xs, int dx, int ys, int dy) {
|
||||
cal_xs = xs;
|
||||
cal_ys = ys;
|
||||
cal_dx = dx;
|
||||
cal_dy = dy;
|
||||
void touch_set_calibration_values(int xs, int dx, int ys, int dy)
|
||||
{
|
||||
cal_xs = xs;
|
||||
cal_ys = ys;
|
||||
cal_dx = dx;
|
||||
cal_dy = dy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool touch_init() {
|
||||
return ll_touch_init();
|
||||
bool touch_init()
|
||||
{
|
||||
return ll_touch_init();
|
||||
}
|
||||
|
||||
void touch_set_value_convert_mode(bool uc) {
|
||||
use_calibration=uc;
|
||||
void touch_set_value_convert_mode(bool uc)
|
||||
{
|
||||
use_calibration = uc;
|
||||
}
|
||||
|
||||
|
||||
bool touch_add_raw_event(uint16_t touchX, uint16_t touchY, TOUCH_STATE state) {
|
||||
//Update current and old position/state
|
||||
bool penDown = (state==TOUCH_DOWN);
|
||||
bool oldPenDown = (oldState==TOUCH_DOWN);
|
||||
oldState=state;
|
||||
bool touch_add_raw_event(uint16_t touchX, uint16_t touchY, TOUCH_STATE state)
|
||||
{
|
||||
//Update current and old position/state
|
||||
bool penDown = (state == TOUCH_DOWN);
|
||||
bool oldPenDown = (oldState == TOUCH_DOWN);
|
||||
oldState = state;
|
||||
|
||||
if(calibration) //If in Calibration mode
|
||||
{
|
||||
if(penDown)
|
||||
{
|
||||
pos.x=touchX;
|
||||
pos.y=touchY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(oldPenDown) //Run only if we got at least one pen down
|
||||
calibration=0; //Calibration finish (Touch X and Y are the values from the last measure, where the pen was down)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (calibration) { //If in Calibration mode
|
||||
if (penDown) {
|
||||
pos.x = touchX;
|
||||
pos.y = touchY;
|
||||
} else {
|
||||
if (oldPenDown) { //Run only if we got at least one pen down
|
||||
calibration = 0; //Calibration finish (Touch X and Y are the values from the last measure, where the pen was down)
|
||||
}
|
||||
}
|
||||
|
||||
//If we reach this point we're not in calibration mode and we need to process the event and call the registred handlers..
|
||||
return true;
|
||||
}
|
||||
|
||||
if(use_calibration) { //the underlying touch hardware uses calibration
|
||||
//Calculate the real touch position out of the passed ones, and the calibration values
|
||||
pos.x=touchX=(((long)(DWIDTH-2*CCENTER)*2*(long)((long)touchX-cal_xs)/cal_dx+1)>>1)+CCENTER;
|
||||
pos.y=touchY=(((long)(DHEIGHT-2*CCENTER)*2*(long)((long)touchY-cal_ys)/cal_dy+1)>>1)+CCENTER;
|
||||
} else { //no conversion needed for the underlying hardware
|
||||
pos.x=touchX;
|
||||
pos.y=touchY;
|
||||
}
|
||||
//If we reach this point we're not in calibration mode and we need to process the event and call the registred handlers..
|
||||
|
||||
if(penDown) //pen is down now
|
||||
{
|
||||
//tft_draw_pixel(touchX,touchY,WHITE);
|
||||
if(!oldPenDown) //pen wasn't down before (positive edge) => First Touch
|
||||
{
|
||||
for(int z=0; z < NUM_AREAS; z++) // For every touch area
|
||||
{
|
||||
//Check if pos is inside area
|
||||
if(areas[z]!=NULL && touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2 )
|
||||
{
|
||||
areas[z]->flags=1; //Save PenInside=1
|
||||
if(areas[z]->hookedActions & PEN_DOWN) //The user wants to receive pen down events
|
||||
areas[z]->callback(areas[z],PEN_DOWN); //Send event to user callback
|
||||
}
|
||||
}
|
||||
}
|
||||
else //Pen was down before => Second, Third event in row
|
||||
{
|
||||
for(int z=0; z < NUM_AREAS; z++) // For every touch area
|
||||
{
|
||||
if(areas[z]!=NULL )
|
||||
{
|
||||
//Check if pos is inside area
|
||||
if(touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2)
|
||||
{
|
||||
if(areas[z]->flags==0) //Pen was not inside before (PenInside==0)
|
||||
{
|
||||
areas[z]->flags=1; //Pen is inside now (PenInside=1)
|
||||
if(areas[z]->hookedActions & PEN_ENTER) //The user wants to receive pen enter events
|
||||
areas[z]->callback(areas[z],PEN_ENTER);
|
||||
}
|
||||
}
|
||||
else if(areas[z]->flags) //Pos not inside area, but it was before (PenInside==1)
|
||||
{
|
||||
areas[z]->flags=0; //Pen is no longer inside (PenInside=0)
|
||||
if(areas[z]->hookedActions & PEN_LEAVE) //The user wants to receive pen leave events
|
||||
areas[z]->callback(areas[z],PEN_LEAVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int z=0; z < NUM_AREAS; z++) // For every touch area
|
||||
{
|
||||
if(areas[z]!=NULL && (areas[z]->hookedActions&PEN_MOVE)) //User want's to receive pen move events
|
||||
{
|
||||
//Check if pos is inside area
|
||||
if(touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2)
|
||||
{
|
||||
areas[z]->callback(areas[z],PEN_MOVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else //pen is not down now
|
||||
{
|
||||
if(oldPenDown) //but it was down before (negative edge)
|
||||
{
|
||||
for(int z=0; z < NUM_AREAS; z++) // For every touch area
|
||||
{
|
||||
//Check if pos is inside area
|
||||
if(areas[z]!=NULL && touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2 )
|
||||
{
|
||||
areas[z]->flags=0; //The pen is no longer inside (PenInside = 0);
|
||||
if(areas[z]->hookedActions & PEN_UP) //user want's to receive pen up events
|
||||
areas[z]->callback(areas[z],PEN_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (use_calibration) { //the underlying touch hardware uses calibration
|
||||
//Calculate the real touch position out of the passed ones, and the calibration values
|
||||
pos.x = touchX = (((long)(DWIDTH - 2 * CCENTER) * 2 * (long)((long)touchX - cal_xs) / cal_dx + 1) >> 1) + CCENTER;
|
||||
pos.y = touchY = (((long)(DHEIGHT - 2 * CCENTER) * 2 * (long)((long)touchY - cal_ys) / cal_dy + 1) >> 1) + CCENTER;
|
||||
} else { //no conversion needed for the underlying hardware
|
||||
pos.x = touchX;
|
||||
pos.y = touchY;
|
||||
}
|
||||
|
||||
if (penDown) { //pen is down now
|
||||
//tft_draw_pixel(touchX,touchY,WHITE);
|
||||
if (!oldPenDown) { //pen wasn't down before (positive edge) => First Touch
|
||||
for (int z = 0; z < NUM_AREAS; z++) { // For every touch area
|
||||
//Check if pos is inside area
|
||||
if (areas[z] != NULL && touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2) {
|
||||
areas[z]->flags = 1; //Save PenInside=1
|
||||
|
||||
if (areas[z]->hookedActions & PEN_DOWN) { //The user wants to receive pen down events
|
||||
areas[z]->callback(areas[z], PEN_DOWN); //Send event to user callback
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //Pen was down before => Second, Third event in row
|
||||
for (int z = 0; z < NUM_AREAS; z++) { // For every touch area
|
||||
if (areas[z] != NULL) {
|
||||
//Check if pos is inside area
|
||||
if (touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2) {
|
||||
if (areas[z]->flags == 0) { //Pen was not inside before (PenInside==0)
|
||||
areas[z]->flags = 1; //Pen is inside now (PenInside=1)
|
||||
|
||||
if (areas[z]->hookedActions & PEN_ENTER) { //The user wants to receive pen enter events
|
||||
areas[z]->callback(areas[z], PEN_ENTER);
|
||||
}
|
||||
}
|
||||
} else if (areas[z]->flags) { //Pos not inside area, but it was before (PenInside==1)
|
||||
areas[z]->flags = 0; //Pen is no longer inside (PenInside=0)
|
||||
|
||||
if (areas[z]->hookedActions & PEN_LEAVE) { //The user wants to receive pen leave events
|
||||
areas[z]->callback(areas[z], PEN_LEAVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int z = 0; z < NUM_AREAS; z++) { // For every touch area
|
||||
if (areas[z] != NULL && (areas[z]->hookedActions & PEN_MOVE)) { //User want's to receive pen move events
|
||||
//Check if pos is inside area
|
||||
if (touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2) {
|
||||
areas[z]->callback(areas[z], PEN_MOVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //pen is not down now
|
||||
if (oldPenDown) { //but it was down before (negative edge)
|
||||
for (int z = 0; z < NUM_AREAS; z++) { // For every touch area
|
||||
//Check if pos is inside area
|
||||
if (areas[z] != NULL && touchX >= areas[z]->x1 && touchX <= areas[z]->x2 && touchY >= areas[z]->y1 && touchY <= areas[z]->y2) {
|
||||
areas[z]->flags = 0; //The pen is no longer inside (PenInside = 0);
|
||||
|
||||
if (areas[z]->hookedActions & PEN_UP) { //user want's to receive pen up events
|
||||
areas[z]->callback(areas[z], PEN_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool touch_have_empty(unsigned char num)
|
||||
{
|
||||
//go through pointer array and check for free spaces
|
||||
for(unsigned char i=0; i<NUM_AREAS; i++)
|
||||
{
|
||||
if(areas[i]==NULL) num--; //a free space was found, we need one less
|
||||
if(num==0) return true; //enough free spaces found
|
||||
}
|
||||
return false; //not enough free spaces found
|
||||
//go through pointer array and check for free spaces
|
||||
for (unsigned char i = 0; i < NUM_AREAS; i++) {
|
||||
if (areas[i] == NULL) {
|
||||
num--; //a free space was found, we need one less
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
return true; //enough free spaces found
|
||||
}
|
||||
}
|
||||
|
||||
return false; //not enough free spaces found
|
||||
}
|
||||
|
||||
bool touch_register_area(TOUCH_AREA_STRUCT* area)
|
||||
{
|
||||
//go through pointer array and check for free space
|
||||
for(unsigned char i=0; i<NUM_AREAS; i++)
|
||||
{
|
||||
if(areas[i]==NULL) //free space found
|
||||
{
|
||||
area->flags=0; //we start with empty flags (PenInside=0)
|
||||
areas[i]=area; //save pointer into list
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; //no free space found
|
||||
//go through pointer array and check for free space
|
||||
for (unsigned char i = 0; i < NUM_AREAS; i++) {
|
||||
if (areas[i] == NULL) { //free space found
|
||||
area->flags = 0; //we start with empty flags (PenInside=0)
|
||||
areas[i] = area; //save pointer into list
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; //no free space found
|
||||
}
|
||||
|
||||
void touch_unregister_area(TOUCH_AREA_STRUCT* area)
|
||||
{
|
||||
if(area==NULL) return;
|
||||
if (area == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//go through pointer array and find the area to remove
|
||||
for(unsigned char i=0; i<NUM_AREAS; i++)
|
||||
{
|
||||
if(areas[i]==area) //area found in pointer array at pos i
|
||||
{
|
||||
areas[i]=NULL; //set pointer in list to NULL again
|
||||
break;
|
||||
}
|
||||
}
|
||||
//go through pointer array and find the area to remove
|
||||
for (unsigned char i = 0; i < NUM_AREAS; i++) {
|
||||
if (areas[i] == area) { //area found in pointer array at pos i
|
||||
areas[i] = NULL; //set pointer in list to NULL again
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
POINT_STRUCT touch_get_last_point() {
|
||||
return pos;
|
||||
POINT_STRUCT touch_get_last_point()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/**************************************************************************************************************************************
|
||||
* Project: discoverpixy
|
||||
* Website: https://github.com/t-moe/discoverpixy
|
||||
* Authors: Aaron Schmocker, Timo Lang
|
||||
* Institution: BFH Bern University of Applied Sciences
|
||||
* File: common/touch/touch.h
|
||||
*
|
||||
* Version History:
|
||||
* Date Autor Email SHA Changes
|
||||
* 2015-04-03 timolang@gmail.com 51089aa Refactored Project Structure for use with emulator
|
||||
* 2015-04-27 timolang@gmail.com 259d446 Added touch support to emulator. Implemented basic touch function.
|
||||
* 2015-04-27 timolang@gmail.com cf72baa Introduced a Screen (sub) module and divided app into multiple screens.
|
||||
* 2015-05-02 timolang@gmail.com 3281616 Added some more touch functions. Improved pixy test. Drag the Image around!
|
||||
* 2015-05-11 timolang@gmail.com a175a2f Added doxygen docu for touch module
|
||||
* 2015-05-11 timolang@gmail.com 08d9fe0 More work on doxygen module structure
|
||||
* 2015-05-12 timolang@gmail.com 1402598 Added doxygen stuff for button module and some minor changes to touch, screen_main and tft module.
|
||||
* 2015-05-15 timolang@gmail.com 9a16865 Added doxgen comments to filesyste, checkbox, numupdown and screen module. And some minor changes to the other modules.
|
||||
* 2015-06-01 timolang@gmail.com 06227da Added calibrate screen (WIP). fixed bug in emulator drawing.
|
||||
* 2015-06-01 timolang@gmail.com eb573bc Finalized calibration. Fixed a bug in screen module.
|
||||
*
|
||||
**************************************************************************************************************************************/
|
||||
|
||||
#ifndef TOUCH_H
|
||||
#define TOUCH_H
|
||||
|
||||
@@ -19,8 +41,8 @@
|
||||
Enum to describe the current Touch State. \sa touch_add_raw_event
|
||||
*/
|
||||
typedef enum {
|
||||
TOUCH_UP, //!< The display is currently not touched
|
||||
TOUCH_DOWN //!< The display is currently touched at some point
|
||||
TOUCH_UP, //!< The display is currently not touched
|
||||
TOUCH_DOWN //!< The display is currently touched at some point
|
||||
} TOUCH_STATE ;
|
||||
|
||||
/**
|
||||
@@ -28,12 +50,12 @@ typedef enum {
|
||||
* You can OR-combine them. \sa touch_register_area
|
||||
*/
|
||||
typedef enum {
|
||||
NONE=0x00, //!< Do not receive any events
|
||||
PEN_DOWN=0x01, //!< Receive an event when the pen goes down inside the region
|
||||
PEN_UP=0x02, //!< Receive an event when the pen goes up inside the region
|
||||
PEN_ENTER=0x04, //!< Receive an event when the pen enters the region (pen was down before)
|
||||
PEN_LEAVE=0x08, //!< Receive an event when the pen leaves the region (pen was inside region before)
|
||||
PEN_MOVE=0x10 //!< Receive an event when the pen moves inside the region (pen is down)
|
||||
NONE = 0x00, //!< Do not receive any events
|
||||
PEN_DOWN = 0x01, //!< Receive an event when the pen goes down inside the region
|
||||
PEN_UP = 0x02, //!< Receive an event when the pen goes up inside the region
|
||||
PEN_ENTER = 0x04, //!< Receive an event when the pen enters the region (pen was down before)
|
||||
PEN_LEAVE = 0x08, //!< Receive an event when the pen leaves the region (pen was inside region before)
|
||||
PEN_MOVE = 0x10 //!< Receive an event when the pen moves inside the region (pen is down)
|
||||
} TOUCH_ACTION;
|
||||
|
||||
/**
|
||||
@@ -48,13 +70,13 @@ typedef void (*TOUCH_CALLBACK)(void* touchArea, TOUCH_ACTION triggeredAction);
|
||||
* Structure to configure a Touch Area
|
||||
*/
|
||||
typedef struct {
|
||||
TOUCH_ACTION hookedActions; //!< Actions to listen to
|
||||
uint16_t x1; //!< Top Left X-Coordinate of Area
|
||||
uint16_t y1; //!< Top Left Y-Coordinate of Area
|
||||
uint16_t x2; //!< Bottom Right X-Coordinate of Area
|
||||
uint16_t y2; //!< Bottom Right Y-Coordinate of Area
|
||||
TOUCH_CALLBACK callback; //!< Callback which is executed when an event occurred in this Area.
|
||||
uint8_t flags; //!< For internal use, don't change, don't initialize
|
||||
TOUCH_ACTION hookedActions; //!< Actions to listen to
|
||||
uint16_t x1; //!< Top Left X-Coordinate of Area
|
||||
uint16_t y1; //!< Top Left Y-Coordinate of Area
|
||||
uint16_t x2; //!< Bottom Right X-Coordinate of Area
|
||||
uint16_t y2; //!< Bottom Right Y-Coordinate of Area
|
||||
TOUCH_CALLBACK callback; //!< Callback which is executed when an event occurred in this Area.
|
||||
uint8_t flags; //!< For internal use, don't change, don't initialize
|
||||
} TOUCH_AREA_STRUCT;
|
||||
|
||||
|
||||
@@ -62,8 +84,8 @@ typedef struct {
|
||||
* Struct which represents a 2D point on the display
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t x; //!< The X-Coordinate of the point
|
||||
uint16_t y; //!< The Y-Coordinate of the point
|
||||
uint16_t x; //!< The X-Coordinate of the point
|
||||
uint16_t y; //!< The Y-Coordinate of the point
|
||||
} POINT_STRUCT;
|
||||
|
||||
/**
|
||||
@@ -82,7 +104,7 @@ bool touch_init();
|
||||
* @param state Whether the pen is up or down
|
||||
* @return True on success
|
||||
*/
|
||||
bool touch_add_raw_event(uint16_t x, uint16_t y,TOUCH_STATE state);
|
||||
bool touch_add_raw_event(uint16_t x, uint16_t y, TOUCH_STATE state);
|
||||
|
||||
/**
|
||||
* Checks whether or not we have memory to manage and track additional \p num TOUCH_AREA_STRUCT%s
|
||||
|
||||
Reference in New Issue
Block a user