Commits

Anonymous committed 405d343

Add Full duplex debug device code

Signed-off-by: Sven Schnelle <svens@stackframe.org>

Comments (0)

Files changed (6)

examples/debugdevice_full_duplex/Makefile

+FX2LIBDIR=../../
+BASENAME = debugdev
+SOURCES=debugdev.c
+A51_SOURCES=dscr.a51
+PID=0x1004
+CXX=g++
+HOSTCC=gcc
+CXXFLAGS=-Wall -Wextra -O2 -ggdb
+HOSTCFLAGS=-Wall -Wextra -O2 -ggdb
+
+all: test terminal build/debugdev.ihx
+include $(FX2LIBDIR)lib/fx2.mk
+
+download: build/$(BASENAME).ihx
+	  ./download.sh $<
+
+terminal:	terminal.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -lusb-1.0
+
+%:		%.cpp
+	$(CXX) $(CXXFLAGS) -o $@ $< -lusb-1.0

examples/debugdevice_full_duplex/debugdev.c

+/*
+ * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+#include <stdio.h>
+
+#include <fx2regs.h>
+#include <fx2macros.h>
+#include <serial.h>
+#include <delay.h>
+#include <autovector.h>
+#include <lights.h>
+#include <setupdat.h>
+#include <eputils.h>
+
+#define SYNCDELAY() SYNCDELAY4
+#define REARMVAL 0x80
+#define REARM() EP2BCL=REARMVAL
+
+volatile __bit got_sud;
+extern __code WORD debug_dscr;
+
+#define INPUTDATA IOB
+#define OUTPUTDATA IOD
+
+#define DVALID_IN (1 << 0)
+#define DLAST_IN (1 << 2)
+#define DRDY_IN  (1 << 3)
+
+#define DVALID_OUT (1 << 4)
+#define DLAST_OUT (1 << 6)
+#define DRDY_OUT  (1 << 7)
+
+typedef enum {
+	TX_STATE_IDLE=0,
+	TX_STATE_DATA,
+	TX_STATE_ACK,
+} tx_state_t;
+
+typedef enum {
+	RX_STATE_IDLE=0,
+	RX_STATE_DATA,
+	RX_STATE_ACK,
+} rx_state_t;
+
+static void tx_state(void)
+{
+	static int offset, last;
+	static tx_state_t state = TX_STATE_IDLE;
+
+	switch(state) {
+		case TX_STATE_IDLE:
+			if (EP2468STAT & bmEP6FULL)
+				break;
+			IOA |= DRDY_OUT;
+
+			if(IOA & DVALID_IN)
+				state = TX_STATE_DATA;
+			break;
+
+		case TX_STATE_DATA:
+			last = IOA & DLAST_IN;
+			EP6FIFOBUF[offset] = INPUTDATA;
+			IOA &= ~DRDY_OUT;
+			state = TX_STATE_ACK;
+			break;
+
+		case TX_STATE_ACK:
+			if (IOA & DVALID_IN)
+				break;
+			offset++;
+			if (last) {
+				EP6BCH = MSB(offset);
+				SYNCDELAY();
+				EP6BCL = LSB(offset);
+				state = TX_STATE_IDLE;
+				offset = 0;
+				break;
+			}
+			state = TX_STATE_IDLE;;
+			break;
+		default:
+			state = TX_STATE_IDLE;
+	}
+}
+
+static void rx_state(void)
+{
+	static int offset, remaining;
+	static rx_state_t state = RX_STATE_IDLE;
+
+	switch(state) {
+		case RX_STATE_IDLE:
+			if (EP2468STAT & bmEP2EMPTY)
+				break;
+
+			state = RX_STATE_DATA;
+			offset = 0;
+			remaining = MAKEWORD(EP2BCH, EP2BCL);
+			break;
+
+		case RX_STATE_DATA:
+			if (!(IOA & DRDY_IN))
+				break;
+
+			OUTPUTDATA = EP2FIFOBUF[offset++];
+
+			if (--remaining)
+				IOA &= ~DLAST_OUT;
+			else
+				IOA |= DLAST_OUT;
+
+			IOA |= DVALID_OUT;
+
+			state = RX_STATE_ACK;
+			break;
+
+		case RX_STATE_ACK:
+			if (IOA & DRDY_IN)
+				break;
+
+			IOA &= ~DVALID_OUT;
+
+			if (remaining) {
+				state = RX_STATE_DATA;
+			} else {
+				state = RX_STATE_IDLE;
+				REARM();
+			}
+			break;
+		default:
+			state = RX_STATE_IDLE;
+	}
+}
+
+static void mainloop(void)
+{
+	while(TRUE) {
+		if (got_sud) {
+			handle_setupdata();
+			got_sud=FALSE;
+		}
+		tx_state();
+		rx_state();
+	}
+}
+
+static void clock_setup(void)
+{
+	SETCPUFREQ(CLK_48M);
+	SETIF48MHZ();
+}
+
+static void usb_setup(void)
+{
+	RENUMERATE_UNCOND();
+
+	USE_USB_INTS();
+	ENABLE_SUDAV();
+	ENABLE_SOF();
+	ENABLE_HISPEED();
+	ENABLE_USBRESET();
+
+	/* BULK IN endpoint EP2 */
+	EP2CFG = 0xA2; // 10100010
+	SYNCDELAY();
+
+	/* BULK OUT endpoint EP6 */
+	EP6CFG = 0xE2; // 11100010
+	SYNCDELAY();
+
+	/* disable all other endpoints */
+
+	EP1INCFG &= ~bmVALID;
+	SYNCDELAY();
+
+	EP1OUTCFG &= ~bmVALID;
+	SYNCDELAY();
+
+	EP4CFG &= ~bmVALID;
+	SYNCDELAY();
+
+	EP8CFG &= ~bmVALID;
+	SYNCDELAY();
+
+	// arm ep2
+	EP2BCL = 0x80; // write once
+	SYNCDELAY();
+	EP2BCL = 0x80; // do it again
+}
+
+static void port_setup(void)
+{
+	IOA = 0;
+	IOB = 0xff;
+	IOD = 0xff;
+
+	OEA = 0xf0;	/* [3:0] INPUT, [7:4] OUTPUT */
+	OEB = 0;	/* INPUTDATA */
+	OED = 0xff;	/* OUTPUTDATA */
+}
+
+void main()
+{
+	REVCTL=0; // not using advanced endpoint controls
+
+	port_setup();
+
+	clock_setup();
+
+	usb_setup();
+
+	delay(10);
+
+	EA=1; // global __interrupt enable
+
+	mainloop();
+}
+
+#define VC_EPSTAT 0xB1
+
+BOOL handle_vendorcommand(BYTE cmd)
+{
+	__xdata BYTE* pep;
+	switch ( cmd ) {
+	case 6:
+		return TRUE;
+	case VC_EPSTAT:
+
+		pep = ep_addr(SETUPDAT[2]);
+		if (pep) {
+			EP0BUF[0] = *pep;
+			EP0BCH=0;
+			EP0BCL=1;
+			return TRUE;
+		}
+	default:
+	}
+	return FALSE;
+}
+
+// this firmware only supports 0,0
+BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
+{
+	if (ifc)
+		return FALSE;
+	*alt_ifc=0;
+	return TRUE;
+}
+
+BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
+{
+	if (ifc==0&&alt_ifc==0) {
+		// SEE TRM 2.3.7
+		// reset toggles
+		RESETTOGGLE(0x02);
+		RESETTOGGLE(0x86);
+		// restore endpoints to default condition
+		RESETFIFO(0x02);
+		EP2BCL=0x80;
+		SYNCDELAY();
+		EP2BCL=0X80;
+		SYNCDELAY();
+		RESETFIFO(0x86);
+		return TRUE;
+	} else
+		return FALSE;
+}
+
+// get/set configuration
+BYTE handle_get_configuration()
+{
+	return 1;
+}
+
+BOOL handle_get_descriptor(BYTE desc)
+{
+	if (desc != DSCR_DEBUG_TYPE)
+		return FALSE;
+
+	SUDPTRH = MSB((WORD)&debug_dscr);
+	SUDPTRL = LSB((WORD)&debug_dscr);
+	return TRUE;
+}
+
+BOOL handle_set_configuration(BYTE cfg)
+{
+
+	return cfg==1 ? TRUE : FALSE; // we only handle cfg 1
+}
+
+
+// copied usb jt routines from usbjt.h
+void sudav_isr() __interrupt SUDAV_ISR
+{
+	got_sud = TRUE;
+	CLEAR_SUDAV();
+}
+
+void sof_isr () __interrupt SOF_ISR __using 1
+{
+	CLEAR_SOF();
+}
+
+void usbreset_isr() __interrupt USBRESET_ISR
+{
+	handle_hispeed(FALSE);
+	CLEAR_USBRESET();
+}
+
+void hispeed_isr() __interrupt HISPEED_ISR
+{
+	handle_hispeed(TRUE);
+	CLEAR_HISPEED();
+}

