From 024203b0f98e5e8c3ca0f3d680ff092b435d1802 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Sat, 27 Aug 2022 13:45:24 +0800
Subject: [PATCH] Update fbtest.c, can support show BMP file

---
 /dev/null              |  154 ---------------
 bsp/uapi/test/fbtest.c |  395 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 395 insertions(+), 154 deletions(-)

diff --git a/bsp/uapi/test/fbtest.c b/bsp/uapi/test/fbtest.c
new file mode 100644
index 0000000..91b9d55
--- /dev/null
+++ b/bsp/uapi/test/fbtest.c
@@ -0,0 +1,395 @@
+/********************************************************************************
+ *      Copyright:  (C) 2021 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292>
+ *                  All rights reserved.
+ *
+ *       Filename:  fbtest.c
+ *    Description:  This program used to:
+ *                  1, Show framebuffer device information
+ *                  2, Show RGB color on LCD full screen
+ *                  3, Show BMP file on LCD;
+ *
+ *        Version:  1.0.0(08/26/22)
+ *         Author:  Guo Wenxue <wenxue.guo@avnet.com>
+ *      ChangeLog:  1, Release initial version on "08/26/22 12:56:31"
+ *                 
+ ********************************************************************************/
+#include <stdio.h>  
+#include <stdlib.h>  
+#include <stdint.h>  
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>  
+#include <fcntl.h>  
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/fb.h>  
+#include <sys/mman.h>  
+
+#define PROG_VERSION      "1.0.0"
+
+enum
+{
+    CMD_SHOW_INFO, /* show LCD info  */
+    CMD_SHOW_RGB,  /* show RGB color */
+    CMD_SHOW_BMP,  /* show BMP file  */
+};
+
+typedef struct fb_ctx_s 
+{
+    int                       fd;       /* framebuffer file descriptor */
+    char                      dev[64];  /* framebuffer device name */
+    long                      fb_size;  /* framebuffer size */
+    int                       pix_size; /* lcd screen pix size  */
+    struct fb_var_screeninfo  vinfo;    /* framebuffer var information */
+    char                     *fbp;      /* framebuffer mmap() address */
+} fb_ctx_t; 
+
+
+int fb_init(fb_ctx_t *fb_ctx);
+int fb_term(fb_ctx_t *fb_ctx);
+int show_rgb(fb_ctx_t *fb_ctx, int times);
+int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file);
+
+static void program_usage(char *progname)
+{
+    printf("Usage: %s [OPTION]...\n", progname);
+    printf(" %s is a program to show RGB color or BMP file on LCD screen\n", progname);
+
+    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
+    printf(" -d[device  ]  Specify framebuffer device, such as: /dev/fb0\n");
+    printf(" -c[color   ]  Display RGB corlor on LCD screen for some times, such as: -c 3\n");
+    printf(" -b[bmp     ]  Display BMP file, such as: -b bg.bmp\n");
+    printf(" -h[help    ]  Display this help information\n");
+    printf(" -v[version ]  Display the program version\n");
+
+    printf("\n%s version %s\n", progname, PROG_VERSION);
+    return;
+}
+
+int main (int argc, char **argv)
+{  
+    fb_ctx_t                  fb_ctx;
+    char                     *progname=NULL;
+    char                     *bmp_file=NULL;
+    char                     *fb_dev="/dev/fb0";
+    int                       cmd = CMD_SHOW_INFO;
+    int                       opt, times;
+
+    struct option long_options[] = { 
+        {"device", required_argument, NULL, 'd'},
+        {"color", required_argument, NULL, 'c'},
+        {"bmp", required_argument, NULL, 'b'},
+        {"version", no_argument, NULL, 'v'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };
+
+    progname = (char *)basename(argv[0]);
+
+    /* Parser the command line parameters */
+    while ((opt = getopt_long(argc, argv, "d:c:b:vh", long_options, NULL)) != -1)
+    {
+        switch (opt)
+        {
+            case 'd': /* Set framebuffer device */
+                 fb_dev = optarg;
+                break;
+
+            case 'b': /* Set BMP file */
+                bmp_file = optarg;
+                cmd = CMD_SHOW_BMP;
+                break;
+
+            case 'c': /* Show RGB color */
+                times = atoi(optarg);
+                cmd = CMD_SHOW_RGB;
+                break;
+
+            case 'v':  /* Get software version */
+                printf("%s version %s\n", progname, PROG_VERSION);
+                return 0;
+
+            case 'h':  /* Get help information */
+                program_usage(progname);
+                return 0;
+
+            default:
+                break;
+        }
+
+    }
+
+    memset(&fb_ctx, 0, sizeof(fb_ctx));
+    strncpy(fb_ctx.dev, fb_dev, sizeof(fb_ctx.dev));
+
+    if( fb_init(&fb_ctx) < 0 )
+    {
+        printf("ERROR: Initial framebuffer device '%s' failure.\n", fb_ctx.dev);
+        return 1;
+    }
+
+    switch( cmd )
+    {
+        case CMD_SHOW_RGB:
+            show_rgb(&fb_ctx, times);
+            break;
+
+        case CMD_SHOW_BMP:
+            show_bmp(&fb_ctx, bmp_file);
+            break;
+
+        default:
+            break;
+    }
+
+    fb_term(&fb_ctx);
+
+    return 0;
+}
+
+
+int fb_get_var_screeninfo(int fd, struct fb_var_screeninfo *vinfo)
+{
+    if( fd<0 || !vinfo )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+ 
+    if(ioctl(fd, FBIOGET_VSCREENINFO, vinfo))
+    {
+        printf("ERROR: ioctl() get variable info failure: %s\n", strerror(errno));  
+        return -2;
+    }  
+
+    printf("LCD information : %dx%d, bpp:%d rgba:%d/%d,%d/%d,%d/%d,%d/%d\n", vinfo->xres, vinfo->yres, vinfo->bits_per_pixel,
+            vinfo->red.length, vinfo->red.offset, vinfo->green.length, vinfo->green.offset, 
+			vinfo->blue.length,vinfo->blue.offset, vinfo->transp.length, vinfo->transp.offset);
+
+    return 0;
+}
+
+int fb_init(fb_ctx_t *fb_ctx)
+{
+    struct fb_var_screeninfo    *vinfo;
+
+    if( !fb_ctx || !strlen(fb_ctx->dev) )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    if( (fb_ctx->fd=open(fb_ctx->dev, O_RDWR)) < 0 )
+    {
+        printf("ERROR: Open framebuffer device '%s' failure: %s\n", fb_ctx->dev, strerror(errno));  
+        return -2;
+    } 
+
+    fb_get_var_screeninfo(fb_ctx->fd, &fb_ctx->vinfo);
+
+    vinfo = &fb_ctx->vinfo;
+    fb_ctx->fb_size = vinfo->xres * vinfo->yres * vinfo->bits_per_pixel / 8;  
+    fb_ctx->pix_size = vinfo->xres * vinfo->yres;
+
+    fb_ctx->fbp =(char *)mmap(0, fb_ctx->fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_ctx->fd ,0);  
+    if ( !fb_ctx->fbp )  
+    {    
+        printf ("ERROR: Framebuffer mmap() failure: %s\n", strerror(errno));  
+        return -2;
+    }
+
+    vinfo->xoffset = 0;
+    vinfo->yoffset = 0;
+
+    return 0;
+}
+
+int fb_term(fb_ctx_t *fb_ctx)
+{
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    munmap(fb_ctx->fbp, fb_ctx->fb_size);
+    close (fb_ctx->fd);
+ 
+    return 0;
+}
+
+int show_rgb_screen(fb_ctx_t *fb_ctx)
+{
+    struct fb_var_screeninfo    *vinfo;
+    char                        *fb_addr;
+    int                          interval = 1;
+    int                          i, color;
+    int                          bpp_bytes;
+
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    vinfo = &fb_ctx->vinfo;
+    bpp_bytes = vinfo->bits_per_pixel / 8;
+
+    printf("show full screen on red\n");
+    color = (1<<vinfo->red.length-1) << vinfo->red.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    printf("show full screen on green\n");
+    color = (1<<vinfo->green.length-1) << vinfo->green.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    printf("show full screen on blue\n");
+    color = (1<<vinfo->blue.length-1) << vinfo->blue.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    return 0;
+}
+
+int show_rgb(fb_ctx_t *fb_ctx, int times)
+{
+    int       i;
+
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    for(i=0; i<times; i++)
+    {
+        show_rgb_screen(fb_ctx);
+    }
+
+    return 0;
+}
+
+
+/* BMP format: https://blog.csdn.net/weixin_39756273/article/details/110585675  */
+typedef struct bmp_file_head_s 
+{
+    uint8_t  bfType[2];        /* BMP file type: "BM" */
+    int32_t bfSize;           /* BMP file size */
+    int32_t bfReserved;       /* reserved */
+    int32_t bfoffBits;        /* image data offset */
+}__attribute__((packed)) bmp_file_head_t; 
+
+
+typedef struct bmp_bitmap_info_s 
+{
+    int32_t biSize;           /* this struture size */
+    int32_t biWidth;          /* image width in pix */
+    int32_t biHeight;         /* image height in pix */
+    uint16_t biPlanes;         /* display planes, always be 1 */
+    uint16_t biBitCount;       /* bpp: 1,4,8,16,24,32 */
+    int32_t biCompress;       /* compress type */
+    int32_t biSizeImage;      /* image size in byte */
+    int32_t biXPelsPerMeter;  /* x-res in pix/m */
+    int32_t biYPelsPerMeter;  /* y-res in pix/m */
+    int32_t biClrUsed;
+    int32_t biClrImportant;
+}__attribute__((packed)) bmp_bitmap_info_t; 
+
+/*
+ * BMP image file format:
+ * +----------------+------------------+--------------------+---------------+
+ * | File Head(14B) | Bitmap Info(40B) | color palette(OPT) |  bitmap data  |
+ * +----------------+------------------+--------------------+---------------+
+ */
+int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file)
+{
+    struct fb_var_screeninfo    *vinfo;
+    char                        *fb_addr;
+    bmp_file_head_t            *file_head;
+    bmp_bitmap_info_t          *bitmap_info;
+    struct stat                 statbuf;
+    char                       *f_addr;
+    char                       *d_addr;
+    char                       *p_addr;
+    int                         fd;
+    int                         bpp_bytes;
+    int                         i, j;
+	int                         width, height;
+
+    if( !fb_ctx || !bmp_file )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    if( (fd=open(bmp_file, O_RDONLY)) < 0 )
+    {
+        printf("ERROR: Open file '%s' failure: %s\n", bmp_file, strerror(errno));
+        return -2;
+    }
+
+    fstat(fd, &statbuf);
+    f_addr =(char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd ,0);  
+    if ( !f_addr )   
+    {    
+        printf ("ERROR: BMP file mmap() failure: %s\n", strerror(errno));  
+        return -2; 
+    }   
+
+    /* BMP file header */
+    file_head = (bmp_file_head_t *)f_addr;
+    if( memcmp(file_head->bfType, "BM", 2) != 0)  
+    {
+        printf("ERROR: It's not a BMP file\n");
+        return -3;
+    }
+
+    /* BMP bitmap information header */
+    bitmap_info = (bmp_bitmap_info_t *)(f_addr+sizeof(bmp_file_head_t));
+
+    /* BMP bitmap data */
+    d_addr = f_addr + file_head->bfoffBits;
+
+    vinfo = &fb_ctx->vinfo;
+    fb_addr = fb_ctx->fbp;
+    bpp_bytes = vinfo->bits_per_pixel / 8;
+
+    width = bitmap_info->biWidth>vinfo->xres ? vinfo->xres : bitmap_info->biWidth;
+    height = bitmap_info->biHeight>vinfo->yres ? vinfo->yres : bitmap_info->biHeight;
+
+    printf("BMP file '%s': %dx%d and display %dx%d\n", bmp_file, bitmap_info->biWidth, bitmap_info->biHeight, width, height);
+
+	/* if biHeight is positive, the bitmap is a bottom-up DIB */
+	for(i=0; i<height; i++)
+	{
+		p_addr=d_addr+(height-1-i)*bitmap_info->biWidth*bpp_bytes;
+		memcpy(fb_addr, p_addr, bpp_bytes*width);
+		fb_addr += bpp_bytes * vinfo->xres;
+	}
+
+    munmap(f_addr, statbuf.st_size);
+    close (fd);
+
+    return 0;
+}
+
diff --git a/bsp/uapi/test/test_fb.c b/bsp/uapi/test/test_fb.c
deleted file mode 100644
index 2010d23..0000000
--- a/bsp/uapi/test/test_fb.c
+++ /dev/null
@@ -1,154 +0,0 @@
-
-/*********************************************************************************
- *      Copyright:  (C) 2021 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292>
- *                  All rights reserved.
- *
- *       Filename:  test_key.c
- *    Description:  This file used to test GPIO button driver builtin Linux kernel on ARM board
- *                 
- *        Version:  1.0.0(11/17/2021~)
- *         Author:  Guo Wenxue <guowenxue@gmail.com>
- *      ChangeLog:  1, Release initial version on "11/17/2021 02:46:18 PM"
- *                 
- *     Linux Clear LCD screen command : 
- *
- *                  dd if=/dev/zero of=/dev/fb0 bs=320 count=720  [ 240*(24bpp/8)=720 ] 
- *
- ********************************************************************************/
- 
-#include <unistd.h>  
-#include <stdio.h>  
-#include <fcntl.h>  
-#include <linux/fb.h>  
-#include <sys/mman.h>  
-#include <stdlib.h>  
-#include <string.h>
-#include <sys/ioctl.h>
-
-
-#define CONFIG_RGB565
-
-#ifdef  CONFIG_RGB565  /* RRRR RGGG GGGB BBBB  */
-#define RED       0xF800
-#define GREEN     0x07E0
-#define BLUE      0x001F
-#define YELLOW    0xFFE0
-#define WHITE     0xFFFF 
-#endif
-
-
-void fill_color16(short *fb_addr, short bit_map, int psize)
-{
-    int i;
-    for(i=0; i<psize; i++) {
-        *fb_addr = bit_map;
-        fb_addr++;
-    }
-}
-
-int main ()   
-{  
-    int fp=0;  
-    struct fb_var_screeninfo vinfo;  
-    struct fb_fix_screeninfo finfo;  
-    long screensize=0;  
-    char *fbp = NULL, *test_fbp=NULL;    
-    int x = 0, y = 0;  
-    long location = 0;
-    int i;
-    int num = 5;
-    int pix_size=0;
-
-    fp = open("/dev/fb0", O_RDWR);  
-
-    if(fp < 0) {  
-        printf("Error : Can not open framebuffer device/n");  
-        exit(1);  
-    }  
-
-    if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){  
-        printf("Error reading fixed information/n");  
-        exit(2);  
-    }  
-
-    if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){  
-        printf("Error reading variable information/n");  
-        exit(3);  
-    }  
-
-    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
-
-    printf("The phy mem = 0x%x, total size = %d(byte)\n", finfo.smem_start, finfo.smem_len);  
-    printf("xres =  %d, yres =  %d, bits_per_pixel = %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);  
-    printf("So the screensize = %d(byte), using %d frame\n", screensize, finfo.smem_len/screensize);
-    printf("vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset);  
-    printf("vinfo.vmode is :%d\n", vinfo.vmode);  
-    printf("finfo.ypanstep is :%d\n", finfo.ypanstep);  
-    printf("vinfo.red.offset=0x%x\n", vinfo.red.offset);
-    printf("vinfo.red.length=0x%x\n", vinfo.red.length);
-    printf("vinfo.green.offset=0x%x\n", vinfo.green.offset);
-    printf("vinfo.green.length=0x%x\n", vinfo.green.length);
-    printf("vinfo.blue.offset=0x%x\n", vinfo.blue.offset);
-    printf("vinfo.blue.length=0x%x\n", vinfo.blue.length);
-    printf("vinfo.transp.offset=0x%x\n", vinfo.transp.offset);
-    printf("vinfo.transp.length=0x%x\n", vinfo.transp.length);
-    
-
-    fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);  
-    if ((int)fbp == -1)  
-    {    
-        printf ("Error: failed to map framebuffer device to memory./n");  
-        exit (4);  
-    }
-    printf("Get virt mem = %p\n", fbp);  
-
-
-    pix_size = vinfo.xres * vinfo.yres;
-    /* using first frame, for FBIOPAN_DISPLAY
-     * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
-     * 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;
-     */
-    vinfo.xoffset = 0;
-    vinfo.yoffset = 0;
-
-    /* show color loop */
-    while(num--) {
-        printf("\ndrawing red ...\n");
-        fill_color16((short *)fbp, RED, pix_size);
-        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
-        sleep(3);
-
-        printf("\ndrawing green ...\n");
-        fill_color16((short *)fbp, GREEN, pix_size);
-        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
-        sleep(3);
-
-        printf("\ndrawing blue ...\n");
-        fill_color16((short *)fbp, BLUE, pix_size);
-        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
-        sleep(3);
-        
-        printf("\ndrawing yellow ...\n");
-        fill_color16((short *)fbp, YELLOW, pix_size);
-        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
-        sleep(3);
-
-    }
-#if 1
-    /*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/    
-    x = 10;  
-    y = 10;  
-    location = x * (vinfo.bits_per_pixel / 8) + y  *  finfo.line_length;  
-    test_fbp = fbp + location;
-    printf("draw line.......\n");
-    for(i = 0; i < (vinfo.xres - x); i++)
-        *test_fbp++ = i+30;
-
-    //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
-#endif
-
-    munmap(fbp, screensize); /*解除映射*/  
-
-    close (fp);
-    return 0;
-}

--
Gitblit v1.9.1