/*****************************************************************************/
/* Copyright (c) 2009 NXP B.V.  All rights are reserved.                     */
/*                                                                           */
/* Redistribution and use in source and binary forms, with or without        */
/* modification, are permitted provided that the following conditions        */
/* are met:                                                                  */
/*                                                                           */
/* Redistributions of source code must retain the above copyright            */
/* notice, this list of conditions and the following disclaimer.             */
/*                                                                           */
/* Redistributions in binary form must reproduce the above copyright         */
/* notice, this list of conditions and the following disclaimer in the       */
/* documentation and/or other materials provided with the distribution.      */
/*                                                                           */
/* Neither the name of NXP nor the names of its                              */
/* contributors may be used to endorse or promote products derived from      */
/* this software without specific prior written permission.                  */
/*                                                                           */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,     */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT          */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE         */
/* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH          */
/* DAMAGE.                                                                   */
/*                                                                           */
/*****************************************************************************/
/**
   Filename: phStbFB_UnitTest.c


Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20050519   batelaan    Original
  2 20090120   batelaan    Update file copyright/license text
*/

/** @file
    Simple test program for framebuffer device. Draws some rectangles
    (see bottom of main() function).
*/

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
static long int screensize = 0;
static char *fbbase = 0;

static void rect(unsigned int x, unsigned int y,
                 unsigned int width, unsigned int height,
                 unsigned int r, unsigned int g, unsigned int b)
{
    unsigned int xstart = x;
    unsigned int ystart = y;

    printf("rectangle %d,%d %dx%d rgb=%02x%02x%02x\n", x, y, width, height, r, g, b);
    // Figure out where in memory to put the pixel
    for (y = ystart; y < ystart + height; y++ ) {
        for (x = xstart; x < xstart + width; x++ ) {
            unsigned int offset =
                ((x+vinfo.xoffset) * (vinfo.bits_per_pixel/8)) +
                ((y+vinfo.yoffset) * finfo.line_length);

            if ( vinfo.bits_per_pixel == 32 ) {
                *(fbbase + offset + 0) = b;
                *(fbbase + offset + 1) = g;
                *(fbbase + offset + 2) = r;
                *(fbbase + offset + 3) = 255;      // No transparency
            } else  { //assume 16bpp
                unsigned short int t = r<<11 | g << 5 | b;
                *((unsigned short int*)(fbbase + offset)) = t;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    int fd = 0;
    char *path = argc <= 1 ? "/dev/fb0" : argv[1];

    // Open the framebuffer device
    fd = open(path, O_RDWR);
    if (!fd) {
        printf("Error: cannot open framebuffer device %s\n", path);
        perror(path);
        exit(1);
    }
    printf("The framebuffer device %s was opened successfully.\n", path);

    // Get fixed screen information
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) {
        printf("Error reading fixed information.\n");
        perror(path);
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) {
        printf("Error reading variable information.\n");
        perror(path);
        exit(3);
    }

    printf("Framebuffer is %dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );

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

    // Map the device to memory
    fbbase = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                       fd, 0);
    if ((int)fbbase == -1) {
        printf("Error: failed to map framebuffer device to memory.\n");
        perror(path);
        exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.\n");

    //     x    y    w    h    r    g    b
    rect(200, 200, 200, 200, 255,   0,   0);
    rect(  0,   0, 100,  50,   0, 255,   0);
    rect(  0,   0,  50, 100,   0,   0, 255);

    munmap(fbbase, screensize);
    close(fd);
    return 0;
}