examples/debugdevice_full_duplex/download.sh

+#!/bin/bash -e
+
+DEVS=$(lsusb|grep 04b4:8613|sed 's/:.*//;s/Bus //;s/Device //;s/ /\//')
+
+if [ -z "$1" ]; then
+    echo "$0: usage: $0 <file>"
+    exit 1;
+fi
+
+for dev in $DEVS;do
+    echo "Downloading $1 to $dev"
+    sudo /sbin/fxload -D /dev/bus/usb/$dev -t fx2lp -I $1
+done
+
+exit 0

examples/debugdevice_full_duplex/dscr.a51

+; Copyright (C) 2009 Ubixum, Inc.
+;
+; This library 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.1 of the License, or (at your option) any later version.
+;
+; This library 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 library; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+; this is a the default
+; full speed and high speed
+; descriptors found in the TRM
+; change however you want but leave
+; the descriptor pointers so the setupdat.c file works right
+
+
+.module DEV_DSCR
+
+; descriptor types
+; same as setupdat.h
+DSCR_DEVICE_TYPE=1
+DSCR_CONFIG_TYPE=2
+DSCR_STRING_TYPE=3
+DSCR_INTERFACE_TYPE=4
+DSCR_ENDPOINT_TYPE=5
+DSCR_DEVQUAL_TYPE=6
+
+; for the repeating interfaces
+DSCR_INTERFACE_LEN=9
+DSCR_ENDPOINT_LEN=7
+
+; endpoint types
+ENDPOINT_TYPE_CONTROL=0
+ENDPOINT_TYPE_ISO=1
+ENDPOINT_TYPE_BULK=2
+ENDPOINT_TYPE_INT=3
+
+    .globl	_dev_dscr, _dev_qual_dscr, _highspd_dscr, _fullspd_dscr, _debug_dscr, _dev_strings, _dev_strings_end
+; These need to be in code memory.  If
+; they aren't you'll have to manully copy them somewhere
+; in code memory otherwise SUDPTRH:L don't work right
+    .area	DSCR_AREA	(CODE)
+
+_dev_dscr:
+	.db	dev_dscr_end-_dev_dscr    ; len
+	.db	DSCR_DEVICE_TYPE		  ; type
+	.dw	0x0002					  ; usb 2.0
+	.db	0xff  					  ; class (vendor specific)
+	.db	0					  ; subclass (vendor specific)
+	.db	0					  ; protocol (vendor specific)
+	.db	64						  ; packet size (ep0)
+	.dw	0xb404					  ; vendor id
+	.dw	0x1386					  ; product id
+	.dw	0x0100					  ; version id
+	.db	1					  ; manufacturure str idx
+	.db	2				          ; product str idx
+	.db	0				          ; serial str idx
+	.db	1			              ; n configurations
+dev_dscr_end:
+
+_dev_qual_dscr:
+	.db	dev_qualdscr_end-_dev_qual_dscr
+	.db	DSCR_DEVQUAL_TYPE
+	.dw	0x0002                              ; usb 2.0
+	.db	0xff
+	.db	0x00
+	.db	0x0
+	.db	64                                  ; max packet
+	.db	1									; n configs
+	.db	0									; extra reserved byte
+dev_qualdscr_end:
+
+_debug_dscr:
+	.db	_debug_dscr_end - _debug_dscr
+	.db	10
+	.db	0x86
+	.db	0x02
+_debug_dscr_end:
+
+
+_highspd_dscr:
+	.db	highspd_dscr_end-_highspd_dscr      ; dscr len											;; Descriptor length
+	.db	DSCR_CONFIG_TYPE
+    ; can't use .dw because byte order is different
+	.db	(highspd_dscr_realend-_highspd_dscr) % 256 ; total length of config lsb
+	.db	(highspd_dscr_realend-_highspd_dscr) / 256 ; total length of config msb
+	.db	1								 ; n interfaces
+	.db	1								 ; config number
+	.db	0								 ; config string
+	.db	0x80                             ; attrs = bus powered, no wakeup
+	.db	0x32                             ; max power = 100ma
+highspd_dscr_end:
+
+; all the interfaces next
+; NOTE the default TRM actually has more alt interfaces
+; but you can add them back in if you need them.
+; here, we just use the default alt setting 1 from the trm
+	.db	DSCR_INTERFACE_LEN
+	.db	DSCR_INTERFACE_TYPE
+	.db	0				 ; index
+	.db	0				 ; alt setting idx
+	.db	2				 ; n endpoints
+	.db	0xff			 ; class
+	.db	0
+	.db	0
+	.db	3	             ; string index
+
+; endpoint 2 out
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x02				;  ep2 dir=OUT and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x00				; max packet LSB
+	.db	0x02				; max packet size=512 bytes
+	.db	0x00				; polling interval
+
+; endpoint 6 in
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x86				;  ep6 dir=in and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x00				; max packet LSB
+	.db	0x02				; max packet size=512 bytes
+	.db	0x00				; polling interval
+
+highspd_dscr_realend:
+
+    .even
+_fullspd_dscr:
+	.db	fullspd_dscr_end-_fullspd_dscr      ; dscr len
+	.db	DSCR_CONFIG_TYPE
+    ; can't use .dw because byte order is different
+	.db	(fullspd_dscr_realend-_fullspd_dscr) % 256 ; total length of config lsb
+	.db	(fullspd_dscr_realend-_fullspd_dscr) / 256 ; total length of config msb
+	.db	1								 ; n interfaces
+	.db	1								 ; config number
+	.db	0								 ; config string
+	.db	0x80                             ; attrs = bus powered, no wakeup
+	.db	0x32                             ; max power = 100ma
+fullspd_dscr_end:
+
+; all the interfaces next
+; NOTE the default TRM actually has more alt interfaces
+; but you can add them back in if you need them.
+; here, we just use the default alt setting 1 from the trm
+	.db	DSCR_INTERFACE_LEN
+	.db	DSCR_INTERFACE_TYPE
+	.db	0				 ; index
+	.db	0				 ; alt setting idx
+	.db	2				 ; n endpoints
+	.db	0xff			 ; class
+	.db	0xff
+	.db	0xff
+	.db	3	             ; string index
+
+; endpoint 2 out
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x02				;  ep2 dir=OUT and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x40				; max packet LSB
+	.db	0x00				; max packet size=64 bytes
+	.db	0x00				; polling interval
+
+; endpoint 6 in
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x86				;  ep6 dir=in and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x40				; max packet LSB
+	.db	0x00				; max packet size=64 bytes
+	.db	0x00				; polling interval
+
+fullspd_dscr_realend:
+
+.even
+_dev_strings:
+; sample string
+_string0:
+	.db	string0end-_string0 ; len
+	.db	DSCR_STRING_TYPE
+    .db 0x09, 0x04     ; who knows
+string0end:
+; add more strings here
+
+_string1:
+    .db string1end-_string1
+    .db DSCR_STRING_TYPE
+    .ascii 'N'
+    .db 0
+    .ascii 'o'
+    .db 0
+    .ascii 'n'
+    .db 0
+    .ascii 'e'
+    .db 0
+string1end:
+
+_string2:
+    .db string2end-_string2
+    .db DSCR_STRING_TYPE
+    .ascii 'E'
+    .db 0
+    .ascii 'H'
+    .db 0
+    .ascii 'C'
+    .db 0
+    .ascii 'I'
+    .db 0
+    .ascii ' '
+    .db 0
+    .ascii 'D'
+    .db 0
+    .ascii 'e'
+    .db 0
+    .ascii 'b'
+    .db 0
+    .ascii 'u'
+    .db 0
+    .ascii 'g'
+    .db 0
+    .ascii ' '
+    .db 0
+    .ascii 'c'
+    .db 0
+    .ascii 'a'
+    .db 0
+    .ascii 'b'
+    .db 0
+    .ascii 'l'
+    .db 0
+    .ascii 'e'
+    .db 0
+string2end:
+
+_string3:
+    .db string3end-_string3
+    .db DSCR_STRING_TYPE
+    .ascii 'i'
+    .db 0
+    .ascii 'F'
+    .db 0
+    .ascii 'a'
+    .db 0
+    .ascii 'c'
+    .db 0
+    .ascii 'e'
+    .db 0
+string3end:
+
+_dev_strings_end:
+    .dw 0x0000   ; just in case someone passes an index higher than the end to the firmware

