/*
 * Python extension module to rescale a framebuffer image into a Python string
 *
 * Written by Andrew Pam <andrew@sericyb.com.au>
 * Copyright (c) 2003, 2011 Serious Cybernetics
 */

#include <Python.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

/* Thumbnail window should be 256x144 (1/4 size at 16:9 aspect ratio) */
#define THUMBWIDTH (256)
#define THUMBHEIGHT (144)

#define BUFBYTES (3)	/* 24bpp */
#define BUFLEN (THUMBWIDTH * THUMBHEIGHT * BUFBYTES)

char buf[BUFLEN];
int fd;
char *fb;
int fb_bytes;
struct fb_fix_screeninfo fix_info;
struct fb_var_screeninfo var_info;

static PyObject *
fb_open(PyObject *self, PyObject *args)
{
	const char *device;

	if (!PyArg_ParseTuple(args, "s", &device))
		return NULL;
	fd = open(device, O_RDONLY);
	if (!fd)
		return NULL;
	if (ioctl(fd, FBIOGET_FSCREENINFO, (char *) &fix_info))
		return NULL;
	if (fix_info.type != FB_TYPE_PACKED_PIXELS)
		return NULL;
	if (fix_info.visual != FB_VISUAL_TRUECOLOR)
		return NULL;
	if (ioctl(fd, FBIOGET_VSCREENINFO, (char *) &var_info))
		return NULL;
	fb_bytes = var_info.bits_per_pixel / 8;
	fb = (char *) mmap(NULL, fix_info.smem_len, PROT_READ, MAP_SHARED, fd, 0);
	if (!fb)
		return NULL;
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
fb_close(PyObject *self, PyObject *args)
{
	munmap(fb, fix_info.smem_len);
	close(fd);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
fb_getbuf(PyObject *self, PyObject *args)
{
	int buf_ix = 0;
	int line_ix = 0;
	int x, y;
	int dy = 0;

	for (y = 0; y < THUMBHEIGHT; y++)
	{
		int fb_ix = line_ix;
		int dx = 0;
		for (x = 0; x < THUMBWIDTH; x++)
		{
			buf[buf_ix++] = fb[fb_ix + 2];	/* Red */
			buf[buf_ix++] = fb[fb_ix + 1];	/* Green */
			buf[buf_ix++] = fb[fb_ix];	/* Blue */
			for (; dx < var_info.xres; dx += THUMBWIDTH)
			{ fb_ix += fb_bytes; }
			dx -= var_info.xres;
		}
		for (; dy < var_info.yres; dy += THUMBHEIGHT)
		{ line_ix += fix_info.line_length; }
		dy -= var_info.yres;
	}

	return Py_BuildValue("s#", buf, BUFLEN);
}

static PyObject *
fb_resolution(PyObject *self, PyObject *args)
{
	return Py_BuildValue("ii", var_info.xres, var_info.yres);
}

static PyMethodDef FBMethods[] =
{
	{"open", fb_open, METH_VARARGS,
	 "Open framebuffer device."},
	{"close", fb_close, METH_VARARGS,
	 "Close framebuffer device."},
	{"getbuf",  fb_getbuf, METH_VARARGS,
	 "Get a rescaled framebuffer."},
	{"resolution",  fb_resolution, METH_VARARGS,
	 "Return a tuple containing the framebuffer resolution."},
	{NULL, NULL, 0, NULL}	/* Sentinel */
};

PyMODINIT_FUNC
initfb(void)
{
	(void) Py_InitModule("fb", FBMethods);
}


