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.
/*
** 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);
}