FTDI Community

General Category => Discussion - Software => Topic started by: AndersG on November 19, 2020, 05:55:06 PM

Title: Adapting USBHostHID2 - Support one or two devices. Detect insertion.
Post by: AndersG on November 19, 2020, 05:55:06 PM
OK. Making progress. I split up the code to two threads. One for setup that runs once per second and the other that handles the EP interrupts. This works. I can start with one or two USB devices when powering on. Ideally would I like to detect if  a device is added. The code does that, but it fails to initialise the port where I added say a mouse after the fact and I cannot understand why? Possibly do I not know enough about this environment, so I solicit for help here :)

What happens if I add a mouse to port 0 afterwards is that I see it being detected and configured, but I get a "Port 0 read failure 7" where / apparently is USBHOST_TD_FULL. Why?

Code: [Select]
/*
** Filename: USBHostHID2.c
**
** Adapted from FTDI sample code
**
** Purpose: Act as USB to SPI bridge. passing on keypresses and mouse movements
**
**
** Links/doc:
** http://joshp.no-ip.com:8080/vnc2/#issue2
*/

#include "USBHostHID2.h"

/* FTDI:STP Thread Prototypes */
vos_tcb_t *tcbFIRMWARE;
vos_tcb_t *tcbSETUP;

void firmware();
void setup();

//Driver Handles
VOS_HANDLE hUSBHOST_1; // USB Host Port 1
VOS_HANDLE hUSBHOST_2; // USB Host Port 2
VOS_HANDLE hUART; // UART Interface Driver
#ifdef USE_SPI
VOS_HANDLE hSPI_MASTER; // SPIMaster Interface Driver
#endif

// use our own driver handles to simplify code later
VOS_HANDLE hUsb[2];
int tick = 0;
/* Declaration for IOMUx setup function */
void iomux_setup(void);
//--------------------------- GLOBALS -------------------
// test buffer
char buf[64];
char *eol = "\r\n";
char replybuf[64];

unsigned char i;
unsigned short len;
unsigned short written;
unsigned char status;
unsigned char n, m;
unsigned char ch;
unsigned int replylen;
unsigned char flag;
// GPIO and LEDs
unsigned char leds;

// device handle
usbhost_device_handle_ex ifDev;
// endpoint handles
usbhost_ep_handle_ex epInt[2], epCtrl[2];
// endpoint maxPacketLength values
unsigned char maxPack[2];

// completion semaphore and set semaphore list
vos_semaphore_t semRead;
vos_semaphore_t endpointSem[2];

// Host Controller ioctl request block
usbhost_ioctl_cb_t hc_iocb;
usbhost_ioctl_cb_vid_pid_t hc_ioctVidPid;

// interrupt endpoint transfer descriptor
usbhost_xfer_t xfer[2];

// UART ioctl request block
common_ioctl_cb_t uart_iocb;
#ifdef USE_SPI
// SPI Master ioctl request block
common_ioctl_cb_t spim_iocb;
#endif
// host controller device descriptor
usb_deviceRequest_t desc_dev;

// endpoint information
usbhost_ioctl_cb_ep_info_t epInfo;
//
vos_semaphore_t setupSem;
// ---------------------------------------------------------

// Main code - entry point to firmware
void main(void)
{
// UART Driver configuration context
uart_context_t uartContext;
// USB Host configuration context
usbhost_context_t usbhostContext;

#ifdef USE_SPI
// SPI Master configuration context
spimaster_context_t spimContext;
#endif
// Kernel Initialisation
vos_init(50, VOS_TICK_INTERVAL, VOS_NUMBER_DEVICES);
vos_set_clock_frequency(VOS_48MHZ_CLOCK_FREQUENCY);
vos_set_idle_thread_tcb_size(512);

iomux_setup();

// Initialise UART
#ifdef USE_UART
uartContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;
uart_init(VOS_DEV_UART,&uartContext);
#endif
//
// SPI
#ifdef USE_SPI
spimContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;
spimaster_init(VOS_DEV_SPI_MASTER,&spimContext);
#endif

// Initialise USB Host
usbhostContext.if_count = 8;
usbhostContext.ep_count = 16;
usbhostContext.xfer_count = 2;
usbhostContext.iso_xfer_count = 2;
usbhost_init(VOS_DEV_USBHOST_1, VOS_DEV_USBHOST_2, &usbhostContext);

vos_init_semaphore(&setupSem, 0);

//Thread Creation, one for setup, one for interrupts
tcbFIRMWARE = vos_create_thread_ex(21, 4096, firmware, "Application", 0);
tcbFIRMWARE = vos_create_thread_ex(20, 4096, setup, "Setup", 0);
//
vos_gpio_set_port_mode(GPIO_PORT_A, 0xff);  // set all as output for leds
//
vos_start_scheduler();
flag = 0;

main_loop:
goto main_loop;
}

