Skip to content

[part. resolved] Arduino DUE: USBhost does not work with USB keyboard, no keyboard key press transmitted #3613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
shiftleftplusone opened this issue Aug 2, 2015 · 10 comments
Assignees
Labels
Type: Duplicate Another item already exists for this topic Type: Invalid Off topic for this repository, or a bug report determined to not actually represent a bug

Comments

@shiftleftplusone
Copy link

As I coudn't find USBhost-lib in 1.6.3, I just found the USBhost lib in IDE 1.6.1,
so I copied it into the Arduino 1.6.3 system libraries folder,
and now compiling 1.6.3 with this installed lib + DUE:

BUT:
no USB keyboard inputs are shown - why don't I get keyboard keys on Serial when I press a keyboard key?

(I just plugged a PC USB keyboard to the 2nd USB of the DUE )

Test sketch:

#include <KeyboardController.h>

// Initialize USB Controller
USBHost usb;

// Attach Keyboard controller to USB
KeyboardController keyboard(usb);



void setup(){
  Serial.begin(9600);
}

void loop(){
  usb.Task();
}

void keyPressed() {
  Serial.print("Pressed:  ");
  Serial.print(keyboard.getKey());
  Serial.println();
}

source reference: https://www.arduino.cc/en/Reference/KeyboardControllerConstructor

@shiftleftplusone
Copy link
Author

ps,
also this alternative code shows NOTHING on Serial, except "program started":

/*
 Keyboard Controller HID Example

 Shows the output of a USB Keyboard connected to the USB
 controller of an Arduino Due Board.

 created 8 Oct 2012
 by Cristian Maglie
 */

// Require keyboard control library
#include <KeyboardController.h>

// Initialize USB Controller
USBHost usb;

// Attach keyboard controller to USB
KeyboardController keyboard(usb);

// This function intercepts key press
void keyPressed() {
  Serial.print("Pressed:  ");
  printKey();
}

// This function intercepts key release
void keyReleased() {
  Serial.print("Released: ");
  printKey();
}

void printKey() {
  // getOemKey() returns the OEM-code associated with the key
  Serial.print(" key:");
  Serial.print(keyboard.getOemKey());

  // getModifiers() returns a bits field with the modifiers-keys
  int mod = keyboard.getModifiers();
  Serial.print(" mod:");
  Serial.print(mod);

  Serial.print(" => ");

  if (mod & LeftCtrl)
    Serial.print("L-Ctrl ");
  if (mod & LeftShift)
    Serial.print("L-Shift ");
  if (mod & Alt)
    Serial.print("Alt ");
  if (mod & LeftCmd)
    Serial.print("L-Cmd ");
  if (mod & RightCtrl)
    Serial.print("R-Ctrl ");
  if (mod & RightShift)
    Serial.print("R-Shift ");
  if (mod & AltGr)
    Serial.print("AltGr ");
  if (mod & RightCmd)
    Serial.print("R-Cmd ");

  // getKey() returns the ASCII translation of OEM key
  // combined with modifiers.
  Serial.write(keyboard.getKey());
  Serial.println();
}

void setup()
{
  Serial.begin(115200);
  Serial.println("Program started");
  delay(200);
}

void loop()
{
  // Process USB tasks
  usb.Task();
}

what's going on here ?????????

@JulyJim
Copy link

JulyJim commented Aug 2, 2015

If I recall correctly it did work only on mouse , for me , which does not help you.
The KEY is Task() which is does not return anything to loop().

You need to dig into "Task" and retrieve "USB status", it is there somewhere.
Task has two major if's() and those are relatively easy to trace.
I am currently not working on USB, but may get back to it soon.
Sorry I could not be more help.
Good luck.

@shiftleftplusone
Copy link
Author

hmmmmh...
[quote]The KEY is Task() which is does not return anything to loop(). [/quote]

this actually really sounds like a very very clever programmed source :-D
Amazing, that no one but me did run into issues or at least caused rapid bug fixes so far since 2011.... :-/

