みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

C言語でUSB-IOを制御してみる

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

C言語でUSB-IOを制御してみる

投稿記事 by みけCAT » 11年前

公式サンプルはなぜか(宗教上の理由?)VBなのですが、
Windows、C言語でUSB-IO (正確にはUSB-IO2.0(AKI) ) を制御してみました。
「HID(Human Interface Device)として認識するので、ドライバを意識的にインストールする必要が無い」というのが売りのようです。

usb_io.c

CODE:

#include 
#include 
#include 
#include 
#include 

#define IO_SIZE 65

typedef struct {
	HANDLE hDevice;
	int vendor_id, product_id;
	HIDP_CAPS caps;
} hid_t;

int openHID(hid_t *hid, int vendor_id, const int product_ids[], int product_id_num) {
	GUID hid_guid;
	HDEVINFO hDeviceInfo;
	int index;
	HidD_GetHidGuid(&hid_guid);
	if (hid == NULL || product_ids == NULL || product_id_num cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
			if (!SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &did, detail, needed_size, &needed_size, &devinfo)) {
				HeapFree(GetProcessHeap(), 0, detail);
				break;
			}
			/* このデバイスを開く */
			hDevice = CreateFile(detail->DevicePath, GENERIC_READ | GENERIC_WRITE,
				FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
			HeapFree(GetProcessHeap(), 0, detail);
			if (hDevice != INVALID_HANDLE_VALUE) {
				HIDD_ATTRIBUTES attr;
				/* IDがマッチするかを調べる */
				if (HidD_GetAttributes(hDevice, &attr) && attr.VendorID == vendor_id) {
					int i, matched = 0;
					for (i = 0; i caps)) == HIDP_STATUS_SUCCESS) {
							/* 結果を返す */
							hid->hDevice = hDevice;
							hid->vendor_id = attr.VendorID;
							hid->product_id = attr.ProductID;
							SetupDiDestroyDeviceInfoList(hDeviceInfo);
							return 1;
						}
					}
				}
				CloseHandle(hDevice);
			}
		} else {
			break;
		}
	}
	SetupDiDestroyDeviceInfoList(hDeviceInfo);
	return 0;
}

int writeAndRead(HANDLE hHid,const unsigned char* writeData,unsigned char* readData) {
	DWORD size;
	if(!WriteFile(hHid,writeData,IO_SIZE,&size,NULL) || size!=IO_SIZE)return 0;
	if(!ReadFile(hHid,readData,IO_SIZE,&size,NULL) || size!=IO_SIZE)return 0;
	return 1;
}

int writeSettings(HANDLE hUsbIO,int disablePullup,int inputPin) {
	unsigned char write_buffer[IO_SIZE]={};
	unsigned char read_buffer[IO_SIZE]={};
	write_buffer[1]=0xf9;
	write_buffer[3]=(disablePullup?1:0);
	write_buffer[6]=inputPin&0xff;
	write_buffer[7]=(inputPin>>8)&0x0f;
	return writeAndRead(hUsbIO,write_buffer,read_buffer);
}

int readSettings(HANDLE hUsbIO,int *disablePullup,int *inputPin) {
	unsigned char write_buffer[IO_SIZE]={};
	unsigned char read_buffer[IO_SIZE]={};
	write_buffer[1]=0xf8;
	if(!writeAndRead(hUsbIO,write_buffer,read_buffer))return 0;
	if(disablePullup!=NULL)*disablePullup=(read_buffer[3]&1)?1:0;
	if(inputPin!=NULL)*inputPin=read_buffer[6]|(read_buffer[7]>8)&0x0f;
	if(!writeAndRead(hUsbIO,write_buffer,read_buffer))return 0;
	if(readData!=NULL)*readData=read_buffer[2]|(read_buffer[3]>(j+8))&1)?'1':'0');
			putchar(((i+1)%16==0)?'\n':'|');
		} else {
			char err[1024];
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),
				LANG_USER_DEFAULT,err,sizeof(err),NULL);
			printf("%s\n",err);
		}
		if(wait>0)Sleep(wait);
	}
}

int main(int argc,char* argv[]) {
	const int vendor_id = 0x1352;
	const int product_id[2] = {0x120, 0x121};
	const int product_id_num = 2;
	hid_t usb_io;
	int wait=500;
	if(openHID(&usb_io, vendor_id, product_id, product_id_num)) {
		printf("vendor_id  = 0x%X\n", usb_io.vendor_id);
		printf("product_id = 0x%X\n", usb_io.product_id);
		printf("writesize  = %d\n",usb_io.caps.OutputReportByteLength);
		printf("read_size  = %d\n",usb_io.caps.InputReportByteLength);
		if(usb_io.caps.OutputReportByteLength!=IO_SIZE ||
		usb_io.caps.InputReportByteLength!=IO_SIZE) {
			puts("unsupported device");
			CloseHandle(usb_io.hDevice);
			return 1;
		}
		if(argc>=2) {
			if(argv[1][0]=='s' && argv[1][1]=='\0') {
				if(argc>=4) {
					int disablePullup=0;
					int writePin=0xf00;
					sscanf(argv[2],"%d",&disablePullup);
					sscanf(argv[3],"%x",&writePin);
					writeSettings(usb_io.hDevice,disablePullup,writePin);
					puts("wrote settings");
					CloseHandle(usb_io.hDevice);
					return 0;
				} else {
					printf("Usage for config: %s s  \n",argv[0]);
					printf("disablePullup: 0 (enable), 1(disable)\n");
					printf("inputPin: bit 0-7: port0 bit 8-11: port1 in hex 0->output 1->input\n");
				}
			} else {
				sscanf(argv[1],"%d",&wait);
			}
		}
		asobu(usb_io.hDevice,wait);
		CloseHandle(usb_io.hDevice);
	} else {
		puts("open failed");
		return 1;
	}
	return 0;
}
Makefile

CODE:

CC=gcc
CFLAGS=-O2 -Wall -Wextra
LDFLAGS=-s -static
LIBS=-lsetupapi -lhid
OBJS=usb_io.o

usb_io.exe: $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $^

.PHONY: clean
clean:
	rm -rf usb_io.exe $(OBJS)
前半のデバイスを探す部分はほぼ公式サンプルのパクリです。

USB-IOをつないでこのプログラムを実行すると、ポート1の出力を順番に変えながら、ポート2のデータを読み取って表示します。
Sleepをしないと大体0.83秒で実行が終わるので、約300クエリ/秒の速さで処理できるようです。(公式ページにも300Hzと書いてあります)

これを用いてPICのプログラムの読み書きができれば、現行のArduinoを用いた方法より安価に読み書きできることになります。
しかし、300クエリ/秒の速さということは、例えば4096ワード書き込むことを考えると、
データを設定(6+16クロック)→書き込み(6クロック)→アドレスをインクリメント(6クロック)
の流れを4096回繰り返すことになります。
1クロックには上げと下げの2クエリを用いるので、合計で278528クエリが必要となり、
300クエリ/秒では約928秒、すなわち約15.5分かかる計算となります。
さすがに遅すぎるでしょうか…
WriteFileしたあとにReadFileしなければ約400クエリ/秒に上がりましたが、それでも約11分かかる上、
これで大丈夫なのかはわかりません。

コメントはまだありません。