2011년 6월 24일 금요일

3CCD 카메라의 문제점 찾기 !

단일 카메라동작은 물론 테스트 해보았고, 세 대의 카메라를 동기화 시켜도 최대 한 픽셀 정도의 시간적 오차만 발생할 뿐이라는 것을 실험을 통해서 확인해 보았다고 확신 했었다. 하지만 주기적인  물결무늬를 목격한 이후 초창기 상태로 되돌아가 기초적인 점검을 다시 해보았다. 지금 까지의 결론은 세 대의 카메라의 동기가 제대로 되어 있지 못하다. 최대로 생각했던 픽셀 수가 하나가 아니다. 5 픽셀의 동기화 차이가 발생하는 것을 목격했다. 최대 최소를 따질 겨를이 아니다. 우선 한 픽셀이상이면 지금의 알고리즘에서는 문제가 발생한다. 우선 최근의 보드에서 동기화가 제대로 되는지 부터 확인하고 대책을 마련해야 겠다. 에휴~~~

도시에서 자전거 타기?

평소에 출퇴근을 자전거로 타고 있지만 올해는 날씨와 일본의 방사능 유출 사고로 인해 현재 까지 자전거로 출퇴근 할 수 있는 기간이 그리 많지 않았다. 뭐 핑계일 수 도 있지만... 적극적으로 대처 했다면 많이 탈 수 있었을 것이다. 우연히 들른 자전거에 대한 hacking 사이트를 방문했다가 너무나도 공감가는 내용을 찾았다.

http://www.bikehacks.com/bikehacks/2011/06/new-york-city-bike-lane-mishegas.html


대체적인 내용은 자전거 전용도로를 벗어난 자전거 운용자에게 경찰이 50달러의 벌금을 부과한 상황을 너무 불합리하다고 항의 하는 내용이다. 너무나도 현재의 한국의 상황과 맞아 떨어진다. 자전거 전용도로라고 너도 나도 만들어 놓은 것들이 주차해 놓은 차량및 그 밖의 간판, 표시판 등으로 점유 되어 있다.

위 상황은 뉴욕같은데 현재의 서울시와 별반 다름이 없어 보인다. 비슷한 규모의 독일과 네덜란드의 상황과는 다른 것 같다. 상황이 갖추어져 있느냐 없느냐의 차이는 있지만 태평하게 자전거까지 운송수단으로 인정해야 하다는 이야기는 정당성이 없다고 생각한다.

하지만 위에서 설파하는 내용에서 보듯이 아무리 잘살아도 자전거를 운송 수단으로써의 정당한 지위는 인정되지 않는다. 못한다기 보다는 안한다고 본다.

뉴욕도 우리나라와 크게 다르지 않아서 자전거 전용 도로는  그 권리가 보장 받지 못하는 것 같다. 하지만, 위의 내용을 보면 알 겠지만 처절하게 나름데로 항의 하는 주인공의 노력이 눈물 겹다. 댓글에도 보듯이 그래도 헬멧은 꼭 쓰자.

그레서 우선 자전거의 용도와 가치에 대해서 생각해 보았다. 현제 자전거를 운용할 수 있는 상황이란 제한 적이다. 자전거 하면 떠올리는 그림은 시골에서 논과 논 사이의 길을 느긋하게 다니는 노인정도다. 아이러니 하게도 운송 수단 중에 가장 후진적이만 자전거야 말로 첨단의 흐름을 따르는 밀집적인 도시에서 운용 될때 가장 그 가치가 빛난다고 생각한다.

도시야 말로 자전거가 발 붙일 수 있는 최적의 상황이라고 생각한다. 우선 출퇴근용 운송 수단을 분류해보면 (내 입장에서 보면) 다음 네가지 분류로 볼 수 있다. 승용차, 오토바이크, 버스, 지하철, 그리고 자전거. 자전거와 오토바이크, 그리고 지하철을 제외한 나머지는 도시에서 차량의 흐름을 거스를 수 없다. 항상 정체를 보이는 서울시의 출퇴근 길을 생각해 보면 버스와 승용차가 비효율적인 이라는 것은 모두가 공감할 것이다. 물론 지하철의 경우는 예외이다. 그래도 지하철의 경우 서울시의 구석구석 모든 곳에 정거장을 가지고 있지 못하기 때문에 대부분의 경우는 버스와 승용차와 연개해서 운용되어야 한다고 생각하면 근본적인 우월성을 가지고 있다고 생각하지 않는다.

그렇다고 자전거와 오토바이크를 비교해 본데도 자전거가 우세하다. 우선 오토 바이크는 차량과 같은 도로를 운행해야하기 때문에 대단히 위험하다. 뭐 자전거의 경우도 절대적으로 자전거 전용도로가 부족하지만 그래도 나름대로 보행자 다음의 약자의 대우를 받고 있기 때문에 보행자 다음으로 보호 받고 있다고 생각한다. 물론 도로에서 운용 중 일때는 오토바이크와 똑같은 처지에 처한다.

그리고 도시에 한정되지만 (최소한 나의 경우의 출퇴근에 한정되지만) 대중교통및 승용차의 출퇴근 시간이 자전거의 경우와 비교할 때 조금 늦거나 비슷하다. 지극히 개인적이지만 일반적인 체력을 가지고 있고 일반적인 출퇴근 거리를 가지고 있다고 생각하기 때문에 여러가지 면모를 고려했을 때 자전거가 가장 우세하다는 결론은 합리적이다라고 생각한다. 물론 서울시를 모두 자전거로 다니기는 불가능 하지만, 자전거가 다닐 수 있는 곳이라면 자전거를 타고 다니는 것이 금전적인, 시간적인, 그리고 건강적인 면에서 가장 효율적이라고 생각한다. 물론 비, 눈, 황사, 방사능 같은 것이 때때로 방해 하겠지만, 최대한 자전거를 이용하는 것이 여러면에서 이득이 된다고 생각한다. 그런 의미에서 자전거의 권리를 확대하기 위한 위의 youtube의 내용은 부럽다. 뭐 헬멧 미 착용과 같은 문제점이 있지만, 꾸준한 문제제기는 필요하다고 생각한다.

2011년 6월 23일 목요일

