Created
September 4, 2014 18:43
-
-
Save trevd/0a10e86ef91264636fd6 to your computer and use it in GitHub Desktop.
RaspberryPI FBIOPAN_DISPLAY IOCTL Test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* fbtestXIII.c | |
* | |
* | |
* | |
* 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. | |
* | |
* | |
* Modified by Trevor Drake - Test FBIOPAN_DISPLAY IOCTL | |
*/ | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <fcntl.h> | |
#include <linux/fb.h> | |
#include <sys/mman.h> | |
#include <linux/kd.h> | |
#include <stdint.h> | |
#include <time.h> | |
// 'global' variables to store screen info | |
int fbfd = 0; | |
char *fbp = 0; | |
struct fb_var_screeninfo vinfo; | |
struct fb_fix_screeninfo finfo; | |
int page_size = 0; | |
int cur_page = 0; | |
#define NUM_ELEMS 200 | |
int xs[NUM_ELEMS]; | |
int ys[NUM_ELEMS]; | |
int dxs[NUM_ELEMS]; | |
int dys[NUM_ELEMS]; | |
static struct timespec timediff(struct timespec start, struct timespec end) { | |
struct timespec temp; | |
if ((end.tv_nsec - start.tv_nsec) < 0) { | |
temp.tv_sec = end.tv_sec - start.tv_sec - 1; | |
temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; | |
} | |
else { | |
temp.tv_sec = end.tv_sec - start.tv_sec; | |
temp.tv_nsec = end.tv_nsec - start.tv_nsec; | |
} | |
return temp; | |
} | |
// helper function to 'plot' a pixel in given color | |
void put_pixel(int x, int y, int c) | |
{ | |
// calculate the pixel's byte offset inside the buffer | |
unsigned int pix_offset = x + y * finfo.line_length; | |
// offset by the current buffer start | |
pix_offset += cur_page * page_size; | |
// now this is about the same as 'fbp[pix_offset] = value' | |
*((char*)(fbp + pix_offset)) = c; | |
} | |
// helper function to draw a rectangle in given color | |
void fill_rect(int x, int y, int w, int h, int c) { | |
int cx, cy; | |
for (cy = 0; cy < h; cy++) { | |
for (cx = 0; cx < w; cx++) { | |
put_pixel(x + cx, y + cy, c); | |
} | |
} | |
} | |
void clear_screen(int c) { | |
memset(fbp + cur_page * page_size, c, page_size); | |
} | |
// helper function for drawing - no more need to go mess with | |
// the main function when just want to change what to draw... | |
void draw() { | |
int i, x, y, w, h, dx, dy; | |
struct timespec pt; | |
struct timespec ct; | |
struct timespec df; | |
// rectangle dimensions | |
w = vinfo.yres / 10; | |
h = w; | |
// start position (upper left) | |
x = 0; | |
y = 0; | |
int n; | |
for (n = 0; n < NUM_ELEMS; n++) { | |
int ex = rand() % (vinfo.xres - w); | |
int ey = rand() % (vinfo.yres - h); | |
//printf("%d: %d,%d\n", n, ex, ey); | |
xs[n] = ex; | |
ys[n] = ey; | |
int edx = (rand() % 10) + 1; | |
int edy = (rand() % 10) + 1; | |
dxs[n] = edx; | |
dys[n] = edy; | |
} | |
// move step 'size' | |
dx = 1; | |
dy = 1; | |
int fps = 60; | |
int secs = 10; | |
int vx, vy; | |
clock_gettime(CLOCK_REALTIME, &pt); | |
// loop for a while | |
for (i = 0; i < (fps * secs); i++) { | |
// change page to draw to (between 0 and 1) | |
cur_page = (cur_page + 1) % 2; | |
// clear the previous image (= fill entire screen) | |
clear_screen(0); | |
for (n = 0; n < NUM_ELEMS; n++) { | |
x = xs[n]; | |
y = ys[n]; | |
dx = dxs[n]; | |
dy = dys[n]; | |
// draw the bouncing rectangle | |
fill_rect(x, y, w, h, (n % 15) + 1); | |
// move the rectangle | |
x = x + dx; | |
y = y + dy; | |
// check for display sides | |
if ((x < 0) || (x > (vinfo.xres - w))) { | |
dx = -dx; // reverse direction | |
x = x + 2 * dx; // counteract the move already done above | |
} | |
// same for vertical dir | |
if ((y < 0) || (y > (vinfo.yres - h))) { | |
dy = -dy; | |
y = y + 2 * dy; | |
} | |
xs[n] = x; | |
ys[n] = y; | |
dxs[n] = dx; | |
dys[n] = dy; | |
} | |
// switch page | |
//vy = cur_page * vinfo.yres; | |
vinfo.xoffset = 0; | |
vinfo.yoffset = cur_page * vinfo.yres; | |
//printf("Original vx=%d vy=%d \n", vinfo.xoffset, vinfo.yoffset); | |
vinfo.activate = FB_ACTIVATE_VBL; | |
int res = ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo); | |
if(res){ | |
printf("Error panning display. res=%d\n",res); | |
} | |
//usleep(1000000 / fps); | |
} | |
clock_gettime(CLOCK_REALTIME, &ct); | |
df = timediff(pt, ct); | |
printf("done in %ld s %5ld ms\n", df.tv_sec, df.tv_nsec / 1000000); | |
} | |
// application entry point | |
int main(int argc, char* argv[]) | |
{ | |
struct fb_var_screeninfo orig_vinfo; | |
long int screensize = 0; | |
// Open the framebuffer file for reading and writing | |
fbfd = open("/dev/fb0", O_RDWR); | |
if (fbfd == -1) { | |
printf("Error: cannot open linux framebuffer device trying android.\n"); | |
fbfd = open("/dev/graphics/fb0", O_RDWR); | |
} | |
if (fbfd == -1) { | |
printf("Error: cannot open android framebuffer device. Giving up!\n"); | |
return -1; | |
} | |
printf("The framebuffer device was opened successfully.\n"); | |
// hide cursor | |
char *kbfds = "/dev/tty"; | |
int kbfd = open(kbfds, O_WRONLY); | |
if (kbfd >= 0) { | |
ioctl(kbfd, KDSETMODE, KD_GRAPHICS); | |
} | |
else { | |
printf("Could not open %s.\n", kbfds); | |
} | |
// Get variable screen information | |
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { | |
printf("Error reading variable information.\n"); | |
} | |
printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres, | |
vinfo.bits_per_pixel ); | |
// Store for reset (copy vinfo to vinfo_orig) | |
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo)); | |
// Change variable info | |
vinfo.bits_per_pixel = 8; | |
vinfo.xres = 960; | |
vinfo.yres = 540; | |
vinfo.xres_virtual = vinfo.xres; | |
vinfo.yres_virtual = vinfo.yres * 2; | |
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) { | |
printf("Error setting variable information.\n"); | |
} | |
// Get fixed screen information | |
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { | |
printf("Error reading fixed information.\n"); | |
} | |
//printf("Fixed info: smem_len %d, line_length %d\n", finfo.smem_len, finfo.line_length); | |
page_size = finfo.line_length * vinfo.yres; | |
// map fb to user mem | |
screensize = finfo.smem_len; | |
fbp = (char*)mmap(0, | |
screensize, | |
PROT_READ | PROT_WRITE, | |
MAP_SHARED, | |
fbfd, | |
0); | |
if ((int)fbp == -1) { | |
printf("Failed to mmap\n"); | |
} | |
else { | |
// draw... | |
draw(); | |
//sleep(5); | |
} | |
// cleanup | |
munmap(fbp, screensize); | |
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) { | |
printf("Error re-setting variable information.\n"); | |
} | |
close(fbfd); | |
// reset cursor | |
if (kbfd >= 0) { | |
ioctl(kbfd, KDSETMODE, KD_TEXT); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment