1/*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <ParameterWeb.h>
7
8#include "CamSensor.h"
9#include "CamDebug.h"
10#include "addons/sonix/SonixCamDevice.h"
11
12//XXX: unfinished!
13
14#define ENABLE_GAIN 1
15
16
17class TAS5130D1BSensor : public CamSensor {
18public:
19	TAS5130D1BSensor(CamDevice *_camera);
20	~TAS5130D1BSensor();
21	virtual status_t	Probe();
22	virtual status_t	Setup();
23	const char *Name();
24	virtual bool		Use400kHz() const { return false; };
25	virtual bool		UseRealIIC() const { return false; };
26	virtual uint8		IICReadAddress() const { return 0x00; };
27	virtual uint8		IICWriteAddress() const { return 0x11; /*0xff;*/ };
28
29	virtual int			MaxWidth() const { return 640; };
30	virtual int			MaxHeight() const { return 480; };
31
32	virtual status_t	AcceptVideoFrame(uint32 &width, uint32 &height);
33	virtual status_t	SetVideoFrame(BRect rect);
34	virtual void		AddParameters(BParameterGroup *group, int32 &firstID);
35	virtual status_t	GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size);
36	virtual status_t	SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size);
37
38private:
39	bool	fIsSonix;
40	float	fGain;
41};
42
43
44TAS5130D1BSensor::TAS5130D1BSensor(CamDevice *_camera)
45: CamSensor(_camera)
46{
47	fIsSonix = (dynamic_cast<SonixCamDevice *>(_camera) != NULL);
48	if (fIsSonix) {
49		fInitStatus = B_OK;
50	} else {
51		PRINT((CH ": unknown camera device!" CT));
52		fInitStatus = ENODEV;
53	}
54	fGain = (float)0x40; // default
55}
56
57
58TAS5130D1BSensor::~TAS5130D1BSensor()
59{
60}
61
62
63status_t
64TAS5130D1BSensor::Probe()
65{
66	PRINT((CH "()" CT));
67
68	return B_OK;
69}
70
71
72status_t
73TAS5130D1BSensor::Setup()
74{
75	PRINT((CH "()" CT));
76	if (InitCheck())
77		return InitCheck();
78	/*
79	Device()->PowerOnSensor(false);
80	Device()->PowerOnSensor(true);
81	*/
82	if (fIsSonix) {
83		// linux driver seems to do this, but doesn't say why
84		Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x01);	/* power down the sensor */
85		Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x20);	/* enable sensor clk */
86		Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x04);	/* power up the sensor, enable tx, sysclk@12MHz */
87		Device()->WriteReg8(SN9C102_R_B_GAIN, 0x01);	/* red gain = 1+0/8 = 1, red gain = 1+1/8 !!? */
88		Device()->WriteReg8(SN9C102_G_GAIN, 0x00);	/* green gain = 1+0/8 = 1 */
89		Device()->WriteReg8(SN9C102_OFFSET, 0x0a);	/* 0 pix offset */
90		Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x60);	/* enable sensor clk, and invert it */
91		Device()->WriteReg8(SN9C102_SYNC_N_SCALE, 0x06);	/* no compression, normal curve,
92												 * no scaling, vsync active low,
93												 * v/hsync change at rising edge,
94												 * raising edge of sensor pck */
95		Device()->WriteReg8(SN9C102_PIX_CLK, 0xf3);	/* pixclk = masterclk, sensor is slave mode */
96	}
97
98
99	if (fIsSonix) {
100		//sonix_i2c_write_multi(dev, dev->sensor->i2c_wid, 2, 0xc0, 0x80, 0, 0, 0); /* AEC = 0x203 ??? */
101#if 0
102		Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */
103#endif
104
105#if 1
106		Device()->WriteIIC8(0x20, 0xf6 - 0xd0); /* GAIN */
107		Device()->WriteIIC8(0x40, 0x47 - 0x40); /* Exposure */
108		// set crop
109		Device()->WriteReg8(SN9C102_H_SIZE, 104);
110		Device()->WriteReg8(SN9C102_V_SIZE, 12);
111		SetVideoFrame(BRect(0, 0, 320-1, 240-1));
112#endif
113
114#if 0
115//XXX
116		Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */
117		Device()->WriteReg8(SN9C102_H_SIZE, 69);
118		Device()->WriteReg8(SN9C102_V_SIZE, 9);
119		SetVideoFrame(BRect(0, 0, 352-1, 288-1));
120#endif
121
122	}
123
124	//Device()->SetScale(1);
125
126	return B_OK;
127}
128
129
130const char *
131TAS5130D1BSensor::Name()
132{
133	return "TASC tas5130d1b";
134}
135
136
137status_t
138TAS5130D1BSensor::AcceptVideoFrame(uint32 &width, uint32 &height)
139{
140	// default sanity checks
141	status_t err = CamSensor::AcceptVideoFrame(width, height);
142	if (err < B_OK)
143		return err;
144	// must be modulo 16
145	width /= 16;
146	width *= 16;
147	height /= 16;
148	height *= 16;
149	return B_OK;
150}
151
152
153status_t
154TAS5130D1BSensor::SetVideoFrame(BRect rect)
155{
156	if (fIsSonix) {
157		// set crop
158		Device()->WriteReg8(SN9C102_H_START, /*rect.left + */104);
159		Device()->WriteReg8(SN9C102_V_START, /*rect.top + */12);
160		Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb);
161		Device()->WriteReg8(SN9C102_HO_SIZE, 0x14);
162		Device()->WriteReg8(SN9C102_VO_SIZE, 0x0a);
163#if 0
164		Device()->WriteReg8(SN9C102_H_START, /*rect.left + */104);
165		Device()->WriteReg8(SN9C102_V_START, /*rect.top + */12);
166		Device()->WriteReg8(SN9C102_PIX_CLK, 0xf3);
167		Device()->WriteReg8(SN9C102_HO_SIZE, 0x1f);
168		Device()->WriteReg8(SN9C102_VO_SIZE, 0x1a);
169#endif
170		fVideoFrame = rect;
171		/* HACK: TEST IMAGE */
172		//Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x70);	/* enable sensor clk, and invert it, test img */
173
174	}
175
176	return B_OK;
177}
178
179
180void
181TAS5130D1BSensor::AddParameters(BParameterGroup *group, int32 &index)
182{
183	BContinuousParameter *p;
184	CamSensor::AddParameters(group, index);
185
186#ifdef ENABLE_GAIN
187	// NON-FUNCTIONAL
188	BParameterGroup *g = group->MakeGroup("global gain");
189	p = g->MakeContinuousParameter(index++,
190		B_MEDIA_RAW_VIDEO, "global gain",
191		B_GAIN, "", (float)0x00, (float)0xf6, (float)1);
192#endif
193}
194
195
196status_t
197TAS5130D1BSensor::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
198{
199#ifdef ENABLE_GAIN
200	if (id == fFirstParameterID) {
201		*size = sizeof(float);
202		*((float *)value) = fGain;
203		*last_change = fLastParameterChanges;
204	}
205#endif
206	return B_BAD_VALUE;
207}
208
209
210status_t
211TAS5130D1BSensor::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
212{
213#ifdef ENABLE_GAIN
214	if (id == fFirstParameterID) {
215		if (!value || (size != sizeof(float)))
216			return B_BAD_VALUE;
217		if (*(float *)value == fGain)
218			return B_OK;
219		fGain = *(float *)value;
220		fLastParameterChanges = when;
221		PRINT((CH ": gain: %f" CT, fGain));
222
223		if (fIsSonix) {
224			// some drivers do:
225			//Device()->WriteIIC8(0x20, (uint8)0xf6 - (uint8)fGain);
226			// but it doesn't seem to work
227
228			// works, not sure why yet, XXX check datasheet for AEG/AEC
229			uint8 buf[2] = { 0x20, 0x70 };
230			buf[1] = (uint8)0xff - (uint8)fGain;
231			Device()->WriteIIC(0x02, buf, 2);
232		}
233
234		return B_OK;
235	}
236#endif
237	return B_BAD_VALUE;
238}
239
240
241B_WEBCAM_DECLARE_SENSOR(TAS5130D1BSensor, tas5130d1b)
242
243