여러 파일로된 USB2000의 스펙트럼 데이터들을 하나의 파일로 합치는 python 프로그램

NIR 스펙트로미터인 USB2000에서 획득한 스펙트럼 데이터들을(여러개의 파일로 되어 있는) 하나의 파일로 된 매트릭스형태로 합성해 주는 python 스크립트 프로그램이다.

사용방법은 다음과 같다. 우선 리눅스 시스템의 경우 기본적으로 설치되어 있지만, 윈도우즈의 경우 python 2.x 버전의 프로그램을 설치한다. 그리고 USB2000에서 획득한 여러개의 스펙트럼 데이터 파일들을 분류하여 하나의 파일로 만들고 싶은 것들만 하나의 디렉토리로 이동 시키고, 해당 디렉토리에 이 스크립트 파일을 복사하고 실행시키면 해당 디렉토리에 하나의 파일로 합쳐진 매트릭스형태의 스펙트럼 데이터가 생성된다.

 # Usage: copy the script into the directory existing spectrum data and execute it.  
 #!/usr/bin/python  
 import os  
 #import os.path  
 path = "./"  
 dirlist = os.listdir(path)  
 newdirlist = []  
 for fname in dirlist:  
  if os.path.isfile(fname) and fname.find(".Master.Scope") != -1:  
  i = dirlist.index(fname)  
  num = fname.split('.')  
  if num[0].isdigit():  
   newdirlist.append(int(num[0]))  
 newdirlist.sort()  
 #newdirlist.sort(reverse=True)  
 #print newdirlist  
 # the number of samples  
 samples = len(newdirlist)  
 # the number of pixels  
 fname = str(newdirlist[0]) + ".Master.Scope"  
 f = open(fname)  
 lines = f.readlines()  
 f.close()  
 for line in lines:  
  if str(line).find("Number of Pixels in File: ") >= 0:  
  columns = line.split(": ")  
  pixels = int(columns[1])  
  else:  
  if str(line).find(">>>>>Begin Spectral Data<<<<<") >= 0:  
   istart = lines.index(line) + 1  
  else:  
   if str(line).find(">>>>>End Spectral Data<<<<<") >= 0:  
   iend = lines.index(line) - 1  
 print "the # of samples: ", samples  
 print "the # of pixels: ", pixels  
 print "the index of start: ", istart  
 print "the index of end: ", iend  
 signals = [ [ 0 for j in range(samples+1) ] for i in range(pixels) ]  
 for j in range(istart, iend+1, 1):  
  line = lines[j]  
  columns = line.split("\t")  
  #print j, columns[j]  
  signals[j-istart][0] = columns[0].strip();  
 # make directory for merged file  
 if not os.path.isdir("merged"):  
  os.mkdir("merged")  
 for i in range(0, samples, 1):  
  num = newdirlist[i]  
  # for num in newdirlist:  
  # read lines in each file  
  fname = str(num) + ".Master.Scope"  
  f = open(fname)  
  lines = f.readlines()  
  f.close()  
  for j in range(istart, iend+1, 1):  
  line = lines[j]  
  columns = line.split("\t")  
  #print j, columns[j]  
  signals[j-istart][i+1] = columns[1].strip();  
 fname = "merged/USB2000.dat"  
 f = open(fname, "w")  
 for j in range(pixels):  
  for i in range(samples+1):  
  f.write(signals[j][i]+"\t")  
  f.write("\n")  
 f.close()  

General Purpose FIFO for C/C++ Language

/* FIFO

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/


#ifndef __FIFO_H__
#define __FIFO_H__

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    int length;
    char *buffer;
int head;
int tail;
} fifo_t;

fifo_t *fifo_create(int bytes);
void fifo_delete(fifo_t *p);
int fifo_full(fifo_t *p);
int fifo_empty(fifo_t *p);
int fifo_filled_bytes(fifo_t *p);
int fifo_fill(fifo_t *q, const void *p, int bytes);
int fifo_copy(void *q, int bytes, fifo_t *p);
int fifo_bring(void *q, int bytes, fifo_t *p);

#ifdef __cplusplus
}
#endif

#endif /* __FIFO_H__ */


/* FIFO

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/

#include
#include
#include
#include "fifo.h"

fifo_t *fifo_create(int bytes)
{
fifo_t *p;

p = (fifo_t *)malloc(sizeof(*p)+bytes);
assert(p);
if (p == NULL) goto __error_return__;
p->length = bytes;
p->buffer = (char *)p+sizeof(*p);
p->head = 1;
p->tail = 0;
__error_return__:;
return p;
}

void fifo_delete(fifo_t *p)
{
assert(p);
free(p);
}

int fifo_full(fifo_t *p)
{
assert(p);
return (p->head == p->tail);
}

int fifo_empty(fifo_t *p)
{
assert(p);
return (p->head == ((p->tail+1)%p->length));
}

int fifo_fill(fifo_t *q, const void *p, int bytes)
{
int count;
const char *ptr = (const char *)p;

for (count = 0; count < bytes; count++) {
if (q->head == q->tail) break; /* fifo is full ? */
q->buffer[q->head] = *ptr++;
q->head = (q->head+1)%q->length;
}
return count;
}

int fifo_copy(void *q, int bytes, fifo_t *p)
{
int count, tail;

char *ptr = (char *)q;
tail = p->tail;
for (count = 0; count < bytes; count++) {
if (p->head == ((tail+1)%p->length)) break; /* fifo is empty ? */
tail = (tail+1)%p->length;
*ptr++ = p->buffer[tail];
}
return count;
}

int fifo_bring(void *q, int bytes, fifo_t *p)
{
int count;
char *ptr = (char *)q;
for (count = 0; count < bytes; count++) {
if (p->head == ((p->tail+1)%p->length)) break; /* fifo is empty ? */
p->tail = (p->tail+1)%p->length;
*ptr++ = p->buffer[p->tail];
}
return count;
}

int fifo_filled_bytes(fifo_t *p)
{
if (p->head > p->tail) return (p->head-p->tail-1);
if (p->head == p->tail) return p->length;
return ((p->head+p->length)-p->tail-1);
}

2011년 6월 21일 화요일

Convert Bayer with BGRG pattern to RGB24

********************************** bayer.h *************************************