examples/debugdevice_full_duplex/terminal.c

+/**
+ * Copyright (C) 2012 Sven Schnelle <svens@stackframe.rog>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+#include <stdio.h>
+#include <assert.h>
+#include <libusb-1.0/libusb.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+void tp_diff(struct timespec *diff, struct timespec *start, struct timespec *end)
+{
+	if (end->tv_nsec - start->tv_nsec < 0) {
+		diff->tv_sec = end->tv_sec - start->tv_sec - 1;
+		diff->tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec;
+	} else {
+		diff->tv_sec = end->tv_sec - start->tv_sec;
+		diff->tv_nsec = end->tv_nsec - start->tv_nsec;
+	}
+}
+
+static int format_timediff(struct timespec *diff, char *out, int outlen)
+{
+	if (diff->tv_sec > 1)
+		return snprintf(out, outlen, "%d.%02lds", (int)diff->tv_sec,
+				diff->tv_nsec / 10000000);
+
+	if (diff->tv_nsec > 1000000)
+		return snprintf(out, outlen, "%ldms", diff->tv_nsec / 1000000);
+
+	if (diff->tv_nsec > 1000)
+		return snprintf(out, outlen, "%ldus", diff->tv_nsec / 1000);
+
+	return snprintf(out, outlen, "%ldns", diff->tv_nsec);
+
+}
+
+static int terminal_loop(libusb_device_handle *hndl, FILE *outfile)
+{
+	unsigned char buf[512];
+	char timebuf[32];
+
+	struct timespec tp, oldtp, diff, lastlinetp, linediff;
+	unsigned char c;
+	int print_time = 1;
+	int len, ret, i;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &oldtp) == -1) {
+		fprintf(stderr, "clock_gettime: %s\n", strerror(errno));
+		return -1;
+	}
+
+	memcpy(&lastlinetp, &oldtp, sizeof(lastlinetp));
+	for(;;) {
+		ret = libusb_bulk_transfer(hndl, 0x86, (unsigned char*)buf ,sizeof(buf), &len, sizeof(buf));
+
+		if (ret == -4) {
+			fprintf(stderr, "device disappeared\n");
+			return -1;
+		}
+
+		if(ret != -7 && ret != 0) {
+			printf("IN Transfer failed: %d\n", ret);
+			return -1;
+		}
+
+		for (i = 0; i < len; i++) {
+
+			if (print_time) {
+				print_time = 0;
+				if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
+					fprintf(stderr, "clock_gettime: %s\n", strerror(errno));
+					return -1;
+				}
+
+				tp_diff(&diff, &oldtp, &tp);
+				tp_diff(&linediff, &lastlinetp, &tp);
+
+				format_timediff(&linediff, timebuf, sizeof(timebuf)-1);
+
+				printf("%3d.%03ld [%5s]: ", (int)diff.tv_sec, diff.tv_nsec / 1000000, timebuf);
+				fprintf(outfile, "%3d.%03ld [%5s]: ", (int)diff.tv_sec, diff.tv_nsec / 1000000, timebuf);
+
+				memcpy(&lastlinetp, &tp, sizeof(lastlinetp));
+			}
+
+			c = buf[i];
+
+			if (c == '\r')
+				continue;
+
+			printf ("%c", c);
+
+			print_time = !!(c == '\n');
+
+
+			if (outfile)
+				fputc(buf[i], outfile);
+		}
+	}
+}
+
+int main(int argc __attribute__((unused)),
+	char **argv __attribute__((unused)))
+{
+	FILE *outfile;
+	libusb_context* ctx;
+	libusb_device_handle *hndl;
+
+	libusb_init(&ctx);
+
+restart:
+	hndl = libusb_open_device_with_vid_pid(ctx, 0x4b4, 0x8613);
+	if (!hndl) {
+//		fprintf(stderr, "failed to open device\n");
+		sleep(1);
+		goto restart;
+	}
+
+	libusb_claim_interface(hndl, 0);
+	libusb_set_interface_alt_setting(hndl, 0, 0);
+
+	printf("Device opened\n");
+
+	outfile = fopen("debuglog.txt", "w+");
+	if (!outfile) {
+	    fprintf(stderr, "fopen: debuglog.txt: %s", strerror(errno));
+	    goto out;
+	}
+
+	if (terminal_loop(hndl, outfile) == -1)
+		goto restart;
+
+out:
+	if (outfile)
+	    fclose(outfile);
+	libusb_close(hndl);
+	return 0;
+}

examples/debugdevice_full_duplex/test.cpp

+/**
+ * Copyright (C) 2009 Ubixum, Inc.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+#include <cstdio>
+#include <cassert>
+#include <libusb-1.0/libusb.h>
+#include <cstring>
+
+int main(int argc __attribute__((unused)),
+	char **argv __attribute__((unused)))
+{
+	int transferred, rv, i, hdlidx;
+	libusb_context* ctx;
+	unsigned char buf[256];
+	libusb_device_handle *hndl[2];
+	ssize_t devcount;
+	struct libusb_device_descriptor desc;
+
+	libusb_device **devlist;
+	libusb_init(&ctx);
+
+	devcount = libusb_get_device_list(ctx, &devlist);
+
+	for(i = 0, hdlidx = 0; i < devcount && hdlidx < 2; i++) {
+		if (libusb_get_device_descriptor(devlist[i], &desc) != 0)
+			continue;
+
+		if (desc.idVendor == 0x04b4 && desc.idProduct == 0x8613) {
+			if (!(libusb_open(devlist[i], &hndl[hdlidx]))) {
+				printf("opened device %d\n", hdlidx);
+				hdlidx++;
+			}
+		}
+			
+	}
+
+	if (hdlidx != 2) {
+		fprintf(stderr, "Need two devices, have %d\n", hdlidx);
+		return 1;
+	}
+
+	libusb_claim_interface(hndl[0],0);
+	libusb_claim_interface(hndl[1],0);
+
+	libusb_set_interface_alt_setting(hndl[0], 0, 0);
+	libusb_set_interface_alt_setting(hndl[1], 0, 0);
+
+	for (i = 0; i < (int)sizeof(buf); i++)
+		buf[i] = i;
+
+	printf("OUT transfer to device 0, PIPE 2\n");
+	rv = libusb_bulk_transfer(hndl[0], 0x02, buf, sizeof(buf), &transferred, sizeof(buf));
+
+	if(rv)
+		printf("OUT Transfer failed: %d\n", rv);
+
+	printf("IN transfer to device 1, PIPE 6\n");
+
+	memset(buf, 0, sizeof(buf));
+	transferred = 0;
+
+	rv=libusb_bulk_transfer(hndl[1], 0x86, (unsigned char*)buf ,sizeof(buf), &transferred, sizeof(buf));
+	if(rv)
+		printf("IN Transfer failed: %d\n", rv);
+
+	printf("received %d bytes:\n", transferred);
+
+	for (i = 0; i < transferred; i++)
+		printf ("%02x ", buf[i]);
+	printf("\n");
+
+	printf("OUT transfer to device 1, PIPE 2\n");
+	rv = libusb_bulk_transfer(hndl[1], 0x02, buf, sizeof(buf), &transferred, sizeof(buf));
+
+	if(rv)
+		printf("OUT Transfer failed: %d\n", rv);
+
+	printf("IN transfer to device 0, PIPE 6\n");
+
+	memset(buf, 0, sizeof(buf));
+	transferred = 0;
+
+	rv=libusb_bulk_transfer(hndl[0], 0x86, (unsigned char*)buf ,sizeof(buf), &transferred, sizeof(buf));
+	if(rv)
+		printf("IN Transfer failed: %d\n", rv);
+
+	printf("received %d bytes:\n", transferred);
+
+	for (i = 0; i < transferred; i++)
+		printf ("%02x ", buf[i]);
+	printf("\n");
+
+	libusb_free_device_list(devlist, 1);
+	libusb_close(hndl[0]);
+	return 0;
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.