As I have really no clue of C++ ...
what do you mean, where should I start to search...?
USBhost.cpp

/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.

This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").

Contact information
-------------------

Circuits At Home, LTD
Web      :  http://www.circuitsathome.com
e-mail   :  support@circuitsathome.com
*/

/* USB functions */

#include "Arduino.h"
#include "Usb.h"
#include <stdio.h>

static uint32_t usb_error = 0;
static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;

/**
 * \brief USBHost class constructor.
 */
USBHost::USBHost() : bmHubPre(0)
{
    // Set up state machine
    usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;

    // Init host stack
    init();
}

/**
 * \brief Initialize USBHost class.
 */
void USBHost::init()
{
    devConfigIndex  = 0;
    bmHubPre        = 0;
}


/**
 * \brief Get USBHost state.
 *
 * \return USB enumeration status (see USBHost::task).
 */
uint32_t USBHost::getUsbTaskState(void)
{
    return (usb_task_state);
}

/**
 * \brief Set USB state.
 *
 * \param state New USBHost status to be set.
 */
void USBHost::setUsbTaskState(uint32_t state)
{
    usb_task_state = state;
}

/**
 * \brief Get endpoint info from USB device address and device endpoint.
 *
 * \note This function should be used to know which host pipe is being used for
 * the corresponding device endpoint.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 *
 * \return Pointer to an EpInfo structure.
 */
EpInfo* USBHost::getEpInfoEntry(uint32_t addr, uint32_t ep)
{
    UsbDevice *p = addrPool.GetUsbDevicePtr(addr);

    if (!p || !p->epinfo)
        return NULL;

    EpInfo *pep = p->epinfo;

    for (uint32_t i = 0; i < p->epcount; i++)
    {
        if (pep->deviceEpNum == ep)
            return pep;

        pep++;
    }

    return NULL;
}

/**
 * \brief Set device endpoint entry.
 *
 * \note Each device is different and has a different number of endpoints.
 * This function sets endpoint record structure to the device using address
 * addr in the address pool.
 *
 * \param ul_pipe Pipe address.
 * \param ul_token_type Token type.
 *
 * \retval 0 on success.
 * \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found.
 */
uint32_t USBHost::setEpInfoEntry(uint32_t addr, uint32_t epcount, EpInfo* eprecord_ptr)
{
    if (!eprecord_ptr)
        return USB_ERROR_INVALID_ARGUMENT;

    UsbDevice *p = addrPool.GetUsbDevicePtr(addr);

    if (!p)
        return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

    p->address  = addr;
    p->epinfo   = eprecord_ptr;
    p->epcount  = epcount;

    return 0;
}

/**
 * \brief Set host pipe target address and set ppep pointer to the endpoint
 * structure matching the specified USB device address and endpoint.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param ppep Endpoint info structure pointer set by setPipeAddress.
 * \param nak_limit Maximum number of NAK permitted.
 *
 * \retval 0 on success.
 * \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found.
 * \retval USB_ERROR_EPINFO_IS_NULL no endpoint structure found for this device.
 * \retval USB_ERROR_EP_NOT_FOUND_IN_TBL the specified device endpoint cannot be found.
 */
uint32_t USBHost::setPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit)
{
    UsbDevice *p = addrPool.GetUsbDevicePtr(addr);

    if (!p)
        return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

    if (!p->epinfo)
        return USB_ERROR_EPINFO_IS_NULL;

    *ppep = getEpInfoEntry(addr, ep);

    if (!*ppep)
        return USB_ERROR_EP_NOT_FOUND_IN_TBL;

    nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
    nak_limit--;

    // Set peripheral address
    TRACE_USBHOST(printf("     => SetAddress deviceEP=%lu configued as hostPIPE=%lu sending to address=%lu\r\n", ep, (*ppep)->hostPipeNum, addr);)
    uhd_configure_address((*ppep)->hostPipeNum, addr);

    return 0;
}