// FTDI:SSP Support Functions

unsigned char usbhost_connect_state(VOS_HANDLE hUSB)
{
unsigned char connectstate = PORT_STATE_DISCONNECTED;
usbhost_ioctl_cb_t hc_iocb;

if (hUSB)
{
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_GET_CONNECT_STATE;
hc_iocb.get        = &connectstate;
vos_dev_ioctl(hUSB, &hc_iocb);

    // repeat if connected to see if we move to enumerated
if (connectstate == PORT_STATE_CONNECTED)
{
vos_dev_ioctl(hUSB, &hc_iocb);
}
}
return connectstate;
}

void open_drivers(void)
{
/* Code for opening and closing drivers - move to required places in Application Threads */
/* FTDI:SDA Driver Open */
hUSBHOST_1 = vos_dev_open(VOS_DEV_USBHOST_1);
hUSBHOST_2 = vos_dev_open(VOS_DEV_USBHOST_2);
#ifdef USE_UART
hUART = vos_dev_open(VOS_DEV_UART);
#endif
#ifdef USE_SPI
hSPI_MASTER = vos_dev_open(VOS_DEV_SPI_MASTER);
#endif
}

void attach_drivers(void)
{
/* FTDI:SUA Layered Driver Attach Function Calls */
/* FTDI:EUA */
}

void close_drivers(void)
{
vos_dev_close(hUSBHOST_1);
vos_dev_close(hUSBHOST_2);
vos_dev_close(hUART);
#ifdef USE_SPI
vos_dev_close(hSPI_MASTER);
#endif
}

// Helpers
// Write text on UART
void message(char *msg)
{
#ifdef USE_UART
vos_dev_write(hUART, (unsigned char *) msg, strlen(msg), NULL);
#endif
}
// Write number on UART
void number(unsigned char val)
{
#ifdef USE_UART
char letter;
unsigned char nibble;

nibble = (val >> 4) + '0';

if (nibble > '9')
nibble += ('A' - '9' - 1);

vos_dev_write(hUART, &nibble, 1, NULL);
nibble = (val & 15) + '0';

if (nibble > '9')
nibble += ('A' - '9' - 1);

vos_dev_write(hUART, &nibble, 1, NULL);
#endif
}