/* bayer2rgb

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/

#ifndef __BAYER_H__
#define __BAYER_H__

#ifdef __cplusplus
extern "C" {
#endif
/*
typedef enum {
BAYER_BGGR,
BAYER_GBRG,
BAYER_GRBG
} bayer_t;

void bayer2rgb24(unsigned char *rgb, unsigned char *bayer, int sx, int sy, bayer_t tile);
*/
void bayer2rgb24(unsigned char *rgb, unsigned char *bayer, int width, int height);

#ifdef __cplusplus
}
#endif

#endif /* __BAYER_H__ */


********************************** bayer.c *************************************

/* bayer2rgb

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/


#include "bayer.h"

// BGRG pattern
void bayer2rgb24(unsigned char *rgb, unsigned char *raw, int width, int height)
{
int i, j;
int raw_pitch = 2*width;
int rgb_pitch = 3*width;

#undef RED
#define RED(x, y) rgb[(y)*rgb_pitch+(x)*3+2]
#undef GREEN
#define GREEN(x, y) rgb[(y)*rgb_pitch+(x)*3+1]
#undef BLUE
#define BLUE(x, y) rgb[(y)*rgb_pitch+(x)*3+0]

#define RAW_LOW(x, y) ((int)raw[(y)*raw_pitch+(x)*2+0])
#define RAW_HIGH(x, y) ((int)raw[(y)*raw_pitch+(x)*2+1])

for (i = 0; i < height-1; ) {
// odd line
j = 0;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j+1, i)+RAW_HIGH(j, i+1))/3;
RED(j, i) = (RAW_LOW(j+1, i)+RAW_LOW(j+1, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)/3; // green;
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j+1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j+1)*2+0]+1)>>1; // red;
*/
j++;
while (j < width-1) {
BLUE(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
j++;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i)+RAW_HIGH(j+1, i)+RAW_HIGH(j, i+1))>>2;
RED(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i)+RAW_LOW(j-1, i+1)+RAW_LOW(j+1, i+1))>>2;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>2; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j-1)*2+0]+(int)raw[(i+1)*raw_pitch+(j+1)*2+0]+1)>>2; // red
*/
j++;
}
BLUE(j, i) = RAW_LOW(j-1, i);
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitchj*3+0] = raw[i*raw_pitch+(j-1)*2+0]; // blue;
rgb[i*rgb_pitchj*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitchj*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
i++;

// even line
j = 0;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = RAW_LOW(j+1, i);
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitch+j*3+2] = raw[i*raw_pitch+(j+1)*2+0]; // red
*/
j++;
while (j < width-1) {
BLUE(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i)+RAW_LOW(j-1, i+1)+RAW_LOW(j+1, i+1))>>2;
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i)+RAW_HIGH(j+1, i)+RAW_HIGH(j, i+1))>>2;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j-1)*2+0]+(int)raw[(i+1)*raw_pitch+(j+1)*2+0]+1)>>2; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>2; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
j++;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]+1)>>1; // red
*/
j++;
}
BLUE(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j-1, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i)+RAW_HIGH(j, i+1))/3;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+(j-1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j-1)*2+0]+1)>>1; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)/3; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
i++;

// third line
j = 0;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j+1, i)+RAW_HIGH(j, i+1))/3;
RED(j, i) = (RAW_LOW(j+1, i)+RAW_LOW(j+1, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)/3; // green;
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j+1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j+1)*2+0]+1)>>1; // red;
*/
j++;
while (j < width-1) {
BLUE(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i))>>1;
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
j++;
BLUE(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i)+RAW_HIGH(j+1, i)+RAW_HIGH(j, i+1))>>2;
RED(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i)+RAW_LOW(j-1, i+1)+RAW_LOW(j+1, i+1))>>2;
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // blue;
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>2; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]
+(int)raw[(i+1)*raw_pitch+(j-1)*2+0]+(int)raw[(i+1)*raw_pitch+(j+1)*2+0]+1)>>2; // red
*/
j++;
}
BLUE(j, i) = RAW_LOW(j-1, i);
GREEN(j, i) = (RAW_HIGH(j, i)+RAW_HIGH(j, i+1))>>1;
RED(j, i) = (RAW_LOW(j, i)+RAW_LOW(j, i+1))>>1;
/*
rgb[i*rgb_pitchj*3+0] = raw[i*raw_pitch+(j-1)*2+0]; // blue;
rgb[i*rgb_pitchj*3+1] = ((int)raw[i*raw_pitch+j*2+1]
+(int)raw[(i+1)*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitchj*3+2] = ((int)raw[i*raw_pitch+j*2+0]
+(int)raw[(i+1)*raw_pitch+j*2+0]+1)>>1; // red
*/
i++;
}

j = 0;
BLUE(j, i) = RAW_LOW(j, i);
GREEN(j, i) = RAW_HIGH(j, i);
RED(j, i) = RAW_LOW(j+1, i);
/*
rgb[i*rgb_pitch+j*3+0] = raw[i*raw_pitch+j*2+0]; // blue
rgb[i*rgb_pitch+j*3+1] = raw[i*raw_pitch+j*2+1]; // green
rgb[i*rgb_pitch+j*3+2] = raw[i*raw_pitch+(j+1)*2+0]; // red
*/
j++;
while (j < width-1) {
BLUE(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i))>>1;
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i)+RAW_HIGH(j+1, i))/3;
RED(j, i) = RAW_LOW(j, i);
/*
rgb[i*rgb_pitch+j*3+0] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]+1)>>1; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]+(int)raw[i*raw_pitch+(j+1)*2+1]+1)/3; // green
rgb[i*rgb_pitch+j*3+2] = raw[i*raw_pitch+j*2+0]; // red
*/
j++;
BLUE(j, i) = RAW_LOW(j, i);
GREEN(j, i) = RAW_HIGH(j, i);
RED(j, i) = (RAW_LOW(j-1, i)+RAW_LOW(j+1, i))>>1;
/*
rgb[i*rgb_pitch+j*3+0] = raw[i*raw_pitch+j*2+0]; // blue
rgb[i*rgb_pitch+j*3+1] = raw[i*raw_pitch+j*2+1]; // green
rgb[i*rgb_pitch+j*3+2] = ((int)raw[i*raw_pitch+(j-1)*2+0]+(int)raw[i*raw_pitch+(j+1)*2+0]+1)>>1; // red
*/
j++;
}
BLUE(j, i) = RAW_LOW(j-1, i);
GREEN(j, i) = (RAW_HIGH(j-1, i)+RAW_HIGH(j, i))>>1;
RED(j, i) = RAW_LOW(j, i);
/*
rgb[i*rgb_pitch+j*3+0] = raw[i*raw_pitch+(j-1)*2+0]; // blue
rgb[i*rgb_pitch+j*3+1] = ((int)raw[i*raw_pitch+(j-1)*2+1]+(int)raw[i*raw_pitch+j*2+1]+1)>>1; // green
rgb[i*rgb_pitch+j*3+2] = raw[i*raw_pitch+j*2+0]; // red
*/
}

