graphlcd-base/glcddrivers/framebuffer.c
author root@rika
Wed, 06 Feb 2008 17:32:55 +0000
changeset 4 df6a40031aa5
permissions -rw-r--r--
added graphlcd-base
     1 /*
     2  * GraphLCD driver library
     3  *
     4  * framebuffer.h  -  framebuffer device
     5  *                   Output goes to a framebuffer device
     6  *
     7  * This file is released under the GNU General Public License. Refer
     8  * to the COPYING file distributed with this package.
     9  *
    10  * (c) 2004 Stephan Skrodzki
    11  */
    12 
    13 #include <fcntl.h>
    14 #include <stdio.h>
    15 #include <syslog.h>
    16 #include <unistd.h>
    17 #include <sys/mman.h>
    18 #include <sys/ioctl.h>
    19 
    20 #include "common.h"
    21 #include "config.h"
    22 #include "framebuffer.h"
    23 
    24 
    25 namespace GLCD
    26 {
    27 
    28 cDriverFramebuffer::cDriverFramebuffer(cDriverConfig * config)
    29 :   config(config),
    30     offbuff(0),
    31     fbfd(-1)
    32 {
    33     oldConfig = new cDriverConfig(*config);
    34 }
    35 
    36 cDriverFramebuffer::~cDriverFramebuffer()
    37 {
    38     delete oldConfig;
    39 }
    40 
    41 int cDriverFramebuffer::Init()
    42 {
    43     // default values
    44     width = config->width;
    45     if (width <= 0)
    46         width = 320;
    47     height = config->height;
    48     if (height <= 0)
    49         height = 240;
    50     zoom = 1;
    51 
    52     for (unsigned int i = 0; i < config->options.size(); i++)
    53     {
    54         if (config->options[i].name == "Zoom")
    55         {
    56             int z = atoi(config->options[i].value.c_str());
    57             if (z == 0 || z == 1)
    58                 zoom = z;
    59             else
    60                 syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n",
    61                        config->name.c_str(), z, zoom);
    62         }
    63     }
    64 
    65     // Open the file for reading and writing
    66     fbfd = open("/dev/fb0", O_RDWR);
    67     if (1 == fbfd)
    68     {
    69         syslog(LOG_ERR, "%s: cannot open framebuffer device.\n", config->name.c_str());
    70         return -1;
    71     }
    72     syslog(LOG_INFO, "%s: The framebuffer device was opened successfully.\n", config->name.c_str());
    73 
    74     // Get fixed screen information
    75     if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
    76     {
    77         syslog(LOG_ERR, "%s: Error reading fixed information.\n", config->name.c_str());
    78         return -1;
    79     }
    80 
    81     // Get variable screen information
    82     if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
    83     {
    84         syslog(LOG_ERR, "%s: Error reading variable information.\n", config->name.c_str());
    85         return -1;
    86     }
    87 
    88     // Figure out the size of the screen in bytes
    89     screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
    90 
    91     syslog(LOG_INFO, "%s: V01: xres: %d, yres %d, vyres: %d, bpp: %d, linelenght: %d\n", config->name.c_str(),vinfo.xres,vinfo.yres,vinfo.yres_virtual,vinfo.bits_per_pixel,finfo.line_length);
    92 
    93     // reserve another memory to draw into
    94     offbuff = new char[screensize];
    95     if (!offbuff)
    96     {
    97         syslog(LOG_ERR, "%s: failed to alloc memory for framebuffer device.\n", config->name.c_str());
    98         return -1;
    99     }
   100 
   101     // Map the device to memory
   102     fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
   103     if (fbp == MAP_FAILED)
   104     {
   105         syslog(LOG_ERR, "%s: failed to map framebuffer device to memory.\n", config->name.c_str());
   106         return -1;
   107     }
   108     syslog(LOG_INFO, "%s: The framebuffer device was mapped to memory successfully.\n", config->name.c_str());
   109 
   110     *oldConfig = *config;
   111 
   112     // clear display
   113     Refresh(true);
   114 
   115     syslog(LOG_INFO, "%s: Framebuffer initialized.\n", config->name.c_str());
   116     return 0;
   117 }
   118 
   119 int cDriverFramebuffer::DeInit()
   120 {
   121     if (offbuff)
   122         delete[] offbuff;
   123     munmap(fbp, screensize);
   124     if (-1 != fbfd)
   125         close(fbfd);
   126     return 0;
   127 }
   128 
   129 int cDriverFramebuffer::CheckSetup()
   130 {
   131     if (config->device != oldConfig->device ||
   132         config->port != oldConfig->port ||
   133         config->width != oldConfig->width ||
   134         config->height != oldConfig->height)
   135     {
   136         DeInit();
   137         Init();
   138         return 0;
   139     }
   140 
   141     if (config->upsideDown != oldConfig->upsideDown ||
   142         config->invert != oldConfig->invert)
   143     {
   144         oldConfig->upsideDown = config->upsideDown;
   145         oldConfig->invert = config->invert;
   146         return 1;
   147     }
   148     return 0;
   149 }
   150 
   151 void cDriverFramebuffer::SetPixel(int x, int y)
   152 {
   153     int location;
   154     int outcol;
   155 
   156     if (x >= width || y >= height)
   157         return;
   158 
   159     if (config->upsideDown)
   160     {
   161         x = width - 1 - x;
   162         y = height - 1 - y;
   163     }
   164 
   165     // Figure out where in memory to put the pixel
   166     location = (x*(1+zoom)+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
   167                (y*(1+zoom)+vinfo.yoffset) * finfo.line_length;
   168 
   169     if (vinfo.bits_per_pixel <= 8)
   170     {
   171         outcol = 15;
   172     }
   173     else
   174     {
   175         outcol = 255;
   176     }
   177 
   178     if (vinfo.bits_per_pixel <= 8)
   179     {
   180         *(offbuff + location) = outcol;
   181         if (zoom == 1)
   182         {
   183             *(offbuff + location + 1) = outcol;
   184             *(offbuff + location + finfo.line_length) = outcol;
   185             *(offbuff + location + finfo.line_length + 1) = outcol;
   186         }
   187     }
   188     else if (vinfo.bits_per_pixel <= 16)
   189     {
   190         *(offbuff + location) = outcol;
   191         *(offbuff + location + 1) = outcol;
   192         if (zoom == 1)
   193         {
   194             *(offbuff + location + 2) = outcol;
   195             *(offbuff + location + 3) = outcol;
   196             *(offbuff + location + finfo.line_length) = outcol;
   197             *(offbuff + location + finfo.line_length + 1) = outcol;
   198             *(offbuff + location + finfo.line_length + 2) = outcol;
   199             *(offbuff + location + finfo.line_length + 3) = outcol;
   200         }
   201     }
   202     else
   203     {
   204         *(offbuff + location) = outcol;
   205         *(offbuff + location + 1) = outcol;
   206         *(offbuff + location + 2) = outcol;
   207         *(offbuff + location + 3) = 0;     /* should be transparency */
   208         if (zoom == 1)
   209         {
   210             *(offbuff + location + 4) = outcol;
   211             *(offbuff + location + 5) = outcol;
   212             *(offbuff + location + 6) = outcol;
   213             *(offbuff + location + 7) = 0;
   214             *(offbuff + location + finfo.line_length) = outcol;
   215             *(offbuff + location + finfo.line_length + 1) = outcol;
   216             *(offbuff + location + finfo.line_length + 2) = outcol;
   217             *(offbuff + location + finfo.line_length + 3) = 0;
   218             *(offbuff + location + finfo.line_length + 4) = outcol;
   219             *(offbuff + location + finfo.line_length + 5) = outcol;
   220             *(offbuff + location + finfo.line_length + 6) = outcol;
   221             *(offbuff + location + finfo.line_length + 7) = 0;
   222         }
   223     }
   224 }
   225 
   226 void cDriverFramebuffer::Clear()
   227 {
   228     memset(offbuff, 0, screensize);
   229 }
   230 
   231 void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data)
   232 {
   233     int n;
   234 
   235     x &= 0xFFF8;
   236 
   237     for (n = 0; n < 8; ++n)
   238     {
   239         if (data & (0x80 >> n))      // if bit is set
   240             SetPixel(x + n, y);
   241     }
   242 }
   243 
   244 void cDriverFramebuffer::Refresh(bool refreshAll)
   245 {
   246     memcpy(fbp, offbuff, screensize);
   247 }
   248 
   249 } // end of namespace