rendered paste body/* PS Eye test program
by Jim Paris <jim@jtan.com>
License: GPLv2 or GPLv3
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdint.h>
#include <err.h>
#include <usb.h>
#include "hexdump.h"
#define debug(x...) fprintf(stderr,x)
#define info(x...) fprintf(stderr,x)
/****** Lowlevel USB stuff ******/
#define LIBUSB_BULK_SIZE 16384
usb_dev_handle *eye = NULL;
/* Close USB device */
void eye_close(void)
{
if (eye != NULL) {
usb_close(eye);
eye = NULL;
}
}
/* Open & init USB device */
void eye_open(void)
{
struct usb_bus *bus;
struct usb_device *dev;
struct usb_device *usb_dev = NULL;
usb_init();
if (usb_find_busses() < 0)
err(1, "Bus scan");
if (usb_find_devices() < 0)
err(1, "Device scan");
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if(dev->descriptor.idVendor==0x1415 &&
dev->descriptor.idProduct==0x2000) {
usb_dev = dev;
break;
}
}
}
if (usb_dev == NULL)
errx(1, "Camera not found.");
if ((eye = usb_open(usb_dev)) == NULL)
errx(1, "Error opening camera device.");
atexit(eye_close);
if (usb_claim_interface(eye, 0))
err(1, "Can't claim camera interface");
info("Opened device\n");
return;
}
/* Send the control message used to read/write eye registers.
Returns 0 on success or negative on error. */
int eye_control_msg(uint16_t reg, uint8_t *value, int is_write)
{
int ret;
ret = usb_control_msg(
eye,
(is_write ? USB_ENDPOINT_OUT : USB_ENDPOINT_IN) |
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x01, // request
0x0000, // value
reg, // index
(char *)value, 1,
500);
if (ret < 0)
return -1;
if (ret != 1)
return -2;
return 0;
}
/* Do a bulk read on endpoint 1. Returns read length on success. */
int eye_bulk_in(uint8_t *buf, int length)
{
int ret;
ret = usb_bulk_read(eye, 1, (char *)buf, length, 500);
return ret;
}
/* Read eye reg */
uint8_t eye_read(uint16_t reg)
{
uint8_t value;
if (eye_control_msg(reg, &value, 0) < 0) {
fprintf(stderr, "error reading reg 0x%02x\n", reg);
exit(1);
}
return value;
}
/* Read eye reg and warn if we don't get expected value */
uint8_t eye_expect(uint16_t reg, uint8_t value)
{
uint8_t actual = eye_read(reg);
if (actual != value)
debug("read reg 0x%02x: got 0x%02x, "
"expected 0x%02x\n", reg, actual, value);
return value;
}
/* Write eye reg */
void eye_write(uint16_t reg, uint8_t value)
{
if (eye_control_msg(reg, &value, 1) < 0) {
fprintf(stderr, "error writing reg 0x%02x\n", reg);
exit(1);
}
}
/* Write eye reg and verify by reading it back */
void eye_write_verify(uint16_t reg, uint8_t value)
{
uint8_t actual;
eye_write(reg, value);
actual = eye_read(reg);
if (actual != value) {
debug("verify failed writing reg 0x%02x, "
"got 0x%02x wanted 0x%02x\n", reg, actual, value);
exit(1);
}
}
/* Set red LED */
void eye_led(int red)
{
/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
(direction and output)? */
eye_write(0x21, eye_read(0x21) | 0x80);
if (red)
eye_write(0x23, eye_read(0x23) | 0x80);
else
eye_write(0x23, eye_read(0x23) & ~0x80);
}
/******* SCCB/OV interface ******/
#define EYEREG_SCCB_ADDRESS 0xf1 /* ? */
#define EYEREG_SCCB_SUBADDR 0xf2
#define EYEREG_SCCB_WRITE 0xf3
#define EYEREG_SCCB_READ 0xf4
#define EYEREG_SCCB_OPERATION 0xf5
#define EYEREG_SCCB_STATUS 0xf6
#define EYE_SCCB_OP_WRITE_3 0x37
#define EYE_SCCB_OP_WRITE_2 0x33
#define EYE_SCCB_OP_READ_2 0xf9
/* SCCB init */
void eye_sccb_init(void)
{
eye_write_verify(0xe7, 0x3a);
eye_write(EYEREG_SCCB_ADDRESS, 0x60);
eye_write(EYEREG_SCCB_ADDRESS, 0x60);
eye_write(EYEREG_SCCB_ADDRESS, 0x60);
eye_write(EYEREG_SCCB_ADDRESS, 0x42);
}
/* SCCB check status, returns 1 if OK, 0 on error */
#define SCCB_RETRY 5
int eye_sccb_check_status(void)
{
int try = 0;
uint8_t ret;
for (try = 0; try < SCCB_RETRY; try++) {
ret = eye_read(EYEREG_SCCB_STATUS);
switch (ret) {
case 0x00:
return 1;
case 0x04:
return 0;
case 0x03:
/* Retry silently */
break;
default:
debug("sccb status 0x%02x, attempt %d/%d\n",
ret, try+1, SCCB_RETRY);
}
}
return 0;
}
/* SCCB write */
#define ov_write eye_sccb_write
void eye_sccb_write(uint8_t reg, uint8_t value)
{
eye_write(EYEREG_SCCB_SUBADDR, reg);
eye_write(EYEREG_SCCB_WRITE, value);
eye_write(EYEREG_SCCB_OPERATION, EYE_SCCB_OP_WRITE_3);
if (!eye_sccb_check_status())
errx(1, "sccb_write failed");
}
/* SCCB read */
#define ov_read eye_sccb_read
uint8_t eye_sccb_read(uint8_t reg)
{
eye_write(EYEREG_SCCB_SUBADDR, reg);
eye_write(EYEREG_SCCB_OPERATION, EYE_SCCB_OP_WRITE_2);
if (!eye_sccb_check_status())
errx(1, "sccb_read failed 1");
eye_write(EYEREG_SCCB_OPERATION, EYE_SCCB_OP_READ_2);
if (!eye_sccb_check_status())
errx(1, "sccb_read failed 2");
return eye_read(EYEREG_SCCB_READ);
}
/***** Misc */
void eye_init(void)
{
/* adapted from eye.out: */
eye_write_verify(0xe7,0x3a);
eye_write(0xf1,0x60);
eye_write(0xf1,0x60);
eye_write(0xf1,0x60);
eye_write(0xf1,0x42);
eye_write_verify(0xc2,0x0c);
eye_write_verify(0x88,0xf8);
eye_write_verify(0xc3,0x69);
eye_write_verify(0x89,0xff);
eye_write_verify(0x76,0x03);
eye_write_verify(0x92,0x01);
eye_write_verify(0x93,0x18);
eye_write_verify(0x94,0x10);
eye_write_verify(0x95,0x10);
eye_write_verify(0xe2,0x00);
eye_write_verify(0xe7,0x3e);
eye_write(0x1c,0x0a);
eye_write(0x1d,0x22);
eye_write(0x1d,0x06);
eye_write_verify(0x96,0x00);
eye_write(0x97,0x20);
eye_write(0x97,0x20);
eye_write(0x97,0x20);
eye_write(0x97,0x0a);
eye_write(0x97,0x3f);
eye_write(0x97,0x4a);
eye_write(0x97,0x20);
eye_write(0x97,0x15);
eye_write(0x97,0x0b);
eye_write_verify(0x8e,0x40);
eye_write_verify(0x1f,0x81);
eye_write_verify(0x34,0x05);
eye_write_verify(0xe3,0x04);
eye_write_verify(0x88,0x00);
eye_write_verify(0x89,0x00);
eye_write_verify(0x76,0x00);
eye_write_verify(0xe7,0x2e);
eye_write_verify(0x31,0xf9);
eye_write_verify(0x25,0x42);
eye_write_verify(0x21,0xf0);
eye_write(0x1c,0x00);
eye_write(0x1d,0x40);
eye_write(0x1d,0x02);
eye_write(0x1d,0x00);
eye_write(0x1d,0x02);
eye_write(0x1d,0x57);
eye_write(0x1d,0xff);
eye_write_verify(0x8d,0x1c);
eye_write_verify(0x8e,0x80);
eye_write_verify(0xe5,0x04);
ov_write(0x12,0x80);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x11,0x01);
ov_write(0x3d,0x03);
ov_write(0x17,0x26);
ov_write(0x18,0xa0);
ov_write(0x19,0x07);
ov_write(0x1a,0xf0);
ov_write(0x32,0x00);
ov_write(0x29,0xa0);
ov_write(0x2c,0xf0);
ov_write(0x65,0x20);
ov_write(0x11,0x01);
ov_write(0x42,0x7f);
ov_write(0x63,0xe0);
ov_write(0x64,0xff);
ov_write(0x66,0x00);
ov_write(0x13,0xf0);
ov_write(0x0d,0x41);
ov_write(0x0f,0xc5);
ov_write(0x14,0x11);
ov_write(0x22,0x7f);
ov_write(0x23,0x03);
ov_write(0x24,0x40);
ov_write(0x25,0x30);
ov_write(0x26,0xa1);
ov_write(0x2a,0x00);
ov_write(0x2b,0x00);
ov_write(0x6b,0xaa);
ov_write(0x13,0xff);
ov_write(0x90,0x05);
ov_write(0x91,0x01);
ov_write(0x92,0x03);
ov_write(0x93,0x00);
ov_write(0x94,0x60);
ov_write(0x95,0x3c);
ov_write(0x96,0x24);
ov_write(0x97,0x1e);
ov_write(0x98,0x62);
ov_write(0x99,0x80);
ov_write(0x9a,0x1e);
ov_write(0x9b,0x08);
ov_write(0x9c,0x20);
ov_write(0x9e,0x81);
ov_write(0xa6,0x04);
ov_write(0x7e,0x0c);
ov_write(0x7f,0x16);
ov_write(0x80,0x2a);
ov_write(0x81,0x4e);
ov_write(0x82,0x61);
ov_write(0x83,0x6f);
ov_write(0x84,0x7b);
ov_write(0x85,0x86);
ov_write(0x86,0x8e);
ov_write(0x87,0x97);
ov_write(0x88,0xa4);
ov_write(0x89,0xaf);
ov_write(0x8a,0xc5);
ov_write(0x8b,0xd7);
ov_write(0x8c,0xe8);
ov_write(0x8d,0x20);
ov_write(0x0c,0x90);
eye_write_verify(0xc0,0x50);
eye_write_verify(0xc1,0x3c);
eye_write_verify(0xc2,0x0c);
ov_write(0x2b,0x00);
ov_write(0x22,0x7f);
ov_write(0x23,0x03);
ov_write(0x11,0x01);
ov_write(0x0c,0xd0);
ov_write(0x64,0xff);
ov_write(0x0d,0x41);
eye_led(1);
ov_write(0x14,0x41);
ov_write(0x0e,0xcd);
ov_write(0xac,0xbf);
ov_write(0x8e,0x00);
ov_write(0x0c,0xd0);
eye_write(0xe0,0x09);
eye_write(0xe0,0x00);
eye_led(1);
}
void eye_dump_bulk(int size)
{
uint8_t *buf;
int len = 0;
int ret;
if ((buf = malloc(size + LIBUSB_BULK_SIZE)) == NULL)
errx(1, "malloc");
while (len < size) {
ret = eye_bulk_in(&buf[len], LIBUSB_BULK_SIZE);
if (ret <= 0) {
fprintf(stderr,"bulk in failed, ret %d", ret);
free(buf);
return;
}
info("%d %d\n", len, ret);
// if (ret < 128)
// hexdump(&buf[len], ret);
len += ret;
}
info("\n");
hexdump(buf, size);
free(buf);
}
int clip(int x)
{
if (x < 0) x = 0;
if (x > 255) x = 255;
return x;
}
void yuv_to_rgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t *r, uint8_t *g, uint8_t *b)
{
int c = y - 16;
int d = u - 128;
int e = v - 128;
*r = clip((298 * c + 409 * e + 128) >> 8);
*g = clip((298 * c - 100 * d - 208 * e + 128) >> 8);
*b = clip((298 * c + 516 * d + 128) >> 8);
}
void eye_dump_image(int skip_frames)
{
#define LEN (640 * 480 * 2)
uint8_t *buf;
int ret = 0;
int frame = 0;
int i;
if ((buf = malloc(LEN)) == NULL)
errx(1, "malloc");
while (frame < skip_frames) {
ret = eye_bulk_in(buf, LEN);
if (ret >= (LEN - 4)) {
frame++;
info("%d/%d\n", frame, skip_frames);
}
}
info("\ndone\n");
/* convert yuyv -> rgb rgb */
printf("P3\n640\n480\n255\n");
for (i = 0; i < LEN; i += 4) {
int y1 = buf[i + 0];
int u = buf[i + 1];
int y2 = buf[i + 2];
int v = buf[i + 3];
uint8_t r, g, b;
yuv_to_rgb(y1,u,v,&r,&g,&b);
printf("%d %d %d\n", r, g, b);
yuv_to_rgb(y2,u,v,&r,&g,&b);
printf("%d %d %d\n", r, g, b);
}
free(buf);
}
int main(int argc, char *argv[])
{
int i;
uint8_t regs[0x80];
eye_open();
/* my own test: */
eye_led(1);
eye_sccb_init();
ov_write(0x12, 0x80);
for (i = 0; i < sizeof(regs); i++)
regs[i] = ov_read(i);
fhexdump(stderr, regs, sizeof(regs));
eye_led(0);
/* standard init */
eye_init();
/* test */
eye_dump_image(100);
eye_close();
return 0;
}