vos_semaphore_list_t *sem_list;        // pointer to semaphore list
// This is the thread that handles keypresses and mouse movements
void firmware(void)
{
// Wait for the setup sem to finish...
vos_wait_semaphore(&setupSem);
while(1)
{
if (epCtrl[0] || epCtrl[1])
{
sem_list = (vos_semaphore_list_t *) vos_malloc(VOS_SEMAPHORE_LIST_SIZE(2));
sem_list->next = NULL;     // initialise semaphore list
sem_list->siz = 2;         // 2 semaphores (1 for each device endpoint)
sem_list->flags = VOS_SEMAPHORE_FLAGS_WAIT_ANY;

// initialise semaphore
vos_init_semaphore(&endpointSem[0], 0);
vos_init_semaphore(&endpointSem[1], 0);

n = -1;

memset(xfer, 0, sizeof(xfer));

xfer[0].buf = buf;
xfer[0].ep = epInt[0];
xfer[0].s = &endpointSem[0];
// Do not block on completion... we will wait on the sempaphore later
xfer[0].flags = USBHOST_XFER_FLAG_NONBLOCKING | USBHOST_XFER_FLAG_ROUNDING;

xfer[1].buf = buf;
xfer[1].s = &endpointSem[1];
xfer[1].ep = epInt[1];
xfer[1].flags = USBHOST_XFER_FLAG_NONBLOCKING | USBHOST_XFER_FLAG_ROUNDING;

while (1)
{
if(flag == 1) message("hello   ");
// Start or restart each endpoint transfer
if (n != 1 || flag == 1)
{
sem_list->list[0] = &endpointSem[0];
xfer[0].len = maxPack[0];
xfer[0].cond_code = USBHOST_CC_NOTACCESSED;
status = vos_dev_read(hUsb[0], (unsigned char *) &xfer[0], sizeof(usbhost_xfer_t), NULL);

if (status != USBHOST_OK)
{
message("Port 00 Read Failed - code ");
number(status);
message(eol);
//break;
}
flag = 0;
}

if (n != 0 || flag == 1)
{
sem_list->list[1] = &endpointSem[1];
xfer[1].len = maxPack[1];
xfer[1].cond_code = USBHOST_CC_NOTACCESSED;

status = vos_dev_read(hUsb[1], (unsigned char *) &xfer[1], sizeof(usbhost_xfer_t), NULL);

if (status != USBHOST_OK)
{
message("Port 01 Read Failed - code ");
number(status);
message(eol);
//break;
}
flag = 0;
}

// Wait on a key press from either endpoint...
n = vos_wait_semaphore_ex(sem_list);

// Display data received
number(tick++);
message(" Port ");
number(n);
message(" Data: ");

// Display the data from the keyboard...
if (n == 0)
{
//  sem0 has signalled
leds = leds | LED3;
vos_gpio_write_port(GPIO_PORT_A, leds);
replybuf[0] = 0x13;
replybuf[1] = (unsigned char) xfer[0].len;
replylen = 2;
for (i = 0; i < xfer[0].len; i++)
{
number(buf[i]);
ch = buf[i];
replybuf[replylen++] = (ch >> 4); // MSB
replybuf[replylen++] = (ch & 0x0f); // LSB
}
replybuf[replylen++] = 0x14;
#ifdef USE_SPI
vos_dev_write(hSPI_MASTER, (unsigned char *)replybuf, (uint16)replylen, NULL);
#endif
}
else if (n == 1)
{
// sem1 has signalled
leds = led | LED3;
vos_gpio_write_port(GPIO_PORT_A, leds);
replybuf[0] = 0x13;
replybuf[1] = (unsigned char)xfer[1].len;
replylen = 2;
for (i = 0; i < xfer[1].len; i++)
{
number(buf[i]);
ch = buf[i];
replybuf[replylen++] = (ch >> 4); // MSB
replybuf[replylen++] = (ch & 0x0f); // LSB
}
replybuf[replylen++] = 0x14;
#ifdef USE_SPI
vos_dev_write(hSPI_MASTER, (unsigned char *)replybuf, (uint16) replylen, NULL);
#endif
}

message(eol);
}
}
}
}
// Setup the USB ports, then hand off to other thread
void setup(void)
{
int tick = 0;
epInt[0] = NULL;
epCtrl[0] = NULL;
epInt[1] = NULL;
epCtrl[1] = NULL;

open_drivers();
hUsb[0] = hUSBHOST_1;
hUsb[1] = hUSBHOST_2;

#ifdef USE_UART
//uart_iocb.ioctl_code = VOS_IOCTL_COMMON_ENABLE_DMA;
//uart_iocb.set.param = DMA_ACQUIRE_AS_REQUIRED;
//vos_dev_ioctl(hUART, &uart_iocb);

// set baud rate
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_BAUD_RATE;
uart_iocb.set.uart_baud_rate = UART_BAUD_9600; //UART_BAUD_115200
vos_dev_ioctl(hUART, &uart_iocb);

// set flow control
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_FLOW_CONTROL;
uart_iocb.set.param = UART_FLOW_RTS_CTS;
vos_dev_ioctl(hUART, &uart_iocb);

// set data bits
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_DATA_BITS;
uart_iocb.set.param = UART_DATA_BITS_8;
vos_dev_ioctl(hUART, &uart_iocb);

// set stop bits
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_STOP_BITS;
uart_iocb.set.param = UART_STOP_BITS_1;
vos_dev_ioctl(hUART, &uart_iocb);

// set parity
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_PARITY;
uart_iocb.set.param = UART_PARITY_NONE;
vos_dev_ioctl(hUART, &uart_iocb);
#endif
#ifdef USE_SPI
// set clock phase
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SCK_CPHA;
spim_iocb.set.param = SPI_MASTER_SCK_CPHA_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set clock polarity
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SCK_CPOL;
spim_iocb.set.param = SPI_MASTER_SCK_CPOL_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set data order
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_DATA_ORDER;
spim_iocb.set.param = SPI_MASTER_DATA_ORDER_MSB;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// enable DMA
spim_iocb.ioctl_code = VOS_IOCTL_COMMON_ENABLE_DMA;
spim_iocb.set = DMA_ACQUIRE_AND_RETAIN;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set clock rate
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SET_SCK_FREQUENCY;
spim_iocb.set.spi_master_sck_freq = 300000; // /10
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set auto toggle
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_AUTO_TOGGLE_SS;
spim_iocb.set.param = SPI_MASTER_SS_AUTO_TOGGLE_ENABLE_SS_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
#endif
message("Starting...\r\n");
#ifdef USE_SPI
message("With SPI...\r\n");
#endif
do
{
vos_delay_msecs(1000);
// check if USB port i is configured already
for (i = 0; i < 2; i++)
{
if (epCtrl[i] == NULL)
{
// user ioctl to see if selected USB port available
if (usbhost_connect_state(hUsb[i]) == PORT_STATE_ENUMERATED)
{
message("Enumeration complete Port ");
number(i);
message(eol);
if(i==0) leds = leds | LED1;
else leds = leds | LED2;
vos_gpio_write_port(GPIO_PORT_A, leds);

// user ioctl to find first hub device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_NEXT_HANDLE;
// find first device interface
hc_iocb.handle.dif = NULL;
// hc_iocb.set = &hc_ioctVidPid;
hc_iocb.get = &ifDev;
status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No Device Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find control endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_CONTROL_ENDPOINT_HANDLE;
hc_iocb.handle.dif = ifDev;
hc_iocb.get = &epCtrl[i];

status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No Control Endpoint Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find first interrupt endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_INT_IN_ENDPOINT_HANDLE;
hc_iocb.handle.dif = ifDev;
hc_iocb.get = &epInt[i];
status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No interrupt Endpoint Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find interrupt endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_ENDPOINT_INFO;
hc_iocb.handle.ep = epInt[i];
hc_iocb.get = &epInfo;

status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("Interrupt Endpoint Info Not Found - code ");
number(status);
message(eol);
break;
}

maxPack[i] = epInfo.max_size;

desc_dev.bmRequestType = USB_BMREQUESTTYPE_HOST_TO_DEV |
USB_BMREQUESTTYPE_CLASS |
USB_BMREQUESTTYPE_INTERFACE;
desc_dev.bRequest = 0x0a; // USB_HID_REQUEST_CODE_SET_IDLE
desc_dev.wValue = 0; // Repeat rate here
desc_dev.wIndex = 0;
desc_dev.wLength = 0;

hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_SETUP_TRANSFER;
hc_iocb.handle.ep = epCtrl[i];
hc_iocb.set = &desc_dev;

vos_dev_ioctl(hUsb[i], &hc_iocb);

message("Init complete Port ");
number(i);
message(eol);
flag = 1; // Signal to other thread
}
}
if (epCtrl[0] && epCtrl[1]) vos_signal_semaphore(&setupSem);
if ((epCtrl[0] || epCtrl[1]) && tick > 5) vos_signal_semaphore(&setupSem);
++tick;
}
}
while (1);
}


Title: Re: Adapting USBHostHID2 - Support one or two devices. Detect insertion.
Post by: AndersG on November 21, 2020, 02:36:49 PM
OK. I think I have it working now, but feedback is appreciated. I have one thread per port, plus the setup thread that runs once a second.

Code: [Select]
/*
** Filename: USBHostHID2.c
**
** Handle 1..2 USB HID devices, passing on keypresses and mouse movements
** over SPI as packets. Packet format is:
** 0x13
** Packet length, 8 or 4
** first byte, ms nibble
** first byte, ls nibble
** etc
** 0x14
**
**
** Links/doc:
** http://joshp.no-ip.com:8080/vnc2/#issue2
*/

#include "USBHostHID2.h"

/* FTDI:STP Thread Prototypes */
vos_tcb_t *tcbFIRMWARE;
vos_tcb_t *tcbSETUP;

void firmware0();
void firmware1();
void setup();
/* FTDI:ETP */

/* FTDI:SDH Driver Handles */
VOS_HANDLE hUSBHOST_1; // USB Host Port 1
VOS_HANDLE hUSBHOST_2; // USB Host Port 2
VOS_HANDLE hUART; // UART Interface Driver
#ifdef USE_SPI
VOS_HANDLE hSPI_MASTER; // SPIMaster Interface Driver
#endif
/* FTDI:EDH */
// use our own driver handles to simplify code later
VOS_HANDLE hUsb[2];
int tick = 0;
/* Declaration for IOMUx setup function */
void iomux_setup(void);
//--------------------------- GLOBALS -------------------
// test buffer
char buf[64];
char *eol = "\r\n";
char replybuf[64];

unsigned char i;
unsigned short len;
unsigned short written;
unsigned char status;
unsigned char n0, n1, m;
unsigned char ch;
unsigned int replylen;
// GPIO and LEDs
unsigned char leds;

// device handle
usbhost_device_handle_ex ifDev;
// endpoint handles
usbhost_ep_handle_ex epInt[2], epCtrl[2];
// endpoint maxPacketLength values
unsigned char maxPack[2];

// completion semaphore and set semaphore list
//vos_semaphore_t semRead; // not used?

// Host Controller ioctl request block
usbhost_ioctl_cb_t hc_iocb;
usbhost_ioctl_cb_vid_pid_t hc_ioctVidPid;

// interrupt endpoint transfer descriptors for port 0 and 1
usbhost_xfer_t xfer0;
usbhost_xfer_t xfer1;

// UART ioctl request block
common_ioctl_cb_t uart_iocb;
#ifdef USE_SPI
// SPI Master ioctl request block
common_ioctl_cb_t spim_iocb;
#endif

// host controller device descriptor
usb_deviceRequest_t desc_dev;

// endpoint information
usbhost_ioctl_cb_ep_info_t epInfo;
//
vos_semaphore_t setupSem0; // Shows that port is set up
vos_semaphore_t setupSem1;
vos_semaphore_t endpointSem0;
vos_semaphore_t endpointSem1;
// ---------------------------------------------------------

/* Main code - entry point to firmware */
void main(void)
{
// Driver Declarations
// UART Driver configuration context
uart_context_t uartContext;
// USB Host configuration context
usbhost_context_t usbhostContext;

#ifdef USE_SPI
// SPI Master configuration context
spimaster_context_t spimContext;
#endif
// Kernel Initialisation
vos_init(50, VOS_TICK_INTERVAL, VOS_NUMBER_DEVICES);
vos_set_clock_frequency(VOS_48MHZ_CLOCK_FREQUENCY);
vos_set_idle_thread_tcb_size(512);

iomux_setup();

// Driver Initialisation
// Initialise UART
#ifdef USE_UART
uartContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;
uart_init(VOS_DEV_UART,&uartContext);
#endif
//
// SPI
#ifdef USE_SPI
spimContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;
spimaster_init(VOS_DEV_SPI_MASTER,&spimContext);
#endif

// Initialise USB Host
usbhostContext.if_count = 8;
usbhostContext.ep_count = 16;
usbhostContext.xfer_count = 2;
usbhostContext.iso_xfer_count = 2;
usbhost_init(VOS_DEV_USBHOST_1, VOS_DEV_USBHOST_2, &usbhostContext);

vos_init_semaphore(&setupSem0, 0);
vos_init_semaphore(&setupSem1, 0);

// Thread Creation, setup and on thread per port
tcbFIRMWARE = vos_create_thread_ex(21, 2048, firmware0, "Port0", 0);
tcbFIRMWARE = vos_create_thread_ex(21, 2048, firmware1, "Port1", 0);
tcbFIRMWARE = vos_create_thread_ex(20, 4096, setup, "Setup", 0);
//
vos_gpio_set_port_mode(GPIO_PORT_A, 0xff);  // set all as output
//
vos_start_scheduler();

main_loop:
goto main_loop;
}

/* FTDI:SSP Support Functions */

unsigned char usbhost_connect_state(VOS_HANDLE hUSB)
{
unsigned char connectstate = PORT_STATE_DISCONNECTED;
usbhost_ioctl_cb_t hc_iocb;

if (hUSB)
{
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_GET_CONNECT_STATE;
hc_iocb.get        = &connectstate;
vos_dev_ioctl(hUSB, &hc_iocb);

    // repeat if connected to see if we move to enumerated
if (connectstate == PORT_STATE_CONNECTED)
{
vos_dev_ioctl(hUSB, &hc_iocb);
}
}
return connectstate;
}

/* FTDI:ESP */

void open_drivers(void)
{
// Code for opening and closing drivers - move to required places in Application Threads
hUSBHOST_1 = vos_dev_open(VOS_DEV_USBHOST_1);
hUSBHOST_2 = vos_dev_open(VOS_DEV_USBHOST_2);
#ifdef USE_UART
hUART = vos_dev_open(VOS_DEV_UART);
#endif
#ifdef USE_SPI
hSPI_MASTER = vos_dev_open(VOS_DEV_SPI_MASTER);
#endif
}

void attach_drivers(void)
{
/* FTDI:SUA Layered Driver Attach Function Calls */
/* FTDI:EUA */
}

void close_drivers(void)
{
// Driver Close
vos_dev_close(hUSBHOST_1);
vos_dev_close(hUSBHOST_2);
vos_dev_close(hUART);
#ifdef USE_SPI
vos_dev_close(hSPI_MASTER);
#endif
}

// Helpers

void message(char *msg)
{
#ifdef USE_UART
vos_dev_write(hUART, (unsigned char *) msg, strlen(msg), NULL);
#endif
}

void number(unsigned char val)
{
#ifdef USE_UART
char letter;
unsigned char nibble;

nibble = (val >> 4) + '0';

if (nibble > '9')
nibble += ('A' - '9' - 1);

vos_dev_write(hUART, &nibble, 1, NULL);
nibble = (val & 15) + '0';

if (nibble > '9')
nibble += ('A' - '9' - 1);

vos_dev_write(hUART, &nibble, 1, NULL);
#endif
}


//vos_semaphore_list_t *sem_list;        // pointer to semaphore list

//
// Thread for port 0
void firmware0(void)
{
unsigned char status0;
// Wait for the setup sem to finish...
vos_wait_semaphore(&setupSem0);
vos_delay_msecs(1000);
while(1)
{
if (epCtrl[0])
{
vos_init_semaphore(&endpointSem0,0);
n0 = -1;
memset(xfer0, 0, sizeof(xfer0));

xfer0.buf = buf;
xfer0.s = &endpointSem0;
xfer0.ep = epInt[0];
// Do not block on completion... we will wait on the sempaphore later
xfer0.flags = USBHOST_XFER_FLAG_NONBLOCKING | USBHOST_XFER_FLAG_ROUNDING;

while (1)
{
if (n0 != 1) // ie 0 or -1
{
xfer0.len = maxPack[0];
xfer0.cond_code = USBHOST_CC_NOTACCESSED;

status0 = vos_dev_read(hUsb[0], (unsigned char *) &xfer0, sizeof(usbhost_xfer_t), NULL);

if (status0 != USBHOST_OK)
{
message("Port 00 Read Failed - code ");
number(status0);
message(eol);
}
}

// Wait on a key press from  endpoint...
vos_wait_semaphore(&endpointSem0);
n0 = 0;

// Display data received
number(tick++);
message(" Port ");
number(n0);
message(" Data: ");

if (n0 == 0)
{
// sem1 has signalled
leds = leds | LED2;
vos_gpio_write_port(GPIO_PORT_A, leds);
replybuf[0] = 0x13;
replybuf[1] = (unsigned char)xfer0.len;
replylen = 2;
for (i = 0; i < xfer0.len; i++)
{
number(buf[i]);
ch = buf[i];
replybuf[replylen++] = (ch >> 4); // MSB
replybuf[replylen++] = (ch & 0x0f); // LSB
}
replybuf[replylen++] = 0x14;
#ifdef USE_SPI
vos_dev_write(hSPI_MASTER, (unsigned char *)replybuf, (uint16) replylen, NULL);
#endif
}
message(eol);
}
}
}
}

