/*
* MX21 IM8012 Application
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2004 Motorola Semiconductors Hong Kong.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <asm/mman.h>
#include <sys/mman.h>
#include <string.h>
#include "csi.h"
#include "csilib.h"
#include "im8012.h"
#include "im8012lib.h"
#include "camera.h"
typedef struct
{
int width;
int height;
int format;
int bytes_per_pixel;
} IMG_SPEC;
//local function
static void rgb_rotate(unsigned int BufIn, unsigned int BufOut, int imgH, int imgV, int dir, int out_stride);
void im8012_get_config(IM8012_CFG * _cfg, FILE * _fp);
//16-bit rotation
//1=clockwise, -1=anticlockwise, 0=no rot
static void rgb_rotate(unsigned int BufIn, unsigned int BufOut, int imgH, int imgV, int dir, int out_stride)
{
int v, h, k;
unsigned short * _dataIn = (unsigned short *)BufIn;
unsigned short * _dataOut = (unsigned short *)BufOut;
switch(dir)
{
case 1:
{
k = 0;
for(h = 0; h < imgH; h ++)
{
for(v = imgV - 1; v >= 0; v --)
{
_dataOut[k] = _dataIn[v * imgH + h];
k ++;
}
}
break;
}
case -1:
{
k = 0;
for(h = imgH - 1; h >= 0; h --)
{
for(v = 0; v < imgV; v ++)
{
_dataOut[k] = _dataIn[v * imgH + h];
k ++;
}
_dataOut += (out_stride - imgV);
}
break;
}
case 0:
{
//provide the effect of line stride
for(v = 0; v < imgV; v ++)
{
memcpy(_dataOut, _dataIn, imgH * 2);
_dataIn += imgH;
_dataOut += out_stride;
}
break;
}
}
return;
}
/*
//read sensor control file
//modify according to control file
void im8012_get_config(IM8012_CFG * _cfg, FILE * _fp)
{
char buf[200];
memset(_cfg, 0, sizeof(IM8012_CFG));
if(_fp)
{
fgets(buf, sizeof(buf), _fp);
if(!strncmp(buf, "im8012", 6))
{
printf("im8012: reading control file\n");
fgets(buf, sizeof(buf), _fp);
_cfg->color_format = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->vert_mirror = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->hori_mirror = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->out_width = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->out_height = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->test_pattern_enable = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->gamma = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->sharpening = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->colorsat = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->awb_left = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->awb_right = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->awb_top = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->awb_bottom = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->fps = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->afc_freq = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->capture_width = strtoul(buf, NULL, 0);
fgets(buf, sizeof(buf), _fp);
_cfg->capture_height = strtoul(buf, NULL, 0);
}
}
printf("\nIM8012 CONFIGURATION\n\n");
printf("color_format = %d\n", _cfg->color_format);
printf("vert_mirror = %d\n", _cfg->vert_mirror);
printf("hori_mirror = %d\n", _cfg->hori_mirror);
printf("out_width = %d\n", _cfg->out_width);
printf("out_height = %d\n", _cfg->out_height);
printf("test_pattern_enable = %d\n", _cfg->test_pattern_enable);
printf("gain_green1 = %f\n", (double)_cfg->gain_green1 / SCALEFAC);
printf("gain_blue = %f\n", (double)_cfg->gain_blue / SCALEFAC);
printf("gain_red = %f\n", (double)_cfg->gain_red / SCALEFAC);
printf("gain_green2 = %f\n", (double)_cfg->gain_green2 / SCALEFAC);
printf("gain_global = %f\n", (double)_cfg->gain_global / SCALEFAC);
printf("gamma = %f\n", (double)_cfg->gamma / SCALEFAC);
printf("sharpening = %d%%\n", _cfg->sharpening);
printf("colorsat = %d%%\n", _cfg->colorsat);
printf("awb_left = %d\n", _cfg->awb_left);
printf("awb_right = %d\n", _cfg->awb_right);
printf("awb_top = %d\n", _cfg->awb_top);
printf("awb_bottom = %d\n", _cfg->awb_bottom);
printf("fps = %d\n", _cfg->fps);
printf("afc_freq = %d\n", _cfg->afc_freq);
printf("capture_width = %d\n", _cfg->capture_width);
printf("capture_height = %d\n", _cfg->capture_height);
printf("\n");
return;
}
*/
//camera main func
//handles polling, dma & prp
int main(int argc, char *argv[])
{
#define LCD_WIDTH 240
#define ROTATION -1
#define READ_MODE_PRP 0
#define READ_MODE_POLL 1
IMG_SPEC img_spec;
IM8012_CFG im8012_cfg;
CSI_CFG csi_cfg;
FILE * _fp_im8012_cfg;
char * _file_name_sensor;
int read_mode;
int fb;
struct fb_var_screeninfo vinfo;
int screensize;
unsigned int *_tbuf, *_fbuf;
int fr = 0;
if(argc != 3)
{
printf( "Camera application for IM8012 version 0.1\n"
"usage: doCapture2 [read mode] [sensor control file]\n"
" - read mode : p=prp, o=poll\n"
" - sensor control file: contains sensor config\n");
return 0;
}
else
{
if(strcmp(argv[1], "p") == 0)
read_mode = READ_MODE_PRP;
else if(strcmp(argv[1], "o") == 0)
read_mode = READ_MODE_POLL;
_file_name_sensor = argv[2];
}
//csi config
csi_open();
switch(read_mode)
{
case READ_MODE_PRP:
csi_select_config(TIMING_IMAGIC_RGB_PRP, &csi_cfg);
break;
case READ_MODE_POLL:
csi_select_config(TIMING_IMAGIC_RGB_POLL, &csi_cfg);
break;
}
csi_config(&csi_cfg);
csi_dump_config();
//sensor config
im8012_open();
im8012_i2c_test();
im8012_select_config(IM8012_RGB_QVGA, &im8012_cfg);
_fp_im8012_cfg = fopen(_file_name_sensor, "r");
im8012_get_config(&im8012_cfg, _fp_im8012_cfg);
fclose(_fp_im8012_cfg);
im8012_config(&im8012_cfg);
img_spec.width = im8012_cfg.out_width;
img_spec.height = im8012_cfg.out_height;
img_spec.bytes_per_pixel = 2;
if(csi_cfg.prp_if_en)
{
//csi-prp link
//nothing to do
}
// else if(csi_cfg.dma_en)
// {
// //support dma here
// //most of time prp is used instead, dma is not useful and not implemented
// }
else
{
//polling
//write data to frame buffer
// if ((fb = open("/dev/fb0", O_RDWR)) < 0)
if ((fb = open("/dev/fbdir/0", O_RDWR)) < 0)
{
printf("doCapture2: cannot open fb device!\n");
exit(-1);
}
if( ioctl(fb,FBIOGET_VSCREENINFO,&vinfo) )
{
printf("Error reading variable information\n");
exit(2);
}
screensize = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel / 8;
_fbuf = (unsigned int *)mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
_tbuf = (unsigned int *)malloc(img_spec.width * img_spec.height * img_spec.bytes_per_pixel);
while(1)
{
// csi_read(_tbuf, img_spec.width * img_spec.height * img_spec.bytes_per_pixel);
// rgb_rotate((unsigned int)_tbuf, (unsigned int)_fbuf, img_spec.width, img_spec.height, ROTATION, LCD_WIDTH);
csi_read(_fbuf, img_spec.width * img_spec.height * img_spec.bytes_per_pixel);
fr ++;
if(!(fr % 100))
printf("fr %d\n", fr);
}
free(_tbuf);
}
im8012_close();
csi_close();
printf("doCapture2 completed\n");
return 0;
}