major cleanup to avoid segfaults when fetching data, added fbdata module, refactored all methods to use a central screen object
This commit is contained in:
parent
6c3c870f5e
commit
61559bb60f
16
Makefile
16
Makefile
@ -2,16 +2,20 @@
|
|||||||
# # sudo apt-get install libmariadb-dev
|
# # sudo apt-get install libmariadb-dev
|
||||||
# # mariadb_config --libs
|
# # mariadb_config --libs
|
||||||
#
|
#
|
||||||
CFLAGS=-g -Wall -lm -L/usr/lib/arm-linux-gnueabihf -lmariadb -I/usr/include/mariadb
|
CFLAGS=-g -Wall -lm
|
||||||
|
DBFLAGS=-L/usr/lib/arm-linux-gnueabihf -lmariadb -I/usr/include/mariadb
|
||||||
|
|
||||||
fbdash: fbdash.c fblib.o fbfont.o
|
fbdash: fbdash.c fblib.o fbfont.o fbdata.o
|
||||||
gcc -o $@ fblib.o fbfont.o $< $(CFLAGS)
|
gcc -o $@ fblib.o fbfont.o fbdata.o $< $(CFLAGS) $(DBFLAGS)
|
||||||
|
|
||||||
fblib.o: fblib.c fblib.h
|
fblib.o: fblib.c fblib.h
|
||||||
gcc -c fblib.c
|
gcc -c fblib.c $(CFLAGS)
|
||||||
|
|
||||||
fbfont.o: fbfont.c fbfont.h
|
fbfont.o: fbfont.c fbfont.h
|
||||||
gcc -c fbfont.c
|
gcc -c fbfont.c $(CFLAGS)
|
||||||
|
|
||||||
|
fbdata.o: fbdata.c fbdata.h
|
||||||
|
gcc -c fbdata.c $(CFLAGS) $(DBFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f fbdash fblib.o fbfont.o
|
rm -f fbdash fblib.o fbfont.o fbdata.o
|
||||||
|
|||||||
190
fbdash.c
190
fbdash.c
@ -3,8 +3,10 @@
|
|||||||
*
|
*
|
||||||
* Adapted by Florian Klemenz for use in the fb_dash project
|
* Adapted by Florian Klemenz for use in the fb_dash project
|
||||||
*
|
*
|
||||||
* Source and all credit goes to
|
* Credit for most of the framebuffer-related source code goes to
|
||||||
* http://raspberrycompote.blogspot.com/
|
* http://raspberrycompote.blogspot.com/
|
||||||
|
* Thanks for providing an excellent tutorial!
|
||||||
|
|
||||||
* --------------------------------------------------------------------------------------------
|
* --------------------------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html
|
* http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html
|
||||||
@ -27,164 +29,80 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#include <mysql.h>
|
|
||||||
|
|
||||||
#include "fblib.h"
|
#include "fblib.h"
|
||||||
|
#include "fbdata.h"
|
||||||
|
|
||||||
|
#define DEVICE "/dev/fb1"
|
||||||
#define WIDTH 240
|
#define WIDTH 240
|
||||||
#define HEIGHT 320
|
#define HEIGHT 320
|
||||||
|
#define BITS_PER_PIXEL 16
|
||||||
|
|
||||||
|
|
||||||
char *fbp = 0;
|
void updateSlot(screen fb, sourcedata data, int x_offset, int y_offset, color c) {
|
||||||
|
render_string(fb, ubuntu_mono_24, data.text, x_offset, y_offset, c.r, c.g, c.b);
|
||||||
|
|
||||||
struct s_color {
|
if (data.temperature) render_string(fb, ubuntu_mono_48, data.temperature, x_offset + 115, y_offset - 9, c.r, c.g, c.b);
|
||||||
unsigned char r;
|
render_string(fb, ubuntu_mono_48, "C", x_offset + 195, y_offset - 9, c.r, c.g, c.b);
|
||||||
unsigned char g;
|
|
||||||
unsigned char b;
|
|
||||||
};
|
|
||||||
typedef struct s_color color;
|
|
||||||
|
|
||||||
struct s_sourcedata {
|
if (data.humidity) render_string(fb, ubuntu_mono_48, data.humidity, x_offset + 115, y_offset + 26, c.r, c.g, c.b);
|
||||||
char* text;
|
render_string(fb, ubuntu_mono_48, "%", x_offset + 195, y_offset + 26, c.r, c.g, c.b);
|
||||||
char* temperature;
|
|
||||||
char* humidity;
|
|
||||||
};
|
|
||||||
typedef struct s_sourcedata sourcedata;
|
|
||||||
|
|
||||||
|
|
||||||
void finish_with_error(MYSQL *con) {
|
|
||||||
fprintf(stderr, "%s\n", mysql_error(con));
|
|
||||||
mysql_close(con);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSlot(char *fbp, sourcedata data, int x_offset, int y_offset, color c) {
|
void draw(screen fb) {
|
||||||
render_string(fbp, ubuntu_mono_24, data.text, x_offset, y_offset, c.r, c.g, c.b);
|
clear_screen(fb);
|
||||||
|
|
||||||
render_string(fbp, ubuntu_mono_48, data.temperature, x_offset + 115, y_offset - 9, c.r, c.g, c.b);
|
int slot_height = fb.height / 4;
|
||||||
render_string(fbp, ubuntu_mono_48, "C", x_offset + 195, y_offset - 9, c.r, c.g, c.b);
|
|
||||||
|
|
||||||
render_string(fbp, ubuntu_mono_48, data.humidity, x_offset + 115, y_offset + 26, c.r, c.g, c.b);
|
|
||||||
render_string(fbp, ubuntu_mono_48, "%", x_offset + 195, y_offset + 26, c.r, c.g, c.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateData(char *fbp, int slot_height) {
|
|
||||||
// query database for latest values
|
|
||||||
printf("MySQL client version: %s\n", mysql_get_client_info());
|
|
||||||
MYSQL *con = mysql_init(NULL);
|
|
||||||
if (con == NULL) {
|
|
||||||
fprintf(stderr, "%s\n", mysql_error(con));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (mysql_real_connect(con, "web-pi", "grafanaReader", "grafanaReader", "grafanaData", 0, NULL, 0) == NULL) {
|
|
||||||
fprintf(stderr, "%s\n", mysql_error(con));
|
|
||||||
mysql_close(con);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
char* query = "\
|
|
||||||
SELECT \
|
|
||||||
time, \
|
|
||||||
source, \
|
|
||||||
metric, \
|
|
||||||
value \
|
|
||||||
FROM readings AS r \
|
|
||||||
INNER JOIN sources AS s ON r.source_id = s.id \
|
|
||||||
INNER JOIN metrics AS m ON r.metric_id = m.id \
|
|
||||||
WHERE \
|
|
||||||
time > (NOW() - 60 * 15) AND \
|
|
||||||
metric IN ('Luftfeuchte','Temperatur') AND \
|
|
||||||
source IN ('Esszimmer','Wohnzimmer', 'Schlafzimmer', 'Abstellkammer') \
|
|
||||||
ORDER BY time DESC \
|
|
||||||
LIMIT 100;";
|
|
||||||
|
|
||||||
//printf("%s\n",query);
|
|
||||||
printf("Fetching data ...\n");
|
|
||||||
|
|
||||||
if (mysql_query(con, query)) {
|
|
||||||
finish_with_error(con);
|
|
||||||
}
|
|
||||||
MYSQL_RES *result = mysql_store_result(con);
|
|
||||||
if (result == NULL) {
|
|
||||||
finish_with_error(con);
|
|
||||||
}
|
|
||||||
|
|
||||||
// define what to display
|
|
||||||
sourcedata data[4] = {
|
|
||||||
{ "Esszimmer", NULL, NULL },
|
|
||||||
{ "Wohnzimmer", NULL, NULL },
|
|
||||||
{ "Schlafzimmer", NULL, NULL },
|
|
||||||
{ "Abstellkammer", NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
int num_fields = mysql_num_fields(result);
|
|
||||||
if (num_fields > 3) {
|
|
||||||
MYSQL_ROW row;
|
|
||||||
while ((row = mysql_fetch_row(result))) {
|
|
||||||
if (strlen(row[3]) > 4) row[3][4] = '\0'; // loose the secnod and third decimal ...
|
|
||||||
|
|
||||||
// data binding
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
if (strcmp(row[1], data[i].text) == 0) {
|
|
||||||
if (strcmp(row[2], "Temperatur") == 0 && data[i].temperature == NULL) data[i].temperature = row[3];
|
|
||||||
else if (strcmp(row[2], "Luftfeuchte") == 0 && data[i].humidity == NULL) data[i].humidity = row[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// debugging
|
|
||||||
//for(int i = 0; i < num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL");
|
|
||||||
//printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Updating dashboard...\n");
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
color c = {255,125 + 25*i,25 + 25*i};
|
|
||||||
updateSlot(fbp, data[i], 15, 7 + slot_height * i, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
printf("Done!\n");
|
|
||||||
|
|
||||||
mysql_free_result(result);
|
|
||||||
mysql_close(con);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void draw() {
|
|
||||||
clear_screen(fbp);
|
|
||||||
|
|
||||||
// horizontal spacersint x_space = 10;
|
// horizontal spacersint x_space = 10;
|
||||||
int y_step_width = HEIGHT / 4;
|
|
||||||
for (int i = 1; i < 4; i++) {
|
for (int i = 1; i < 4; i++) {
|
||||||
int x0 = 15;
|
int x0 = 15;
|
||||||
int x1 = WIDTH - x0;
|
int x1 = fb.width - x0;
|
||||||
int y = y_step_width * i;
|
int y = slot_height * i;
|
||||||
|
|
||||||
int r = 225;
|
int r = 225;
|
||||||
int g = 32;
|
int g = 32;
|
||||||
int b = 32;
|
int b = 32;
|
||||||
|
|
||||||
draw_line(fbp, x0, y-1, x1, y-1, r, g, b);
|
draw_line(fb, x0, y-1, x1, y-1, r, g, b);
|
||||||
draw_line(fbp, x0, y , x1, y , r, g, b);
|
draw_line(fb, x0, y , x1, y , r, g, b);
|
||||||
draw_line(fbp, x0, y+1, x1, y+1, r, g, b);
|
draw_line(fb, x0, y+1, x1, y+1, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// define what to display
|
||||||
|
sourcedata data[4] = {
|
||||||
|
// text | temperature | humidity
|
||||||
|
{ "Esszimmer" , NULL, NULL },
|
||||||
|
{ "Wohnzimmer" , NULL, NULL },
|
||||||
|
{ "Schlafzimmer" , NULL, NULL },
|
||||||
|
{ "Abstellkammer" , NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
// fetch data from database and update screen
|
// fetch data from database and update screen
|
||||||
updateData(fbp, y_step_width);
|
printf("Fetching data...\n");
|
||||||
|
updateData(data);
|
||||||
|
|
||||||
|
// update dashboard
|
||||||
|
printf("Updating dashboard...\n");
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
color c = {255,125 + 25*i,25 + 25*i};
|
||||||
|
updateSlot(fb, data[i], 15, 7 + slot_height * i, c);
|
||||||
|
|
||||||
|
// release allocated memory for values
|
||||||
|
free(data[i].temperature);
|
||||||
|
free(data[i].humidity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// application entry point
|
// application entry point
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[]) {
|
||||||
{
|
char *fbp = 0;
|
||||||
int fbfd = 0;
|
int fbfd = 0;
|
||||||
long int screensize = 0;
|
long int screensize = 0;
|
||||||
|
|
||||||
// Open the framebuffer file for reading and writing
|
// Open the framebuffer file for reading and writing
|
||||||
fbfd = open("/dev/fb1", O_RDWR);
|
fbfd = open(DEVICE, O_RDWR);
|
||||||
if (fbfd == -1) {
|
if (fbfd == -1) {
|
||||||
printf("Error: cannot open framebuffer device.\n");
|
printf("Error: cannot open framebuffer device.\n");
|
||||||
return(1);
|
return(1);
|
||||||
@ -192,7 +110,7 @@ int main(int argc, char* argv[])
|
|||||||
printf("The framebuffer device was opened successfully.\n");
|
printf("The framebuffer device was opened successfully.\n");
|
||||||
|
|
||||||
// map fb to user mem
|
// map fb to user mem
|
||||||
screensize = WIDTH*HEIGHT*2;
|
screensize = WIDTH * HEIGHT * (BITS_PER_PIXEL / 8);
|
||||||
fbp = (char*)mmap(0,
|
fbp = (char*)mmap(0,
|
||||||
screensize,
|
screensize,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
@ -200,12 +118,24 @@ int main(int argc, char* argv[])
|
|||||||
fbfd,
|
fbfd,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
|
||||||
if ((int)fbp == -1) {
|
if ((int)fbp == -1) {
|
||||||
printf("Failed to mmap.\n");
|
printf("Failed to mmap.\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// define the screen object
|
||||||
|
screen fb = {
|
||||||
|
.buffer = fbp,
|
||||||
|
.width = WIDTH,
|
||||||
|
.height = HEIGHT,
|
||||||
|
.bpp = BITS_PER_PIXEL,
|
||||||
|
.step = (BITS_PER_PIXEL / 8),
|
||||||
|
.line = (BITS_PER_PIXEL / 8) * WIDTH,
|
||||||
|
.screensize = screensize,
|
||||||
|
};
|
||||||
|
|
||||||
// draw...
|
// draw...
|
||||||
draw();
|
draw(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
|
|||||||
74
fbdata.c
Normal file
74
fbdata.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
#include "fbdata.h"
|
||||||
|
|
||||||
|
|
||||||
|
void finish_with_error(MYSQL *con) {
|
||||||
|
fprintf(stderr, "%s\n", mysql_error(con));
|
||||||
|
mysql_close(con);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updateData(sourcedata data[]) {
|
||||||
|
|
||||||
|
// query database for latest values
|
||||||
|
char query[] = "\
|
||||||
|
SELECT time, source, metric, value \
|
||||||
|
FROM readings AS r \
|
||||||
|
INNER JOIN (SELECT MAX(time) AS maxtime, source_id, metric_id FROM readings GROUP BY source_id,metric_id) AS mr \
|
||||||
|
ON mr.maxtime = r.time AND mr.source_id = r.source_id AND mr.metric_id = r.metric_id \
|
||||||
|
INNER JOIN sources AS s \
|
||||||
|
ON r.source_id = s.id \
|
||||||
|
INNER JOIN metrics AS m \
|
||||||
|
ON r.metric_id = m.id;\
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
printf("Connecting to database ...\n");
|
||||||
|
printf("MySQL client version: %s\n", mysql_get_client_info());
|
||||||
|
|
||||||
|
MYSQL *con;
|
||||||
|
if (!(con = mysql_init(NULL))) finish_with_error(con);
|
||||||
|
if (!mysql_real_connect(con, "web-pi", "grafanaReader", "grafanaReader", "grafanaData", 0, NULL, 0)) finish_with_error(con);
|
||||||
|
|
||||||
|
//printf("%s\n",query);
|
||||||
|
printf("Running query ...\n");
|
||||||
|
//printf("Query: %s\n", query);
|
||||||
|
if (mysql_query(con, query)) finish_with_error(con);
|
||||||
|
printf("Finished.\n");
|
||||||
|
|
||||||
|
MYSQL_RES *result;
|
||||||
|
if (!(result = mysql_store_result(con))) finish_with_error(con);
|
||||||
|
int num_fields = mysql_num_fields(result);
|
||||||
|
if (num_fields > 3) { // sanity check to honor bounds
|
||||||
|
MYSQL_ROW row;
|
||||||
|
while ((row = mysql_fetch_row(result))) {
|
||||||
|
unsigned long *length = mysql_fetch_lengths (result); // only valid for current row
|
||||||
|
int l = *(length + 3) - 2;
|
||||||
|
//printf("%s [l = %d]\n", row[3], l);
|
||||||
|
|
||||||
|
// data binding
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (strcmp(row[1], data[i].text) == 0) {
|
||||||
|
if (strcmp(row[2], "Temperatur") == 0 && data[i].temperature == NULL) {
|
||||||
|
data[i].temperature = calloc((l + 1),sizeof(char)); // +1 for null-termination
|
||||||
|
memcpy(data[i].temperature, row[3], l * sizeof(char));
|
||||||
|
}
|
||||||
|
else if (strcmp(row[2], "Luftfeuchte") == 0 && data[i].humidity == NULL){
|
||||||
|
data[i].humidity = calloc((l + 1),sizeof(char)); // +1 for null-termination
|
||||||
|
memcpy(data[i].humidity, row[3], l * sizeof(char));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// debugging
|
||||||
|
//for(int i = 0; i < num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL");
|
||||||
|
//printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// free memory after dashboard was updated
|
||||||
|
mysql_free_result(result);
|
||||||
|
mysql_close(con);
|
||||||
|
printf("Done!\n");
|
||||||
|
}
|
||||||
|
|
||||||
18
fbdata.h
Normal file
18
fbdata.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <mysql.h>
|
||||||
|
|
||||||
|
struct s_sourcedata {
|
||||||
|
char* text;
|
||||||
|
char* temperature;
|
||||||
|
char* humidity;
|
||||||
|
};
|
||||||
|
typedef struct s_sourcedata sourcedata;
|
||||||
|
|
||||||
|
|
||||||
|
void finish_with_error(MYSQL *con);
|
||||||
|
void updateData(sourcedata data[]);
|
||||||
|
|
||||||
210
fblib.c
210
fblib.c
@ -1,136 +1,30 @@
|
|||||||
/*
|
|
||||||
* fblib.c
|
|
||||||
*
|
|
||||||
* Adapted by Florian Klemenz for use in the fb_dash project
|
|
||||||
*
|
|
||||||
* Source and all credit goes to
|
|
||||||
* http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html
|
|
||||||
*
|
|
||||||
* Original work by J-P Rosti (a.k.a -rst- and 'Raspberry Compote')
|
|
||||||
*
|
|
||||||
* Licensed under the Creative Commons Attribution 3.0 Unported License
|
|
||||||
* (http://creativecommons.org/licenses/by/3.0/deed.en_US)
|
|
||||||
*
|
|
||||||
* Distributed in the hope that this will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fblib.h"
|
#include "fblib.h"
|
||||||
|
|
||||||
// helper function to 'plot' a pixel in given color
|
// helper function to 'plot' a pixel in given color
|
||||||
void put_pixel(char *fbp, int x, int y, int r, int g, int b)
|
void put_pixel(screen fb, int x, int y, int r, int g, int b)
|
||||||
{
|
{
|
||||||
// calculate the pixel's byte offset inside the buffer
|
// calculate the pixel's byte offset inside the buffer
|
||||||
// note: x * 2 as every pixel is 2 consecutive bytes
|
// note: x * 2 as every pixel is 2 consecutive bytes
|
||||||
//unsigned int pix_offset = x * 2 + y * finfo.line_length;
|
//unsigned int pix_offset = x * 2 + y * finfo.line_length;
|
||||||
unsigned int pix_offset = x * 2 + y * (WIDTH * 2);
|
unsigned int pix_offset = x * fb.step + y * fb.line;
|
||||||
|
|
||||||
// now this is about the same as 'fbp[pix_offset] = value'
|
// now this is about the same as 'fbp[pix_offset] = value'
|
||||||
// but a bit more complicated for RGB565
|
// but a bit more complicated for RGB565
|
||||||
//unsigned short c = ((r / 8) << 11) + ((g / 4) << 5) + (b / 8);
|
//unsigned short c = ((r / 8) << 11) + ((g / 4) << 5) + (b / 8);
|
||||||
unsigned short c = ((r / 8) * 2048) + ((g / 4) * 32) + (b / 8);
|
unsigned short c = ((r / 8) * 2048) + ((g / 4) * 32) + (b / 8);
|
||||||
// write 'two bytes at once'
|
// write 'two bytes at once'
|
||||||
*((unsigned short*)(fbp + pix_offset)) = c;
|
*((unsigned short*)(fb.buffer + pix_offset)) = c;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to draw a rectangle in given color
|
|
||||||
void fill_rect(char *fbp, int x, int y, int w, int h, int r, int g, int b) {
|
|
||||||
int cx, cy;
|
|
||||||
for (cy = 0; cy < h; cy++) {
|
|
||||||
for (cx = 0; cx < w; cx++) {
|
|
||||||
put_pixel(fbp, x + cx, y + cy, r, g, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to draw a rectangle outline in given color
|
|
||||||
void draw_rect(char *fbp, int x0, int y0, int w, int h, int r, int g, int b) {
|
|
||||||
draw_line(fbp, x0, y0, x0 + w, y0, r, g, b); // top
|
|
||||||
draw_line(fbp, x0, y0, x0, y0 + h, r, g, b); // left
|
|
||||||
draw_line(fbp, x0, y0 + h, x0 + w, y0 + h, r, g, b); // bottom
|
|
||||||
draw_line(fbp, x0 + w, y0, x0 + w, y0 + h, r, g, b); // right
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to draw a circle outline in given color
|
|
||||||
// (uses Bresenham's circle algorithm)
|
|
||||||
void draw_circle(char *fbp, int x0, int y0, int radius, int r, int g, int b)
|
|
||||||
{
|
|
||||||
int x = radius;
|
|
||||||
int y = 0;
|
|
||||||
int radiusError = 1 - x;
|
|
||||||
|
|
||||||
while(x >= y)
|
|
||||||
{
|
|
||||||
// top left
|
|
||||||
put_pixel(fbp, -y + x0, -x + y0, r, g, b);
|
|
||||||
// top right
|
|
||||||
put_pixel(fbp, y + x0, -x + y0, r, g, b);
|
|
||||||
// upper middle left
|
|
||||||
put_pixel(fbp, -x + x0, -y + y0, r, g, b);
|
|
||||||
// upper middle right
|
|
||||||
put_pixel(fbp, x + x0, -y + y0, r, g, b);
|
|
||||||
// lower middle left
|
|
||||||
put_pixel(fbp, -x + x0, y + y0, r, g, b);
|
|
||||||
// lower middle right
|
|
||||||
put_pixel(fbp, x + x0, y + y0, r, g, b);
|
|
||||||
// bottom left
|
|
||||||
put_pixel(fbp, -y + x0, x + y0, r, g, b);
|
|
||||||
// bottom right
|
|
||||||
put_pixel(fbp, y + x0, x + y0, r, g, b);
|
|
||||||
|
|
||||||
y++;
|
|
||||||
if (radiusError < 0)
|
|
||||||
{
|
|
||||||
radiusError += 2 * y + 1;
|
|
||||||
} else {
|
|
||||||
x--;
|
|
||||||
radiusError+= 2 * (y - x + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to draw a filled circle in given color
|
|
||||||
// (uses Bresenham's circle algorithm)
|
|
||||||
void fill_circle(char *fbp, int x0, int y0, int radius, int r, int g, int b) {
|
|
||||||
int x = radius;
|
|
||||||
int y = 0;
|
|
||||||
int radiusError = 1 - x;
|
|
||||||
|
|
||||||
while(x >= y)
|
|
||||||
{
|
|
||||||
// top
|
|
||||||
draw_line(fbp, -y + x0, -x + y0, y + x0, -x + y0, r, g, b);
|
|
||||||
// upper middle
|
|
||||||
draw_line(fbp, -x + x0, -y + y0, x + x0, -y + y0, r, g, b);
|
|
||||||
// lower middle
|
|
||||||
draw_line(fbp, -x + x0, y + y0, x + x0, y + y0, r, g, b);
|
|
||||||
// bottom
|
|
||||||
draw_line(fbp, -y + x0, x + y0, y + x0, x + y0, r, g, b);
|
|
||||||
|
|
||||||
y++;
|
|
||||||
if (radiusError < 0)
|
|
||||||
{
|
|
||||||
radiusError += 2 * y + 1;
|
|
||||||
} else {
|
|
||||||
x--;
|
|
||||||
radiusError+= 2 * (y - x + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to clear the screen - fill whole
|
// helper function to clear the screen - fill whole
|
||||||
// screen with given color
|
// screen with given color
|
||||||
void clear_screen(char *fbp) {
|
void clear_screen(screen fb) {
|
||||||
//memset(fbp, 0, vinfo.xres * vinfo.yres * 2); // 16Bit = 8Bit * 2
|
memset(fb.buffer, 0, fb.screensize);
|
||||||
memset(fbp, 0, WIDTH * HEIGHT * 2); // 16Bit = 8Bit * 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to draw a line in given color
|
// helper function to draw a line in given color
|
||||||
// (uses Bresenham's line algorithm)
|
// (uses Bresenham's line algorithm)
|
||||||
void draw_line(char *fbp, int x0, int y0, int x1, int y1, int r, int g, int b) {
|
void draw_line(screen fb, int x0, int y0, int x1, int y1, int r, int g, int b) {
|
||||||
int dx = x1 - x0;
|
int dx = x1 - x0;
|
||||||
dx = (dx >= 0) ? dx : -dx; // abs()
|
dx = (dx >= 0) ? dx : -dx; // abs()
|
||||||
int dy = y1 - y0;
|
int dy = y1 - y0;
|
||||||
@ -149,7 +43,7 @@ void draw_line(char *fbp, int x0, int y0, int x1, int y1, int r, int g, int b) {
|
|||||||
int e2;
|
int e2;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
put_pixel(fbp, x0, y0, r, g, b);
|
put_pixel(fb, x0, y0, r, g, b);
|
||||||
if ((x0 == x1) && (y0 == y1))
|
if ((x0 == x1) && (y0 == y1))
|
||||||
done = 1;
|
done = 1;
|
||||||
else {
|
else {
|
||||||
@ -166,7 +60,93 @@ void draw_line(char *fbp, int x0, int y0, int x1, int y1, int r, int g, int b) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_string(char *fbp, fbfont font, char *text, int x, int y, int r, int g, int b)
|
// helper function to draw a rectangle in given color
|
||||||
|
void fill_rect(screen fb, int x, int y, int w, int h, int r, int g, int b) {
|
||||||
|
int cx, cy;
|
||||||
|
for (cy = 0; cy < h; cy++) {
|
||||||
|
for (cx = 0; cx < w; cx++) {
|
||||||
|
put_pixel(fb, x + cx, y + cy, r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to draw a rectangle outline in given color
|
||||||
|
void draw_rect(screen fb, int x0, int y0, int w, int h, int r, int g, int b) {
|
||||||
|
draw_line(fb, x0, y0, x0 + w, y0, r, g, b); // top
|
||||||
|
draw_line(fb, x0, y0, x0, y0 + h, r, g, b); // left
|
||||||
|
draw_line(fb, x0, y0 + h, x0 + w, y0 + h, r, g, b); // bottom
|
||||||
|
draw_line(fb, x0 + w, y0, x0 + w, y0 + h, r, g, b); // right
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to draw a circle outline in given color
|
||||||
|
// (uses Bresenham's circle algorithm)
|
||||||
|
void draw_circle(screen fb, int x0, int y0, int radius, int r, int g, int b)
|
||||||
|
{
|
||||||
|
int x = radius;
|
||||||
|
int y = 0;
|
||||||
|
int radiusError = 1 - x;
|
||||||
|
|
||||||
|
while(x >= y)
|
||||||
|
{
|
||||||
|
// top left
|
||||||
|
put_pixel(fb, -y + x0, -x + y0, r, g, b);
|
||||||
|
// top right
|
||||||
|
put_pixel(fb, y + x0, -x + y0, r, g, b);
|
||||||
|
// upper middle left
|
||||||
|
put_pixel(fb, -x + x0, -y + y0, r, g, b);
|
||||||
|
// upper middle right
|
||||||
|
put_pixel(fb, x + x0, -y + y0, r, g, b);
|
||||||
|
// lower middle left
|
||||||
|
put_pixel(fb, -x + x0, y + y0, r, g, b);
|
||||||
|
// lower middle right
|
||||||
|
put_pixel(fb, x + x0, y + y0, r, g, b);
|
||||||
|
// bottom left
|
||||||
|
put_pixel(fb, -y + x0, x + y0, r, g, b);
|
||||||
|
// bottom right
|
||||||
|
put_pixel(fb, y + x0, x + y0, r, g, b);
|
||||||
|
|
||||||
|
y++;
|
||||||
|
if (radiusError < 0)
|
||||||
|
{
|
||||||
|
radiusError += 2 * y + 1;
|
||||||
|
} else {
|
||||||
|
x--;
|
||||||
|
radiusError+= 2 * (y - x + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to draw a filled circle in given color
|
||||||
|
// (uses Bresenham's circle algorithm)
|
||||||
|
void fill_circle(screen fb, int x0, int y0, int radius, int r, int g, int b) {
|
||||||
|
int x = radius;
|
||||||
|
int y = 0;
|
||||||
|
int radiusError = 1 - x;
|
||||||
|
|
||||||
|
while(x >= y)
|
||||||
|
{
|
||||||
|
// top
|
||||||
|
draw_line(fb, -y + x0, -x + y0, y + x0, -x + y0, r, g, b);
|
||||||
|
// upper middle
|
||||||
|
draw_line(fb, -x + x0, -y + y0, x + x0, -y + y0, r, g, b);
|
||||||
|
// lower middle
|
||||||
|
draw_line(fb, -x + x0, y + y0, x + x0, y + y0, r, g, b);
|
||||||
|
// bottom
|
||||||
|
draw_line(fb, -y + x0, x + y0, y + x0, x + y0, r, g, b);
|
||||||
|
|
||||||
|
y++;
|
||||||
|
if (radiusError < 0)
|
||||||
|
{
|
||||||
|
radiusError += 2 * y + 1;
|
||||||
|
} else {
|
||||||
|
x--;
|
||||||
|
radiusError+= 2 * (y - x + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void render_string(screen fb, fbfont font, char *text, int x, int y, int r, int g, int b)
|
||||||
{
|
{
|
||||||
int text_length = strlen(text);
|
int text_length = strlen(text);
|
||||||
//printf("text_length = %d\n", text_length);
|
//printf("text_length = %d\n", text_length);
|
||||||
@ -199,7 +179,7 @@ void render_string(char *fbp, fbfont font, char *text, int x, int y, int r, int
|
|||||||
//printf("x");
|
//printf("x");
|
||||||
|
|
||||||
int x_pos = x_offset + byte_num * 8 + bit_number;
|
int x_pos = x_offset + byte_num * 8 + bit_number;
|
||||||
put_pixel(fbp, x_pos, y_pos, r, g, b);
|
put_pixel(fb, x_pos, y_pos, r, g, b);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// leave empty (or maybe plot 'text backgr color')
|
// leave empty (or maybe plot 'text backgr color')
|
||||||
|
|||||||
53
fblib.h
53
fblib.h
@ -1,23 +1,3 @@
|
|||||||
/*
|
|
||||||
* fblib.h
|
|
||||||
*
|
|
||||||
* Adapted by Florian Klemenz for use in the fb_dash project
|
|
||||||
*
|
|
||||||
* Source and all credit goes to
|
|
||||||
* http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html
|
|
||||||
*
|
|
||||||
* Original work by J-P Rosti (a.k.a -rst- and 'Raspberry Compote')
|
|
||||||
*
|
|
||||||
* Licensed under the Creative Commons Attribution 3.0 Unported License
|
|
||||||
* (http://creativecommons.org/licenses/by/3.0/deed.en_US)
|
|
||||||
*
|
|
||||||
* Distributed in the hope that this will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef FBLIB_H
|
#ifndef FBLIB_H
|
||||||
#define FBLIB_H
|
#define FBLIB_H
|
||||||
|
|
||||||
@ -31,18 +11,35 @@
|
|||||||
#define WIDTH 240
|
#define WIDTH 240
|
||||||
#define HEIGHT 320
|
#define HEIGHT 320
|
||||||
|
|
||||||
|
struct s_color {
|
||||||
|
unsigned char r;
|
||||||
|
unsigned char g;
|
||||||
|
unsigned char b;
|
||||||
|
};
|
||||||
|
typedef struct s_color color;
|
||||||
|
|
||||||
void put_pixel(char *fbp, int x, int y, int r, int g, int b);
|
struct s_screen {
|
||||||
void clear_screen(char *fbp);
|
char *buffer;
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
unsigned char bpp; // bits per pixel
|
||||||
|
unsigned char step; // byte-wise step per pixel
|
||||||
|
unsigned int line; // line length
|
||||||
|
unsigned int screensize;
|
||||||
|
};
|
||||||
|
typedef struct s_screen screen;
|
||||||
|
|
||||||
void draw_line(char *fbp, int x0, int y0, int x1, int y1, int r, int g, int b);
|
void put_pixel(screen fb, int x, int y, int r, int g, int b);
|
||||||
|
void clear_screen(screen fb);
|
||||||
|
|
||||||
void draw_rect(char *fbp, int x0, int y0, int w, int h, int r, int g, int b);
|
void draw_line(screen fb, int x0, int y0, int x1, int y1, int r, int g, int b);
|
||||||
void fill_rect(char *fbp, int x, int y, int w, int h, int r, int g, int b);
|
|
||||||
|
|
||||||
void draw_circle(char *fbp, int x0, int y0, int radius, int r, int g, int b);
|
void draw_rect(screen fb, int x0, int y0, int w, int h, int r, int g, int b);
|
||||||
void fill_circle(char *fbp, int x0, int y0, int radius, int r, int g, int b);
|
void fill_rect(screen fb, int x, int y, int w, int h, int r, int g, int b);
|
||||||
|
|
||||||
void render_string(char *fbp, fbfont font, char *text, int x, int y, int r, int g, int b);
|
void draw_circle(screen fb, int x0, int y0, int radius, int r, int g, int b);
|
||||||
|
void fill_circle(screen fb, int x0, int y0, int radius, int r, int g, int b);
|
||||||
|
|
||||||
|
void render_string(screen fb, fbfont font, char *text, int x, int y, int r, int g, int b);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user