/**
 * \brief Send a control request.
 * Sets address, endpoint, fills control packet with necessary data, dispatches
 * control packet, and initiates bulk IN transfer depending on request.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param bmReqType Request direction.
 * \param bRequest Request type.
 * \param wValLo Value low.
 * \param wValHi Value high.
 * \param wInd Index field.
 * \param total Request length.
 * \param nbytes Number of bytes to read.
 * \param dataptr Data pointer.
 * \param p USB class reader.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint32_t nbytes, uint8_t* dataptr, USBReadParser *p)
{
    // Request direction, IN or OUT
    uint32_t direction = 0;
    uint32_t rcode = 0;
    SETUP_PKT setup_pkt;

    EpInfo *pep = 0;
    uint32_t nak_limit;

    TRACE_USBHOST(printf("    => ctrlReq\r\n");)

    // Set peripheral address
    rcode = setPipeAddress(addr, ep, &pep, nak_limit);
    if (rcode)
        return rcode;

    // Allocate Pipe0 with default 64 bytes size if not already initialized
    // TODO : perform a get device descriptor first to get device endpoint size (else data can be missed if device ep0 > host pipe0)
    rcode = UHD_Pipe0_Alloc(0, 64);
    if (rcode)
    {
        TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", rcode);)
        return (rcode);
    }

    // Determine request direction
    direction = ((bmReqType & 0x80 ) > 0);

    // Fill in setup packet
    setup_pkt.ReqType_u.bmRequestType   = bmReqType;
    setup_pkt.bRequest                  = bRequest;
    setup_pkt.wVal_u.wValueLo           = wValLo;
    setup_pkt.wVal_u.wValueHi           = wValHi;
    setup_pkt.wIndex                    = wInd;
    setup_pkt.wLength                   = total;

    // Configure and write the setup packet into the FIFO
    uhd_configure_pipe_token(0, tokSETUP);
    UHD_Pipe_Write(pep->hostPipeNum, 8, (uint8_t *)&setup_pkt);

    // Dispatch packet
    rcode = dispatchPkt(tokSETUP, pep->hostPipeNum, nak_limit);
    if (rcode)
    {
        // Return HRSLT if not zero
        TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : Setup packet error: %lu\r\n", rcode);)
        return (rcode);
    }

    // Data stage (if present)
    if (dataptr != 0)
    {
        if (direction)
        {
            // IN transfer
            TRACE_USBHOST(printf("    => ctrlData IN\r\n");)
            uint32_t left = total;

            while (left)
            {
                // Bytes read into buffer
                uint32_t read = nbytes;

                rcode = InTransfer(pep, nak_limit, &read, dataptr);
                if (rcode)
                    return rcode;

                // Invoke callback function if inTransfer completed successfuly and callback function pointer is specified
                if (!rcode && p)
                    ((USBReadParser*)p)->Parse(read, dataptr, total - left);

                left -= read;

                if (read < nbytes)
                    break;
            }
        }
        else
        {
            // OUT transfer
            TRACE_USBHOST(printf("    => ctrlData OUT\r\n");)
            rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
        }

        if (rcode)
        {
            TRACE_USBHOST(printf("/!\\ USBHost::ctrlData : Data packet error: %lu\r\n", rcode);)
            return (rcode);
        }
    }

    // Status stage
    return dispatchPkt((direction) ? tokOUTHS : tokINHS, pep->hostPipeNum, nak_limit);
}

/**
 * \brief Perform IN request to the specified USB device.
 *
 * \note This function handles multiple packets (if necessary) and can
 * receive a maximum of 'nbytesptr' bytes. It keep sending INs and writes data
 * to memory area pointed by 'data'. The actual amount of received bytes is
 * stored in 'nbytesptr'.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param nbytesptr Receive buffer size. It is set to the amount of received
 * bytes when the function returns.
 * \param data Buffer to store received data.
 *
 * \return 0 on success, error code otherwise.
 */
 uint32_t USBHost::inTransfer(uint32_t addr, uint32_t ep, uint32_t *nbytesptr, uint8_t* data)
{
    EpInfo *pep = NULL;
    uint32_t nak_limit = 0;

    uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit);

    if (rcode)
    {
        return rcode;
    }

    return InTransfer(pep, nak_limit, nbytesptr, data);
}

uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytesptr, uint8_t* data)
{
    uint32_t rcode = 0;
    uint32_t pktsize = 0;
    uint32_t nbytes = *nbytesptr;
    uint32_t maxpktsize = pep->maxPktSize;

    *nbytesptr = 0;

    while (1)
    {
        // Use a 'return' to exit this loop
        // IN packet to EP-'endpoint'. Function takes care of NAKS.
        rcode = dispatchPkt(tokIN, pep->hostPipeNum, nak_limit);
        if (rcode)
        {
            if (rcode == 1)
            {
                // Pipe freeze is mandatory to avoid sending IN endlessly (else reception becomes messy then)
                uhd_freeze_pipe(pep->hostPipeNum);
            }
            // Should be 1, indicating NAK. Else return error code.
            return rcode;
        }

        // Number of received bytes
        pktsize = uhd_byte_count(pep->hostPipeNum);
        if (nbytes < pktsize)
        {
            TRACE_USBHOST(printf("/!\\ USBHost::InTransfer : receive buffer is too small, size=%lu, expected=%lu\r\n", nbytes, pktsize);)
        }
        data += UHD_Pipe_Read(pep->hostPipeNum, pktsize, data);

        // Add this packet's byte count to total transfer length
        *nbytesptr += pktsize;

        // The transfer is complete under two conditions:
        // 1. The device sent a short packet (L.T. maxPacketSize)
        // 2. 'nbytes' have been transferred.
        if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes))
        {
            return 0;
        }
    }
}