Cypress FX2LP USB 인터페이스 Binder

현재 사용중인 환경은 Visual C++ 6.0이지만 아마도 상위 버전에서도 호환 될 것으로 예상된다. Binder는 Cypress 사가 제공하는 Development Suit의 드라이버와 Libusb-win32의 드라이버 모두에서 선택적으로 사용할 수 있도록 제작 되었다. Development Suit에서 제공하는 드라이버는 속도를 위해서 DeviceIOControl을 이용해 구현하였다. 테스트시 Hang On 상태일때 FX2LP 보드를 리셋 시켜야 테스트 프로그램이 정상적으로 종료 되기 때문에 여간 불편한게 아니다. 정상적으로 검증된 응용프로그램이라도 문제가 될 것같아. Libusb-win32를 사용하였다. Libusb-win32를 사용하면 다소 체감 속도는 감소하지만 Hang On 상태에서도 정상적으로 프로그램이 종료되고 다시 실행하면 초기 상태로 되돌아 간다. 이 문제는 USB 통신을 담당하는 thread가 정상적으로 종료되지 않아서 생기는 문제로 속도를 조금 손해 보더라도 테스트 환경을 위해서 libusb-win32를 사용할 것을 권한다.

간단한 사용방법은

int usb_binder::connectDevice(USHORT vid, USHORT pid)

위의 함수를 이용해서 vendor ID와 Product ID에 해당하는 디바이스와 연결하고 나머지 데이터의 통로는 FIFO를 통한 함수로 제공한다.

FX2LP의 포트와 I2C를 제어하기 위한 함수도 제공한다. 물론 FX2LP의 펌웨어 단에서 VRQ_???에 해당하는 command를 구현해주어야 한다. 이 부분은 다음 기회에 정리해서 올리도록 하겠다.

int controlPortA?(BOOL value, BOOL blink);

위의 포트 제어 함수는 value로 On/Off을 제어하고 blink로 1ms단위의 깜빡거림 제어하기 위한 매개변수이다.

int putI2C(UCHAR addr, UCHAR val);
int getI2C(UCHAR addr, UCHAR *val);
int getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val);
int setI2CReg(UCHAR addr, UCHAR reg, UCHAR val);

위의 네 함수는 I2C전송을 위한 함수이다. putI2C와 getI2C는 일반적인 I2C 전송을 목적으로 사용하는 것이고, 나머지 두 함수는 I2C로 디바이스의 내부 제어 레지스터를 읽고 쓸 목적으로 제공하는 함수이다.

가장 근본적인 데이타 전송은 Thread함수 내에 구현 되어 있다. 데이터 전송은 EP2만 사용가능하게 되어있지만 얼마든지 쉽게 수정가능하다. 주의 해야할 것은 NR_BUF와 BUF_SIZE를 적절하게 설정하는 것이다. BUF_SIZE는 한번에 non-EP0를 통해서 통신한 데이터의 크기이다. 최소 크기 512로 설정해 놓으면 모든 곳에서 작동하지만 데이터 처리속도와 효율성 면에서 가능한한 가장 큰 데이터 전송 단위로 설정할 것을 추천한다. 그리고 NR_BUF는 내부 FIFO의 저장 공간을 확보 할때 사용한다. 그 저장 공간은 NR_BUF*BUF_SIZE만큼 할당한다.

********************************** command.h *************************************

#ifndef __COMMANDS_H__
#define __COMMANDS_H__

#define MAX_EP0_PKTSIZE       64 // max size of EP0 packet on FX2

// ----------------------------------------------------------------
// Vendor bmRequestType's
// ----------------------------------------------------------------

#define VRT_VENDOR_IN 0xC0
#define VRT_VENDOR_OUT 0x40

// ----------------------------------------------------------------
//  USRP Vendor Requests
//
// Note that Cypress reserves [0xA0,0xAF].
// 0xA0 is the firmware load function.
// ----------------------------------------------------------------


// IN commands
#define VRQ_GET_STATUS 0x80
//#define VRQ_I2C_READ 0x81 // wIndexL: i2c id

// OUT commands
#define VRQ_PA0_CTRL    0xD0 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA1_CTRL 0xD1 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA3_CTRL 0xD2 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA7_CTRL            0xD3
#define VRQ_PE1_CTRL 0xD4
#define VRQ_I2C_WRITE 0xD5 // mValue = 0
// mIndex = addr;
// mLength = 0;
#define VRQ_I2C_READ 0xD6 // mValue = 0
// mIndex = addr;
// mLength = 4;
#define VRQ_I2C_WRITE_REG 0xD7 // mValue = ((USHORT)reg << 8) | (USHORT)val;
// mIndex = addr;
// mLength = 0;
#define VRQ_I2C_READ_REG 0xD8 // mValue = ((USHORT)reg << 8);
// mIndex = addr;
// mLength = 4;

#endif /* _COMMANDS_H_ */


********************************** usb_binder.h *************************************

