嵌入式调试显示屏,可能用过tslib,其中有些代码拿出来就是对linux fb不错的封装。
例如如下程序,就是tslib中的部分代码,大家可以直接使用,或者再加工修改:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <fcntl.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/fb.h>
/*****************************************************************************
*
* Macro definition
*
*****************************************************************************/
//
#define VTNAME_LEN (128)
/*****************************************************************************
*
* Structure/Class Definition
*
*****************************************************************************/
union multiptr {
uint8_t *p8;
uint16_t *p16;
uint32_t *p32;
};
/*****************************************************************************
*
* Data definition
*
*****************************************************************************/
static int32_t con_fd = -1;
static int32_t last_vt = -1;
static struct fb_fix_screeninfo fix;
static struct fb_var_screeninfo var;
static unsigned char *fbuffer = NULL;
static unsigned char **line_addr = NULL;
static int32_t fb_fd;
static int32_t bytes_per_pixel;
static uint32_t transp_mask;
uint32_t xres, yres;
uint32_t xres_orig, yres_orig;
int8_t rotation;
// 0 ... no rotation; 0 degree (default)
// 1 ... clockwise orientation; 90 degrees
// 2 ... upside down orientation; 180 degrees
// 3 ... counterclockwise orientation; 270 degrees
static const char *defaultfbdevice = "/dev/fb0";
//static char *defaultconsoledevice = "/dev/tty";
static const char *fbdevice;
static const char *consoledevice;
/*****************************************************************************
*
* Function Entity
*
*****************************************************************************/
int FbOpen(const char *fb_dev, const char * console_dev, uint32_t *max_width, uint32_t *max_height)
{
struct vt_stat vts;
char vtname[VTNAME_LEN];
int32_t fd, nr;
uint32_t y, addr;
//
if (NULL == fb_dev)
{
fbdevice = defaultfbdevice;
}
else
{
fbdevice = fb_dev;
}
//
if (NULL == console_dev)
{
consoledevice = "none";
}
else
{
consoledevice = console_dev;
}
if (strcmp(consoledevice, "none") != 0)
{
if (strlen(consoledevice) >= VTNAME_LEN)
{
return -1;
}
sprintf(vtname, "%s%d", consoledevice, 1);
fd = open(vtname, O_WRONLY);
if (fd < 0)
{
perror("open consoledevice");
return -1;
}
if (ioctl(fd, VT_OPENQRY, &nr) < 0)
{
close(fd);
perror("ioctl VT_OPENQRY");
return -1;
}
close(fd);
sprintf(vtname, "%s%d", consoledevice, nr);
con_fd = open(vtname, O_RDWR | O_NDELAY);
if (con_fd < 0)
{
perror("open tty");
return -1;
}
if (ioctl(con_fd, VT_GETSTATE, &vts) == 0)
last_vt = vts.v_active;
if (ioctl(con_fd, VT_ACTIVATE, nr) < 0)
{
perror("VT_ACTIVATE");
close(con_fd);
return -1;
}
#ifndef TSLIB_NO_VT_WAITACTIVE
if (ioctl(con_fd, VT_WAITACTIVE, nr) < 0)
{
perror("VT_WAITACTIVE");
close(con_fd);
return -1;
}
#endif
if (ioctl(con_fd, KDSETMODE, KD_GRAPHICS) < 0)
{
perror("KDSETMODE");
close(con_fd);
return -1;
}
}
fb_fd = open(fbdevice, O_RDWR);
if (fb_fd == -1)
{
perror("open fbdevice");
return -1;
}
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0)
{
perror("ioctl FBIOGET_FSCREENINFO");
close(fb_fd);
return -1;
}
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0)
{
perror("ioctl FBIOGET_VSCREENINFO");
close(fb_fd);
return -1;
}
xres_orig = var.xres;
yres_orig = var.yres;
if (rotation & 1)
{
/* 1 or 3 */
y = var.yres;
yres = var.xres;
xres = y;
}
else
{
/* 0 or 2 */
xres = var.xres;
yres = var.yres;
}
fbuffer = mmap(NULL,
fix.smem_len,
PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED,
fb_fd,
0);
if (fbuffer == (unsigned char *)-1)
{
printf("%s - smem_len = %d, fb = %d\n\r", __func__, fix.smem_len, fb_fd);
perror("mmap framebuffer");
close(fb_fd);
return -1;
}
memset(fbuffer, 0, fix.smem_len);
bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
transp_mask = ((1 << var.transp.length) - 1) << var.transp.offset; // transp.length unlikely > 32
line_addr = malloc(sizeof(*line_addr) * var.yres_virtual);
addr = 0;
for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
{
line_addr[y] = fbuffer + addr;
}
if (max_width != NULL && max_height != NULL)
{
*max_width = xres;
*max_height = yres;
}
return 0;
}
void FbClose(void)
{
memset(fbuffer, 0, fix.smem_len);
munmap(fbuffer, fix.smem_len);
close(fb_fd);
if (strcmp(consoledevice, "none") != 0)
{
if (ioctl(con_fd, KDSETMODE, KD_TEXT) < 0)
{
perror("KDSETMODE");
}
if (last_vt >= 0)
{
if (ioctl(con_fd, VT_ACTIVATE, last_vt))
{
perror("VT_ACTIVATE");
}
}
close(con_fd);
}
free(line_addr);
xres = 0;
yres = 0;
rotation = 0;
fbuffer = NULL;
line_addr = NULL;
}
static void __PixelLocate(int32_t x, int32_t y, union multiptr *loc)
{
if (NULL == line_addr)
{
loc->p8 = NULL;
return;
}
switch (rotation)
{
case 0:
default:
loc->p8 = line_addr[y] + x * bytes_per_pixel;
break;
case 1:
loc->p8 = line_addr[x] + (yres - y - 1) * bytes_per_pixel;
break;
case 2:
loc->p8 = line_addr[yres - y - 1] + (xres - x - 1) * bytes_per_pixel;
break;
case 3:
loc->p8 = line_addr[xres - x - 1] + y * bytes_per_pixel;
break;
}
}
static inline void __SetPixel(union multiptr loc, uint32_t xormode, uint32_t color)
{
if (NULL == loc.p8)
{
return;
}
switch (bytes_per_pixel)
{
case 1:
default:
if (xormode)
*loc.p8 ^= color;
else
*loc.p8 = color;
break;
case 2:
if (xormode)
*loc.p16 ^= color;
else
*loc.p16 = color;
break;
case 3:
if (xormode)
{
*loc.p8++ ^= (color >> 16) & 0xff;
*loc.p8++ ^= (color >> 8) & 0xff;
*loc.p8 ^= color & 0xff;
}
else
{
*loc.p8++ = (color >> 16) & 0xff;
*loc.p8++ = (color >> 8) & 0xff;
*loc.p8 = color & 0xff;
}
break;
case 4:
if (xormode)
*loc.p32 ^= color;
else
*loc.p32 = color;
break;
}
}
// 绘制一个像素点
void FbDrawPixel(int32_t x, int32_t y, uint32_t color)
{
uint32_t xormode;
union multiptr loc;
if ((x < 0) || ((uint32_t)x >= xres) || (y < 0) || ((uint32_t)y >= yres))
{
return;
}
xormode = 0;
__PixelLocate(x, y, &loc);
__SetPixel(loc, xormode, color);
}
// 绘制一条直线,任何2点之间的直线
void FbDrawBeeLine(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, uint32_t color)
{
int32_t tmp;
int32_t distance_x = x_end - x_start;
int32_t distance_y = y_end - y_start;
if (abs(distance_x) < abs(distance_y))
{
if (y_start > y_end)
{
tmp = x_start;
x_start = x_end;
x_end = tmp;
tmp = y_start;
y_start = y_end;
y_end = tmp;
distance_x = -distance_x;
distance_y = -distance_y;
}
x_start <<= 16;
// distance_y is apriori > 0
distance_x = (distance_x << 16) / distance_y;
while (y_start <= y_end)
{
FbDrawPixel(x_start >> 16, y_start, color);
x_start += distance_x;
y_start++;
}
}
else
{
if (x_start > x_end)
{
tmp = x_start;
x_start = x_end;
x_end = tmp;
tmp = y_start;
y_start = y_end;
y_end = tmp;
distance_x = -distance_x;
distance_y = -distance_y;
}
y_start <<= 16;
distance_y = distance_x ? (distance_y << 16) / distance_x : 0;
while (x_start <= x_end)
{
FbDrawPixel(x_start, y_start >> 16, color);
y_start += distance_y;
x_start ++;
}
}
}
// 绘制一个矩形框
void FbDrawRectLine(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, uint32_t color)
{
FbDrawBeeLine(x_start, y_start, x_end, y_start, color);
FbDrawBeeLine(x_end, y_start + 1, x_end, y_end - 1, color);
FbDrawBeeLine(x_end, y_end, x_start, y_end, color);
FbDrawBeeLine(x_start, y_end - 1, x_start, y_start + 1, color);
}
void CoordinateChk(int32_t *x_start, int32_t *y_start, int32_t *x_end, int32_t *y_end)
{
int32_t x_loc;
int32_t y_loc;
// Clipping and sanity checking
if (*x_start > *x_end)
{
x_loc = *x_start;
*x_start = *x_end;
*x_end = x_loc;
}
if (*y_start > *y_end)
{
y_loc = *y_start;
*y_start = *y_end;
*y_end = y_loc;
}
if (*x_start < 0)
{
*x_start = 0;
}
if ((uint32_t)(*x_start) >= xres)
{
*x_start = xres - 1;
}
if (*x_end < 0)
{
*x_end = 0;
}
if ((uint32_t)(*x_end) >= xres)
{
*x_end = xres - 1;
}
if (*y_start < 0)
{
*y_start = 0;
}
if ((uint32_t)(*y_start) >= yres)
{
*y_start = yres - 1;
}
if (*y_end < 0)
{
*y_end = 0;
}
if ((uint32_t)(*y_end) >= yres)
{
*y_end = yres - 1;
}
}
// 绘制一个实心矩形
void FbFillRect(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, uint32_t color)
{
int32_t x_loc;
int32_t y_loc;
uint32_t xormode = 0;
union multiptr loc;
// Clipping and sanity checking
CoordinateChk(&x_start, &y_start, &x_end, &y_end);
if ((x_start > x_end) || (y_start > y_end))
{
return;
}
//
for (y_loc = y_start; y_loc <= y_end; ++y_loc)
{
for (x_loc = x_start; x_loc <= x_end; ++x_loc)
{
__PixelLocate(x_loc, y_loc, &loc);
__SetPixel(loc, xormode, color);
//loc.p8 += bytes_per_pixel;
}
}
}
// 根据输入的图像,绘制一个矩形图案,图案为ARGB
void FbFillRectPicture(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, uint32_t *pic_color)
{
int32_t x_loc;
int32_t y_loc;
int32_t height;
int32_t width;
uint32_t xormode = 0;
union multiptr loc;
// Clipping and sanity checking
CoordinateChk(&x_start, &y_start, &x_end, &y_end);
if ((x_start > x_end) || (y_start > y_end))
{
return;
}
//
height = y_end - y_start + 1;
width = x_end - x_start + 1;
//
for (y_loc = y_start; y_loc <= y_end; ++y_loc)
{
for (x_loc = x_start; x_loc <= x_end; ++x_loc)
{
__PixelLocate(x_loc, y_loc, &loc);
__SetPixel(loc, xormode, pic_color[x_loc - x_start]);
}
pic_color += width;
}
}
// 绘制一个单色矩形图案,将输入的8bit像素值,拷贝到RGB
void FbFillRectPictureByYUV400(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, uint8_t *pic_color)
{
int32_t x_loc;
int32_t y_loc;
int32_t height;
int32_t width;
uint32_t xormode = 0;
uint32_t color;
union multiptr loc;
// Clipping and sanity checking
CoordinateChk(&x_start, &y_start, &x_end, &y_end);
if ((x_start > x_end) || (y_start > y_end))
{
return;
}
//
height = y_end - y_start + 1;
width = x_end - x_start + 1;
//printf("%s - x_start = %d, x_end = %d, width = %d\n\r", __func__, x_start, x_end, width);
//printf("%s - y_start = %d, y_end = %d, width = %d\n\r", __func__, y_start, y_end, height);
//
for (y_loc = y_start; y_loc <= y_end; ++y_loc)
{
for (x_loc = x_start; x_loc <= x_end; ++x_loc)
{
color = 0xff000000 | (pic_color[x_loc - x_start] << 16) | (pic_color[x_loc - x_start] << 8) | (pic_color[x_loc - x_start]);
__PixelLocate(x_loc, y_loc, &loc);
__SetPixel(loc, xormode, color);
}
pic_color += width;
}
}