/**
 * \brief Perform OUT request to the specified USB device.
 *
 * \note This function handles multiple packets (if necessary) and sends
 * 'nbytes' bytes.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param nbytes Buffer size to be sent.
 * \param data Buffer to send.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data)
{
    EpInfo *pep = NULL;
    uint32_t nak_limit = 0;

    uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit);

    if (rcode)
    {
        return rcode;
    }

    return OutTransfer(pep, nak_limit, nbytes, data);
}

uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data)
{
    uint32_t rcode = 0;
    uint32_t bytes_tosend = 0;
    uint32_t bytes_left = nbytes;
    uint32_t maxpktsize = pep->maxPktSize;

    if (maxpktsize < 1)
        return USB_ERROR_INVALID_MAX_PKT_SIZE;

    while (bytes_left)
    {
        bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;

        // Write FIFO
        UHD_Pipe_Write(pep->hostPipeNum, bytes_tosend, data);

        // Use a 'return' to exit this loop
        // OUT packet to EP-'endpoint'. Function takes care of NAKS.
        rcode = dispatchPkt(tokOUT, pep->hostPipeNum, nak_limit);
        if (rcode)
        {
            // Should be 0, indicating ACK. Else return error code.
            return rcode;
        }

        bytes_left -= bytes_tosend;
        data += bytes_tosend;
    }

    // Should be 0 in all cases
    return rcode;
}

/**
 * \brief Dispatch USB packet.
 *
 * \note Ensure peripheral address is set and relevant buffer is loaded/empty.
 * If NAK, tries to re-send up to nak_limit times.
 * If nak_limit == 0, do not count NAKs, exit after timeout.
 *
 * \param token Token type (Setup, In or Out).
 * \param hostPipeNum Host pipe number to use for sending USB packet.
 * \param nak_limit Maximum number of NAK permitted.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t hostPipeNum, uint32_t nak_limit)
{
    uint32_t timeout = millis() + USB_XFER_TIMEOUT;
    uint32_t nak_count = 0;
    uint32_t rcode = USB_ERROR_TRANSFER_TIMEOUT;

    TRACE_USBHOST(printf("     => dispatchPkt token=%lu pipe=%lu nak_limit=%lu\r\n", token, hostPipeNum, nak_limit);)

    // Launch the transfer
    UHD_Pipe_Send(hostPipeNum, token);

    // Check timeout but don't hold timeout if VBUS is lost
    while ((timeout > millis()) && (UHD_GetVBUSState() == UHD_STATE_CONNECTED))
    {
        // Wait for transfer completion
        if (UHD_Pipe_Is_Transfer_Complete(hostPipeNum, token))
        {
            return 0;
        }

        // Is NAK received?
        if (Is_uhd_nak_received(hostPipeNum))
        {
            uhd_ack_nak_received(hostPipeNum);
            nak_count++;

            if (nak_limit && (nak_count == nak_limit))
            {
                // Return NAK
                return 1;
            }
        }
    }

    return rcode;
}

/**
 * \brief Configure device using known device classes.
 * The device get a new address even if its class remain unknown.
 *
 * \param parent USB device address of the device's parent (0 if root).
 * \param port USB device base address (see AddressPoolImpl).
 * \param lowspeed Device speed.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
{
    uint32_t rcode = 0;

    for (; devConfigIndex < USB_NUMDEVICES; ++devConfigIndex)
    {
        if (!devConfig[devConfigIndex])
            continue;

        rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);

        if (!rcode)
        {
            TRACE_USBHOST(printf("USBHost::Configuring : found device class!\r\n");)
            devConfigIndex = 0;
            return 0;
        }


        if (rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
        {
            TRACE_USBHOST(printf("USBHost::Configuring : ERROR : device not supported!\r\n");)
        }
        else if (rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)
        {
            TRACE_USBHOST(printf("USBHost::Configuring : ERROR : class instance already in use!\r\n");)
        }
        else
        {
            // in case of an error devConfigIndex should be reset to 0
            // in order to start from the very beginning the next time
            // the program gets here
            if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
                devConfigIndex = 0;

            return rcode;
        }
    }

    // Device class is not supported by any of the registered classes
    devConfigIndex = 0;

    rcode = DefaultAddressing(parent, port, lowspeed);

    return rcode;
}

/**
 * \brief Configure device with unknown USB class.
 *
 * \param parent USB device address of the device's parent (0 if root).
 * \param port USB device base address (see AddressPoolImpl).
 * \param lowspeed Device speed.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t lowspeed)
{
    uint32_t rcode = 0;
    UsbDevice *p0 = 0, *p = 0;

    // Get pointer to pseudo device with address 0 assigned
    p0 = addrPool.GetUsbDevicePtr(0);

    if (!p0)
        return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

    if (!p0->epinfo)
        return USB_ERROR_EPINFO_IS_NULL;

    p0->lowspeed = (lowspeed) ? 1 : 0;

    // Allocate new address according to device class
    uint32_t bAddress = addrPool.AllocAddress(parent, 0, port);

    if (!bAddress)
        return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;

    p = addrPool.GetUsbDevicePtr(bAddress);

    if (!p)
        return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

    p->lowspeed = lowspeed;

    // Assign new address to the device
    rcode = setAddr(0, 0, bAddress);

    if (rcode)
    {
        TRACE_USBHOST(printf("/!\\ USBHost::DefaultAddressing : Set address failed with code: %lu\r\n", rcode);)
        addrPool.FreeAddress(bAddress);
        bAddress = 0;
        return rcode;
    }

    return 0;
}

/**
 * \brief Release device and free associated resources.
 *
 * \param addr USB device address.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::ReleaseDevice(uint32_t addr)
{
    if (!addr)
        return 0;

    for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
    {
        if (devConfig[i]->GetAddress() == addr)
        {
            return devConfig[i]->Release();
        }
    }

    return 0;
}

/**
 * \brief Get device descriptor.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param nbytes Buffer size.
 * \param dataptr Buffer to store received descriptor.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr)
{
    return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, 0));
}

/**
 * \brief Get configuration descriptor.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param nbytes Buffer size.
 * \param conf Configuration number.
 * \param dataptr Buffer to store received descriptor.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint32_t conf, uint8_t* dataptr)
{
    return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, 0));
}

/**
 * \brief Get configuration descriptor and extract endpoints using USBReadParser object.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param conf Configuration number.
 * \param p USBReadParser object pointer used to extract endpoints.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p)
{
    const uint32_t bufSize = 64;
    uint8_t buf[bufSize];

    uint32_t ret = getConfDescr(addr, ep, 8, conf, buf);

    if (ret)
        return ret;

    uint32_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
    delay(100);

    return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
}

/**
 * \brief Get string descriptor.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param nbytes Buffer size.
 * \param index String index.
 * \param langid Language ID.
 * \param dataptr Buffer to store received descriptor.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr)
{
    return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, nbytes, dataptr, 0));
}

/**
 * \brief Set USB device address.
 *
 * \param oldaddr Current USB device address.
 * \param ep USB device endpoint number.
 * \param addr New USB device address to be set.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr)
{
    TRACE_USBHOST(printf("   => USBHost::setAddr\r\n");)
    return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, 0, 0);
}

/**
 * \brief Set configuration.
 *
 * \param addr USB device address.
 * \param ep USB device endpoint number.
 * \param conf_value New configuration value to be set.
 *
 * \return 0 on success, error code otherwise.
 */