/* USB Binder for libusb-win32

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/


// usb_binder.h: interface for the usb_binder class.
//
//////////////////////////////////////////////////////////////////////

#ifndef __USB_BINDER_H__
#define __USB_BINDER_H__

#include "../../commands.h"
//#include "../config.h"
//#undef USE_LIBUSB
//#define USE_CYAPI
#define USE_LIBUSB

#if defined(USE_LIBUSB)
# include
#elif defined(USE_CYAPI)
# include
# include
# include
#endif

#include "fifo.h"

class usb_binder
{
public:
void setDataEnable(BOOL enable);
ULONG readBuffer(UCHAR *buf, ULONG bufsize);
ULONG glimpseBuffer(UCHAR *buf, ULONG bufsize);
//void setSize(ULONG bufsize);
ULONG getSize(void);
int controlPortA0(BOOL value, BOOL blink);
int controlPortA1(BOOL value, BOOL blink);
int controlPortA3(BOOL value, BOOL blink);
int controlPortA7(BOOL value, BOOL blink);
//int controlPortE1(BOOL value, BOOL blink);

int putI2C(UCHAR addr, UCHAR val);
int getI2C(UCHAR addr, UCHAR *val);
int getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val);
int setI2CReg(UCHAR addr, UCHAR reg, UCHAR val);

int connectDevice(USHORT vid, USHORT pid);
usb_binder();
virtual ~usb_binder();
private:
fifo_t *mFifo;
int waitPortCtrlDone(void);
int waitI2CDone(void);
UCHAR mCommand;
USHORT mRequest, mValue, mIndex, mLength;
#ifdef USE_LIBUSB
usb_dev_handle *mDevice; /* the device handle */
#elif defined(USE_CYAPI)
HANDLE mDevice;
#endif
BOOL mThreadLooping;
CWinThread *mWinThread;
USHORT mPid;
USHORT mVid;
static UINT Thread(LPVOID params);
UCHAR *mXmitBuf;
HANDLE mMutex;
};

#endif /* __USB_BINDER_H__ */


********************************** usb_binder.cpp *************************************
/* USB Binder for libusb-win32

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/

// usb_binder.cpp: implementation of the usb_binder class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "usb_binder.h"
#include

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//#define TEST_ASYNC

#define NR_BUF   (3)
#define BUF_SIZE (1280*1024)

#define CMD_READ_I2C 0x01
#define CMD_WRITE_I2C 0x02
#define CMD_PORT_CTRL 0x04
#define CMD_READ_DATA 0x08

#define USB_ENDP_IN   (0x82)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

usb_binder::usb_binder()
{
mDevice = NULL;
mWinThread = NULL;
mThreadLooping = TRUE;
mVid = 0;
mPid = 0;
mCommand = 0;
mFifo = NULL;
mXmitBuf = (UCHAR *)malloc(64);
mMutex = CreateMutex(NULL, FALSE, NULL);
}

usb_binder::~usb_binder()
{
DWORD dwBytes;

mThreadLooping = FALSE;

#ifdef USE_CYAPI
if (mDevice) 
DeviceIoControl(mDevice, IOCTL_ADAPT_RESET_PARENT_PORT, NULL, 0, NULL, 0, &dwBytes, NULL);
#endif

Sleep(10);

if (mWinThread) {
CloseHandle(mWinThread->m_hThread);
mWinThread->m_hThread = NULL;
}

if (mFifo) fifo_delete(mFifo);

CloseHandle(mMutex);

free(mXmitBuf);

if (mDevice) CloseHandle(mDevice);
}

static UCHAR portal_buffer[512];
static UCHAR RecvBuff[BUF_SIZE];
static int RecvBuffSize = BUF_SIZE;

#ifdef USE_LIBUSB
/*
* Read/Write using async transfer functions.
*
* NOTE: This function waits for the transfer to complete essentially making
* it a sync transfer function so it only serves as an example of how one might
* implement async transfers into thier own code.
*/
static int transfer_bulk_async(usb_dev_handle *dev,
                               int ep,
                               char *bytes,
                               int size,
                               int timeout)
{
    // Each async transfer requires it's own context. A transfer
    // context can be re-used.  When no longer needed they must be
    // freed with usb_free_async().
    //
    void* async_context = NULL;
    int ret;

    // Setup the async transfer.  This only needs to be done once
    // for multiple submit/reaps. (more below)
    //
    ret = usb_bulk_setup_async(dev, &async_context, ep);
    if (ret < 0)
    {
        printf("error usb_bulk_setup_async:\n%s\n", usb_strerror());
        goto Done;
    }

    // Submit this transfer.  This function returns immediately and the
    // transfer is on it's way to the device.
    //
    ret = usb_submit_async(async_context, bytes, size);
    if (ret < 0)
    {
        printf("error usb_submit_async:\n%s\n", usb_strerror());
        usb_free_async(&async_context);
        goto Done;
    }

    // Wait for the transfer to complete.  If it doesn't complete in the
    // specified time it is cancelled.  see also usb_reap_async_nocancel().
    //
    ret = usb_reap_async(async_context, timeout);

    // Free the context.
    usb_free_async(&async_context);

Done:
    return ret;
}
#endif

UINT usb_binder::Thread(LPVOID params)
{
usb_binder *dlg;
int RecvCount = 0;
int byte_count = 0;
BOOL bPrevContinuous = FALSE;

int success;
int i; 
DWORD dwReturnBytes;

dlg = (usb_binder *)params;

#if defined(USE_LIBUSB)
printf("hello thread\n");
int ret;

for (;dlg->mThreadLooping;) {
if (dlg->mCommand & CMD_READ_I2C) { // send command to read i2c data
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 
dlg->mRequest,
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);

if (ret < 0) {
// error
} else {
for (i = 0; i < dlg->mLength; i++) {
dlg->mXmitBuf[i] = RecvBuff[i];
//printf("%02x ", pExtraData[i]);
}
//putchar('R');

//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_READ_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_WRITE_I2C) { // send command to write i2c data
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, 
dlg->mRequest,
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);
if (ret < 0) {
// error;
} else {
//putchar('W');
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_WRITE_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_PORT_CTRL) { // send command to reset CPLD chip
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, 
dlg->mRequest, //VRQ_PA0_CTRL
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);
if (ret < 0) {
// error
printf("CMD_PORT_CTRL error");
} else {
putchar('P');

//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_PORT_CTRL;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_READ_DATA) {
RecvBuffSize = BUF_SIZE;
#ifdef TEST_ASYNC
// Running an async read test
ret = transfer_bulk_async(dlg->mDevice, USB_ENDP_IN, (char *)RecvBuff, RecvBuffSize, 100);
#else
// Running a sync read test
ret = usb_bulk_read(dlg->mDevice, USB_ENDP_IN, (char *)RecvBuff, RecvBuffSize, 100);
#endif
if (ret < 0) {
//printf("error reading:\n%s\n", usb_strerror());
} else {
byte_count += ret;
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /*retval == WAIT_OBJECT_0*/) {
fifo_fill(dlg->mFifo, RecvBuff, ret);
}
//ReleaseMutex(dlg->m_hMutex[i]);
putchar('D');
}
}
//Sleep(0);
}
#elif defined(USE_CYAPI)