//
// Thread for port 1
void firmware1(void)
{
unsigned char status1;
// Wait for the setup sem to finish...
vos_wait_semaphore(&setupSem1);
vos_delay_msecs(1000);
while(1)
{
if (epCtrl[1])
{
vos_init_semaphore(&endpointSem1,0);
n1 = -1;
memset(xfer1, 0, sizeof(xfer1));

xfer1.buf = buf;
xfer1.s = &endpointSem1; //&endpointSem[1];
xfer1.ep = epInt[1];
//Do not block on completion... we will wait on the sempaphore later
xfer1.flags = USBHOST_XFER_FLAG_NONBLOCKING | USBHOST_XFER_FLAG_ROUNDING;

while (1)
{
if (n1 != 0) // ie 1 or -1
{
xfer1.len = maxPack[1];
xfer1.cond_code = USBHOST_CC_NOTACCESSED;

status1 = vos_dev_read(hUsb[1], (unsigned char *) &xfer1, sizeof(usbhost_xfer_t), NULL);

if (status1 != USBHOST_OK)
{
message("Port 01 Read Failed - code ");
number(status1);
message(eol);
//break;
}
}

// Wait on a key press from  endpoint...
vos_wait_semaphore(&endpointSem1);
n1 = 1;

// Display data received
number(tick++);
message(" Port ");
number(n1);
message(" Data: ");

if (n1 == 1)
{
// sem1 has signalled
leds = leds | LED3;
vos_gpio_write_port(GPIO_PORT_A, leds);
replybuf[0] = 0x13;
replybuf[1] = (unsigned char)xfer1.len;
replylen = 2;
for (i = 0; i < xfer1.len; i++)
{
number(buf[i]);
ch = buf[i];
replybuf[replylen++] = (ch >> 4); // MSB
replybuf[replylen++] = (ch & 0x0f); // LSB
}
replybuf[replylen++] = 0x14;
#ifdef USE_SPI
vos_dev_write(hSPI_MASTER, (unsigned char *)replybuf, (uint16) replylen, NULL);
#endif
}

message(eol);
}
}
}
}
// Setup thread, runs slowly and flags added devices through semaptĀ“hores
void setup(void)
{
int tick = 0;
int i = 0;
epInt[0] = NULL;
epCtrl[0] = NULL;
epInt[1] = NULL;
epCtrl[1] = NULL;

open_drivers();
hUsb[0] = hUSBHOST_1;
hUsb[1] = hUSBHOST_2;

#ifdef USE_UART
//uart_iocb.ioctl_code = VOS_IOCTL_COMMON_ENABLE_DMA;
//uart_iocb.set.param = DMA_ACQUIRE_AS_REQUIRED;
//vos_dev_ioctl(hUART, &uart_iocb);

// set baud rate
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_BAUD_RATE;
uart_iocb.set.uart_baud_rate = UART_BAUD_9600; //UART_BAUD_115200
vos_dev_ioctl(hUART, &uart_iocb);

// set flow control
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_FLOW_CONTROL;
uart_iocb.set.param = UART_FLOW_RTS_CTS;
vos_dev_ioctl(hUART, &uart_iocb);

// set data bits
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_DATA_BITS;
uart_iocb.set.param = UART_DATA_BITS_8;
vos_dev_ioctl(hUART, &uart_iocb);

// set stop bits
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_STOP_BITS;
uart_iocb.set.param = UART_STOP_BITS_1;
vos_dev_ioctl(hUART, &uart_iocb);

// set parity
uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_PARITY;
uart_iocb.set.param = UART_PARITY_NONE;
vos_dev_ioctl(hUART, &uart_iocb);
#endif
#ifdef USE_SPI
// set clock phase
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SCK_CPHA;
spim_iocb.set.param = SPI_MASTER_SCK_CPHA_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set clock polarity
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SCK_CPOL;
spim_iocb.set.param = SPI_MASTER_SCK_CPOL_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set data order
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_DATA_ORDER;
spim_iocb.set.param = SPI_MASTER_DATA_ORDER_MSB;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// enable DMA
spim_iocb.ioctl_code = VOS_IOCTL_COMMON_ENABLE_DMA;
spim_iocb.set = DMA_ACQUIRE_AND_RETAIN;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set clock rate
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_SET_SCK_FREQUENCY;
spim_iocb.set.spi_master_sck_freq = 300000; // /10
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
// set auto toggle
spim_iocb.ioctl_code = VOS_IOCTL_SPI_MASTER_AUTO_TOGGLE_SS;
spim_iocb.set.param = SPI_MASTER_SS_AUTO_TOGGLE_ENABLE_SS_0;
vos_dev_ioctl(hSPI_MASTER, &spim_iocb);
#endif
message("Starting...\r\n");
#ifdef USE_SPI
message("With SPI...\r\n");
//vos_dev_write(hSPI_MASTER, "With SPI...\r\n", 13, NULL);
#endif
do
{
vos_delay_msecs(1000);

// check if USB port i is configured already
for (i = 0; i < 2; i++)
{
if (epCtrl[i] == NULL)
{
// user ioctl to see if selected USB port available
if (usbhost_connect_state(hUsb[i]) == PORT_STATE_ENUMERATED)
{
message("Enumeration complete Port ");
number(i);
message(eol);
leds = leds | LED1;
vos_gpio_write_port(GPIO_PORT_A, leds);

// user ioctl to find first hub device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_NEXT_HANDLE;
// find first device interface
hc_iocb.handle.dif = NULL;
// hc_iocb.set = &hc_ioctVidPid;
hc_iocb.get = &ifDev;
status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No Device Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find control endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_CONTROL_ENDPOINT_HANDLE;
hc_iocb.handle.dif = ifDev;
hc_iocb.get = &epCtrl[i];

status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No Control Endpoint Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find first interrupt endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_INT_IN_ENDPOINT_HANDLE;
hc_iocb.handle.dif = ifDev;
hc_iocb.get = &epInt[i];
status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("No interrupt Endpoint Found - code ");
number(status);
message(eol);
break;
}

// user ioctl to find interrupt endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_ENDPOINT_INFO;
hc_iocb.handle.ep = epInt[i];
hc_iocb.get = &epInfo;

status = vos_dev_ioctl(hUsb[i], &hc_iocb);

if (status != USBHOST_OK)
{
message("Interrupt Endpoint Info Not Found - code ");
number(status);
message(eol);
break;
}

maxPack[i] = epInfo.max_size;

desc_dev.bmRequestType = USB_BMREQUESTTYPE_HOST_TO_DEV |
USB_BMREQUESTTYPE_CLASS |
USB_BMREQUESTTYPE_INTERFACE;
desc_dev.bRequest = 0x0a; // USB_HID_REQUEST_CODE_SET_IDLE
desc_dev.wValue = 0; // Repeat rate here
desc_dev.wIndex = 0;
desc_dev.wLength = 0;

hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_SETUP_TRANSFER;
hc_iocb.handle.ep = epCtrl[i];
hc_iocb.set = &desc_dev;

vos_dev_ioctl(hUsb[i], &hc_iocb);

message("Init complete Port ");
number(i);
message(eol);

}
}
// Signal semaphore is port is configured
if (epCtrl[1]) vos_signal_semaphore(&setupSem1);
if (epCtrl[0]) vos_signal_semaphore(&setupSem0);
++tick;
}
}
while (1);
}

Title: Re: Adapting USBHostHID2 - Support one or two devices. Detect insertion.
Post by: FTDI Community on November 23, 2020, 10:16:32 PM
Hello,

There was nothing wrong with what you are doing except reading from port 0 when there was no device there.

Best Regards,
FTDI Community