uint32_t USBHost::setConf(uint32_t addr, uint32_t ep, uint32_t conf_value)
{
    return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, 0, 0));
}

/**
 * \brief USB main task, responsible for enumeration and clean up stage.
 *
 * \note Must be periodically called from loop().
 */
void USBHost::Task(void)
{
    uint32_t rcode = 0;
    volatile uint32_t tmpdata = 0;
    static uint32_t delay = 0;
    uint32_t lowspeed = 0;

    // Update USB task state on Vbus change
    tmpdata = UHD_GetVBUSState();
    switch (tmpdata)
    {
        case UHD_STATE_ERROR:
            // Illegal state
            usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
            lowspeed = 0;
            break;

        case UHD_STATE_DISCONNECTED:
            // Disconnected state
            if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
            {
                usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
                lowspeed = 0;
            }
            break;

        case UHD_STATE_CONNECTED:
            // Attached state
            if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED)
            {
                delay = millis() + USB_SETTLE_DELAY;
                usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
                //FIXME TODO: lowspeed = 0 ou 1;  already done by hardware?
            }
            break;
    }

    // Poll connected devices (if required)
    for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
        if (devConfig[i])
            rcode = devConfig[i]->Poll();

    // Perform USB enumeration stage and clean up
    switch (usb_task_state)
    {
        case USB_DETACHED_SUBSTATE_INITIALIZE:
            TRACE_USBHOST(printf(" + USB_DETACHED_SUBSTATE_INITIALIZE\r\n");)

            // Init USB stack and driver
            UHD_Init();
            init();

            // Free all USB resources
            for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
                if (devConfig[i])
                    rcode = devConfig[i]->Release();

            usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
            break;

        case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:
            // Nothing to do
            break;

        case USB_DETACHED_SUBSTATE_ILLEGAL:
            // Nothing to do
            break;

        case USB_ATTACHED_SUBSTATE_SETTLE:
            // Settle time for just attached device
            if (delay < millis())
            {
                TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_SETTLE\r\n");)
                usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
            }
            break;

        case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
            TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_RESET_DEVICE\r\n");)

            // Trigger Bus Reset
            UHD_BusReset();
            usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
            break;

        case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
            if (Is_uhd_reset_sent())
            {
                TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE\r\n");)

                // Clear Bus Reset flag
                uhd_ack_reset_sent();

                // Enable Start Of Frame generation
                uhd_enable_sof();

                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;

                // Wait 20ms after Bus Reset (USB spec)
                delay = millis() + 20;
            }
            break;

        case USB_ATTACHED_SUBSTATE_WAIT_SOF:
            // Wait for SOF received first
            if (Is_uhd_sof())
            {
                if (delay < millis())
                {
                    TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_WAIT_SOF\r\n");)

                    // 20ms waiting elapsed
                    usb_task_state = USB_STATE_CONFIGURING;
                }
            }
            break;

        case USB_STATE_CONFIGURING:
            TRACE_USBHOST(printf(" + USB_STATE_CONFIGURING\r\n");)
            rcode = Configuring(0, 0, lowspeed);

            if (rcode)
            {
                TRACE_USBHOST(printf("/!\\ USBHost::Task : USB_STATE_CONFIGURING failed with code: %lu\r\n", rcode);)
                if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
                {
                    usb_error = rcode;
                    usb_task_state = USB_STATE_ERROR;
                }
            }
            else
            {
                usb_task_state = USB_STATE_RUNNING;
                TRACE_USBHOST(printf(" + USB_STATE_RUNNING\r\n");)
            }
            break;

        case USB_STATE_RUNNING:
            break;

        case USB_STATE_ERROR:
            break;
    }
}