union  {
struct {
UCHAR Recipient:5; 
UCHAR Type:2; 
UCHAR Direction:1; 
} bmRequest; 
UCHAR bmReq; 
};
SINGLE_TRANSFER *pSingleTransfer;
UCHAR *pExtraData;
OVERLAPPED ov;

//pSingleTransfer = (SINGLE_TRANSFER *)malloc(sizeof(SINGLE_TRANSFER)+64);
pSingleTransfer = (SINGLE_TRANSFER *)portal_buffer;

/*
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 
*/
printf("hello thread\n");

for (;dlg->mThreadLooping;) {
//printf(".");

if (dlg->mCommand & CMD_READ_I2C) { // send command to read i2c data
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_FROM_DEVICE; // IN command (from  Device to Host) 
memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER)+dlg->mLength);
pSingleTransfer->SetupPacket.bmRequest = bmReq;
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest; //VRQ_I2C_READ;
pSingleTransfer->SetupPacket.wValue = dlg->mValue;
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex;
pSingleTransfer->SetupPacket.wLength = dlg->mLength;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER); //+dlg->mLength;
pSingleTransfer->BufferLength = dlg->mLength; 
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
if (!DeviceIoControl(dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER)+dlg->mLength,
pSingleTransfer, sizeof(SINGLE_TRANSFER)+dlg->mLength,
&dwReturnBytes,  NULL)) {
printf("VRQ_I2C_READ error\n");
//printf("dwReturnBytes%c, 0x%04x \n", dwReturnBytes, pSingleTransfer->SetupPacket.wValue);
} else {
//printf("VRQ_I2C_READ complete\n");
pExtraData = (UCHAR *)(pSingleTransfer+1);
for (i = 0; i < dlg->mLength; i++) {
dlg->mXmitBuf[i] = pExtraData[i];
//printf("%02x ", pExtraData[i]);
}
//printf("R");
}
dlg->mCommand &= ~CMD_READ_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_WRITE_I2C) { // send command to write i2c data
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->SetupPacket.bmRequest = bmReq; 
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest; //VRQ_I2C_WRITE;
pSingleTransfer->SetupPacket.wValue = dlg->mValue;
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex;
pSingleTransfer->SetupPacket.wLength = dlg->mLength;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER); 
pSingleTransfer->BufferLength = dlg->mLength;
//printf("VRQ_I2C_WRITE: wValue(%04x), wIndex(0x%04x), wLength(0x%04x)\n", dlg->mValue, dlg->mIndex, dlg->mLength);
if (!DeviceIoControl(dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER),
pSingleTransfer, sizeof(SINGLE_TRANSFER),
&dwReturnBytes,  NULL)) {
printf("VRQ_I2C_WRITE error\n");
} else {
// printf("VRQ_I2C_WRITE complete\n");
//printf("W");
}
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
dlg->mCommand &= ~CMD_WRITE_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_PORT_CTRL) { // send command to reset CPLD chip
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->SetupPacket.bmRequest = bmReq; 
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest;//VRQ_PA0_CTRL;
pSingleTransfer->SetupPacket.wValue = dlg->mValue; // port on
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex; // auto inv
pSingleTransfer->SetupPacket.wLength = 0;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);
pSingleTransfer->BufferLength = 0; 
if (!DeviceIoControl (dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER),
pSingleTransfer, sizeof(SINGLE_TRANSFER),
&dwReturnBytes,  NULL)) {
printf("VRQ_SEND_RESET error\n");
} else {
// printf("VRQ_SEND_RESET complete\n");
printf("P");
}
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
dlg->mCommand &= ~CMD_PORT_CTRL;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_READ_DATA) {
RecvBuffSize = 512; //BUF_SIZE;
memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->ucEndpointAddress = USB_ENDP_IN;
pSingleTransfer->IsoPacketLength = 0;
pSingleTransfer->BufferOffset = 0;
pSingleTransfer->BufferLength = 0;

success = DeviceIoControl(dlg->mDevice,
IOCTL_ADAPT_SEND_NON_EP0_DIRECT,
pSingleTransfer, sizeof(SINGLE_TRANSFER),
RecvBuff, RecvBuffSize,
&dwReturnBytes, NULL); 
//printf("red %d ", dwReturnBytes);
if (success && dwReturnBytes > 0) {
byte_count += RecvBuffSize;
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /*retval == WAIT_OBJECT_0*/) {
fifo_fill(dlg->mFifo, RecvBuff, RecvBuffSize);
}
//ReleaseMutex(dlg->m_hMutex[i]);
printf("D");
}
//if (!dlg->mThreadLooping) break;
}
}

// free(pSingleTransfer);
printf("exit thread\n");
dlg->mWinThread = NULL;

#endif

return TRUE;
}

#define MAX_DEVICE_NUMBER 10

