How to get pixel colour from framebuffer on linux (Raspberry Pi)
Asked Answered
A

0

2

I am trying to make a small program to control the colour of an RGB LED according to the colour of certain pixels on the screen. Since this is on Raspberry Pi running Raspbmc, I cant use XLib because everything is drawn from the frame buffer(not sure if this is true, but from what I read on the FAQ this appears to be the case). I tried using XLib but couldn't get the display to be detected (makes sense why it doesn't work now).

This is an example I found online. The problem is, it compiles fine, but when run, the second error message appears: "Error reading fixed information". I tried displaying the content of fbfd but that results in a Segmentation Error. So it appears nothing is written to fbfd?

I cant make sense of it because everything I find about the frame buffer is basicly this same code, so I don't know why it doesn't work.

Hope someone can help!

#include <unistd.h>
#include <fcntl.h>        /* for fcntl */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>        /* for mmap */
#include <sys/ioctl.h>
#include <linux/fb.h>

#include <stdio.h>
#include <stdlib.h>

int main() {
    long int screensize = 0;    
    int fbfd =0;                    /* frame buffer file descriptor */
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    char* fbp;                    /* pointer to framebuffer */
    int location;                    /* iterate to location */

    int x, y;                    /* x and y location */

    /* open the file for reading and writing */
    fbfd = open("/dev/fb0", O_RDWR);
    //printf("%s\n",fbfd);
    if (!fbfd) {
        printf("Error: cannot open framebuffer device.\n");
        exit(1);
    }
    printf ("The framebuffer device was opened successfully.\n");

    /* get the fixed screen information */
    if (ioctl (fbfd, FBIOGET_FSCREENINFO, &finfo)) {
        printf("Error reading fixed information.\n");
        exit(2);
    }

    /* get variable screen information */
    if (ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
        printf("Error reading variable information.\n");
        exit(3);
    }

    /* figure out the size of the screen in bytes */
    //screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    /* map the device to memory */
    fbp = (char*)mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);

    if ((int)fbp == -1) {
        printf ("Error: failed to map framebuffer device to memory.\n");
        exit(4);
    }
    printf ("Framebuffer device was mapped to memory successfully.\n");

    // Figure out where in memory to put the pixel
    for ( y = 0; y < (vinfo.yres/2); y++ )
        for ( x = 0; x < vinfo.xres; x++ ) { 
            location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y+vinfo.yoffset) * finfo.line_length;
            if ( vinfo.bits_per_pixel == 32 ) { 
                *(fbp + location) = 100; // Some blue 
                *(fbp + location + 1) = 15+(x-100)/2; // A little green 
                *(fbp + location + 2) = 200-(y-100)/5; // A lot of red
                *(fbp + location + 3) = 0; // No transparency 
            } else { //assume 16bpp 
                int b = 10; int g = (x-100)/6; // A little green 
                int r = 31-(y-100)/16; // A lot of red 
                unsigned short int t = r<<11 | g << 5 | b; 
                *((unsigned short int*)(fbp + location)) = t; 
            }
        }
    munmap(fbp, screensize);
    close(fbfd);

    return 0;
}
Apocrine answered 23/10, 2013 at 12:42 Comment(4)
try to read that enter link description hereAcetous
I'm not surprised that doesn't work, it looks old. Nowadays you need to request a framebuffer from the GPU. You send a specific message to specific mailbox with a pointer to a struct containing information about what you want and if you're lucky it works. Then it works like a regular framebuffer, maybe not on /dev/fb0, I think you get a pointer. But you need memory barriers and all that because the CPU is talking to the GPU and you have to have it synchronized. This sounds like something from an i386. ioctls? No. I don't know yet, that's why I'm googling it, but this is wrong.Learning
Actually it did work. But under Raspbian on a Pi 3B. There's a framebuffer driver I think built into Linux which must get stuff from the GPU. Try fbset, mine reads the screen size and depth correctly. If you have /etc/fb.modes it should show the modes it can use.Learning
You probably have bcm2708_fb.c somewhere or it's built into your kernel. It's copyright Broadcom and I think it makes the Pi framebuffer act like a traditional framebuffer, opening on /dev/fb0, etc. Search for framebuffer at raspberrypi.org/forums there's a lot there, and the engineers participate in the forum too.Learning

© 2022 - 2024 — McMap. All rights reserved.