@shiftleftplusone shiftleftplusone changed the title IDE 1.6.1 + DUE: USBhost does not work with USB keyboard, no keyboard key press transmitted Arduino DUE: USBhost does not work with USB keyboard, no keyboard key press transmitted Aug 3, 2015
@JulyJim
Copy link

JulyJim commented Aug 4, 2015

"As I have really no clue of C++ ."
Than be ready to receive many advices in line "USB is very complicated..."
I am really not sure how I can help you ii it (keyboard) does not work for you and same time you feel it (USBHost) is a good program.
And the reasons nobody else said anything about USB (keyboard) not working is because there is no interest in Arduino circles.

@shiftleftplusone
Copy link
Author

I have no idea if USB host is a good program as I haven't tried it yet.
I simply want to read the keyboard just like I'm able to do it when a keyboard is plugged to my PC or to a RaspPi, actually that's all about it and that's the simple functionality which is is required. The DUE provides a USB host port, so it should work like a USB host port is supposed to do.

@shiftleftplusone shiftleftplusone changed the title Arduino DUE: USBhost does not work with USB keyboard, no keyboard key press transmitted [part. resolved] Arduino DUE: USBhost does not work with USB keyboard, no keyboard key press transmitted Aug 4, 2015
@shiftleftplusone
Copy link
Author

at
https://github.com/arduino-libraries
a USBhst version is thankfully provided which works and returns keystrokes!
there are some issues though

(RIGHT-SHIFT + characters => not uppercase, 
Backslash not printed, 
OR operator | not printed, but [] (key left hand of z) or ~ (key right hand of ,) instead )

@shiftleftplusone
Copy link
Author

as now discovered after some first attempts, there are different other issues about the current USBhost lib mentioned in this thread:
#3630

@shiftleftplusone
Copy link
Author

When can we expect an improvement in the Keyboard functions, like e.g.
kbhit()
getch()
getche()
getchar()
gets()
scanf()

?

@shiftleftplusone
Copy link
Author

bump!
when will there be an update for reasonable keyboard stdin C functionality?

@per1234
Copy link
Collaborator

per1234 commented Jul 3, 2017

The remaining unsolved portion of this issue is a duplicate of #3630

@per1234 per1234 closed this as completed Jul 3, 2017
@per1234 per1234 added Type: Duplicate Another item already exists for this topic Type: Invalid Off topic for this repository, or a bug report determined to not actually represent a bug labels Jul 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Duplicate Another item already exists for this topic Type: Invalid Off topic for this repository, or a bug report determined to not actually represent a bug
Projects
None yet
Development

No branches or pull requests

4 participants