int usb_binder::connectDevice(USHORT vid, USHORT pid)
{
if (mDevice) {
AfxMessageBox("Already connected device !!!", MB_ICONINFORMATION|MB_OK);
return -1;
}

#if defined(USE_LIBUSB)
int i, j, l, k;
// USB interface setting
struct usb_bus *bus;
struct usb_device *dev;
int udev_config = 1;
int udev_interface = 0;
usb_init(); /* initialize the library */
usb_find_busses(); /* find all busses */
usb_find_devices(); /* find all connected devices */

printf("Hello Libusb-win32\n");
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("VID_%04X, PID_%04X\r\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
if (dev->descriptor.idVendor == vid && dev->descriptor.idProduct == pid) {
printf("\"%s\"\r\n", dev->filename);
printf("Descriptor\r\n");
printf("VID_%04X, PID_%04X\r\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
printf("%d Configuration\r\n", i);
for (j = 0; j < dev->config[i].bNumInterfaces; j++) {
printf(" %d Interface\r\n", j);
for (l = 0; l < dev->config[i].interface[j].num_altsetting; l++) {
printf("  %d altsetting\r\n", l);
for (k = 0; k < dev->config[i].interface[j].altsetting[l].bNumEndpoints; k++) {
printf("   %d Endpoint\r\n", k);
printf("    Address : 0x%0X\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].bEndpointAddress);
printf("    Attribute : 0x%0X\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].bmAttributes);
printf("    MaxPacketSize : %d\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].wMaxPacketSize);
}
}
}
}
mDevice = usb_open(dev);
// goto __next_step;
}
}
}

//__next_step:;

if (mDevice) {
if (!(usb_set_configuration(mDevice, udev_config) < 0)) {
printf("Setting config %d\r\n", udev_config);
if (!(usb_claim_interface(mDevice, udev_interface) < 0)) {
printf("Claiming interface %d\r\n", udev_interface);
} else {
printf("error: claiming interface %d failed\r\n", udev_interface);
usb_close(mDevice);
mDevice = NULL;
}
} else {
printf("error: setting config %d failed\r\n", udev_config);
usb_close(mDevice);
mDevice = NULL;
}

if (mDevice) {
// need reset fifo
//usb_reset(mDevice);
usb_resetep(mDevice, USB_ENDP_IN);
//usb_clear_halt(mDevice, USB_ENDP_IN);

mVid = vid;
mPid = pid;

mFifo = fifo_create(BUF_SIZE*NR_BUF);

mWinThread = AfxBeginThread(Thread, this, THREAD_PRIORITY_NORMAL /* THREAD_PRIORITY_ABOVE_NORMAL,  THREAD_PRIORITY_HIGHEST */);
return 0;
}
// Syncronize tick
} else {
printf("error: device not found!\r\n");
}

#elif defined(USE_CYAPI)

char devPath[80];

sprintf(devPath, "\\\\?\\usb#vid_%04x&pid_%04x#", vid, pid);

HDEVINFO hwDeviceInfo = SetupDiGetClassDevs((LPGUID) &CYUSBDRV_GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 
if (hwDeviceInfo != INVALID_HANDLE_VALUE) {
SP_DEVICE_INTERFACE_DATA devInterfaceData; 
devInterfaceData.cbSize = sizeof(devInterfaceData);

for (int devNumber = 0; devNumber < MAX_DEVICE_NUMBER; devNumber++) {
if (!SetupDiEnumDeviceInterfaces(hwDeviceInfo, 0, (LPGUID) &CYUSBDRV_GUID, devNumber, &devInterfaceData))
break;

SP_DEVINFO_DATA deviceInfoData; 
memset(&deviceInfoData, 0, sizeof(SP_DEVINFO_DATA)); 
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; 
ULONG requiredLength = 0, reservedLength = 0, realLength = 0; 

if (!SetupDiGetDeviceInterfaceDetail(hwDeviceInfo, &devInterfaceData, NULL, 0, &requiredLength, NULL)) { 
int errorCode = GetLastError();
if (errorCode != ERROR_INSUFFICIENT_BUFFER) {
printf("SetupDiGetDeviceInterfaceDetail() failed.\n");
//AfxMessageBox("ERROR CODE %d (0x%X)\r\n", errorCode, errorCode);
break;
}
}
reservedLength = requiredLength; 
deviceInterfaceDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) new char[reservedLength]; 
memset(deviceInterfaceDetailData, 0, reservedLength); 
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
realLength = reservedLength; 
if (SetupDiGetDeviceInterfaceDetail(hwDeviceInfo, &devInterfaceData, deviceInterfaceDetailData, reservedLength, &realLength, &deviceInfoData)) { 
if (!memcmp(deviceInterfaceDetailData->DevicePath, devPath, strlen(devPath))) {
mDevice = CreateFile(deviceInterfaceDetailData->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 
}
} else { 
int error = ::GetLastError(); 
printf("SetupDiGetDeviceInterfaceDetail() is failed.\n");
break;

delete deviceInterfaceDetailData; 
deviceInterfaceDetailData = NULL;
if (mDevice) break;
}
SetupDiDestroyDeviceInfoList(hwDeviceInfo);

if (mDevice) {
DWORD dwBytes = 0; 
ULONG driver_version;
ULONG usdi_version;
UCHAR device_address;
UCHAR intfc = 0; 
UCHAR alt; 
UCHAR device_name[256], device_friendly_name[256]; 
ULONG device_speed;
UCHAR endPts; 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DRIVER_VERSION, 
&driver_version, sizeof (driver_version),      
&driver_version, sizeof (driver_version), 
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_USBDI_VERSION, 
&usdi_version, sizeof (usdi_version),      
&usdi_version, sizeof (usdi_version), 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DEVICE_NAME, 
device_name, 256, 
device_name, 256, 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_FRIENDLY_NAME,
device_friendly_name, 256,
device_friendly_name, 256,
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_ADDRESS, 
&device_address, sizeof (UCHAR),      
&device_address, sizeof (UCHAR), 
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DEVICE_SPEED,
&device_speed, sizeof (ULONG),
&device_speed, sizeof (ULONG),
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_ALT_INTERFACE_SETTING, 
&intfc, sizeof (intfc), 
&alt, sizeof (alt), 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_NUMBER_ENDPOINTS, 
NULL, 0,
&endPts, sizeof (endPts),
&dwBytes, NULL);

assert(endPts > 0);
printf("driver version: %x\n", driver_version);
printf("usdi version: %x\n", usdi_version);
printf("device name: %s\n", device_name);
printf("device friendly name: %s\n", device_friendly_name);
printf("device speed: %d\n", device_speed);
printf("device address: %d\n", device_address);
printf("intfc: %d, alt: %d\n", intfc, alt);
  printf("endpoint number: %d\n", endPts);

DWORD BytesXfered;
// Define Transfer Size
SET_TRANSFER_SIZE_INFO SetTransferInfo; 
SetTransferInfo.EndpointAddress = USB_ENDP_IN;
//SetTransferInfo.TransferSize = 3*m_FrameSize;
SetTransferInfo.TransferSize = 0x2000;

DeviceIoControl(mDevice, IOCTL_ADAPT_SET_TRANSFER_SIZE,
&SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
&SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
&BytesXfered,  NULL); 

DeviceIoControl(mDevice,  IOCTL_ADAPT_GET_TRANSFER_SIZE, 
&SetTransferInfo,  sizeof (SET_TRANSFER_SIZE_INFO), 
&SetTransferInfo,  sizeof (SET_TRANSFER_SIZE_INFO), 
&BytesXfered,  NULL); 

LONG transferSz = SetTransferInfo.TransferSize; 
printf("transfer size: %d\n", transferSz);

#if 0
// send reset signal
union  { 
struct   { 
UCHAR Recipient:5; 
UCHAR  Type:2; 
CHAR Direction:1; 
} bmRequest; 
UCHAR bmReq; 
}; 

bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

int iXmitBufSize = sizeof(SINGLE_TRANSFER);  //  The size of the two-part structure 
UCHAR *pXmitBuf = new UCHAR[iXmitBufSize];            //  Allocate the memory 
ZeroMemory(pXmitBuf, iXmitBufSize); 

PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER)pXmitBuf;  //  The SINGLE_TRANSFER comes first 

pTransfer->SetupPacket.bmRequest = bmReq; 
pTransfer->SetupPacket.bRequest = VRQ_SEND_RESET;
pTransfer->SetupPacket.wValue = 0; 
pTransfer->SetupPacket.wIndex = 0; 
pTransfer->SetupPacket.wLength = 0; 
pTransfer->SetupPacket.ulTimeOut = 100;
pTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pTransfer->IsoPacketLength = 0; 
pTransfer->BufferOffset = sizeof (SINGLE_TRANSFER); 
pTransfer->BufferLength = 0; 
DWORD dwReturnBytes; 

DeviceIoControl (mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pXmitBuf,  iXmitBufSize, 
pXmitBuf,  iXmitBufSize, 
&dwReturnBytes,  NULL); 
delete [] pXmitBuf;
Sleep(10);
#endif
DeviceIoControl(mDevice, IOCTL_ADAPT_RESET_PARENT_PORT, NULL, 0, NULL, 0, &dwBytes, NULL);

mVid = vid;
mPid = pid;

mFifo = fifo_create(BUF_SIZE*NR_BUF);

mWinThread = AfxBeginThread(Thread, this, THREAD_PRIORITY_NORMAL);

return 0;
} else {
printf("Device connection failed!!!\n");
}
}
#else
# error "unknown device driver!"
#endif

return -1;
}

int usb_binder::putI2C(UCHAR addr, UCHAR val)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_I2C_WRITE;
mValue = val;
mIndex = addr;
mLength = 0;
mCommand |= CMD_WRITE_I2C;
Sleep(1);
while (mCommand & CMD_WRITE_I2C); // putchar('c');
return 0;
}

int usb_binder::getI2C(UCHAR addr, UCHAR *val)
{
if (!(mDevice && mWinThread)) {
*val = 0;
return -1;
}
mRequest = VRQ_I2C_READ;
mValue = 0;
mIndex = addr;
mLength = 2; // the number of returned bytes
mCommand |= CMD_READ_I2C;
Sleep(1);
while (mCommand & CMD_READ_I2C);
if ((addr == mXmitBuf[0])) {
*val = mXmitBuf[1];
return 0;
}
printf("receiveI2C error\n");
*val = 0;
return -1;
}

int usb_binder::setI2CReg(UCHAR addr, UCHAR reg, UCHAR val)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_I2C_WRITE_REG;
mValue = ((USHORT)reg << 8) | (USHORT)val;
mIndex = addr;
mLength = 0;
mCommand |= CMD_WRITE_I2C;
Sleep(1);
while (mCommand & CMD_WRITE_I2C);
return 0;
}

int usb_binder::getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val)
{
if (!(mDevice && mWinThread)) {
*val = 0;
return -1;
}
mRequest = VRQ_I2C_READ_REG;
mValue = ((USHORT)reg << 8);
mIndex = addr;
mLength = 4; // the number of returned bytes
mCommand |= CMD_READ_I2C;
Sleep(1);
while (mCommand & CMD_READ_I2C);
/*
if ((reg == mXmitBuf[1]) && (addr == mXmitBuf[0])) {
*val = mXmitBuf[2];
return 0;
}
printf("receiveI2C error\n");
*/
*val = mXmitBuf[2];
return -1;
}

int usb_binder::controlPortA0(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA0_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA0");
return 0;
}

int usb_binder::controlPortA1(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA1_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA1 error");
return 0;
}

int usb_binder::controlPortA3(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA3_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA3 error");
return 0;
}

int usb_binder::controlPortA7(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA7_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA7 error");
return 0;
}

#if 0
int usb_binder::controlPortE1(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PE1_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortE1 error");
return 0;
}
#endif

int usb_binder::waitI2CDone() 
{
while (mCommand & (CMD_READ_I2C | CMD_WRITE_I2C));
return 0;
}

int usb_binder::waitPortCtrlDone()
{
while (mCommand & (CMD_PORT_CTRL));
return 0;
}

ULONG usb_binder::getSize(void)
{
if (!(mDevice && mWinThread)) return 0;
return fifo_filled_bytes(mFifo);
}

ULONG usb_binder::readBuffer(UCHAR *buf, ULONG bufsize)
{
ULONG fifo_len;

if (!(mDevice && mWinThread)) return 0;

fifo_len = fifo_filled_bytes(mFifo);
if (fifo_len >= bufsize) {
fifo_bring(buf, bufsize, mFifo);
return bufsize;
}
return 0;
}

ULONG usb_binder::glimpseBuffer(UCHAR *buf, ULONG bufsize)
{
ULONG fifo_len;

if (!(mDevice && mWinThread)) return 0;

fifo_len = fifo_filled_bytes(mFifo);
if (fifo_len >= bufsize) {
fifo_copy(buf, bufsize, mFifo);
return bufsize;
}
return 0;

}

void usb_binder::setDataEnable(BOOL enable)
{
if (!(mDevice && mWinThread)) return;
if (enable) mCommand |= CMD_READ_DATA;
else mCommand &= ~CMD_READ_DATA;
}