Library to use Arduino USB host shield on mbed
ArduinoのUSB Host Shield 2.0をmbedで使えるようにしたライブラリです。
大体のコードがArduinoからそのまま移植可能です。
Arduino UNOやMega用のホストシールド以外にもミニサイズのホストシールドでも使用可能です
シールドについて
3.3VのI/O用にシールドの改造が必要になりますがネット上に記事がたくさんあるのでそちらを参考にしてください
接続例
使い方
Arduinoのコードと違うのはUSBのインスタンスの宣言部分のみです。
ピンを自分で指定できるようにしたので使いやすくなりました。
仕様
- Arduinoのmillis関数、micros関数の移植のために内部でTimerクラスを使用しています。
main.cpp
#include "mbed.h" #include <PS3BT.h> #include <usbhub.h> Serial pc(USBTX, USBRX, 115200); //Nucleo f303k8用 USB Usb(A6, A5, A4, A3, A2); // mosi, miso, sclk, ssel, intr BTD Btd(&Usb); PS3BT PS3(&Btd); int main() { bool printAngle = false; if (Usb.Init() == -1) { pc.printf("\r\nOSC did not start"); while (1); // Halt } pc.printf("\r\nPS3 USB Library Started"); while (1) { Usb.Task(); if (PS3.PS3Connected || PS3.PS3NavigationConnected) { if (PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117 || PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117 || PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117 || PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117) { pc.printf("\r\nLeftHatX: %d", PS3.getAnalogHat(LeftHatX)); pc.printf("\tLeftHatY: %d", PS3.getAnalogHat(LeftHatY)); if (PS3.PS3Connected) { // The Navigation controller only have one joystick pc.printf("\tRightHatX: %d", PS3.getAnalogHat(RightHatX)); pc.printf("\tRightHatY: %d", PS3.getAnalogHat(RightHatY)); } } // Analog button values can be read from almost all buttons if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2)) { pc.printf("\r\nL2: %d", PS3.getAnalogButton(L2)); if (!PS3.PS3NavigationConnected) { pc.printf("\tR2: %d", PS3.getAnalogButton(R2)); } } if (PS3.getButtonClick(PS)) { PS3.disconnect(); pc.printf("\r\nPS"); } if (PS3.getButtonClick(TRIANGLE)) pc.printf("\r\nTriangle"); if (PS3.getButtonClick(CIRCLE)) pc.printf("\r\nCircle"); if (PS3.getButtonClick(CROSS)) pc.printf("\r\nCross"); if (PS3.getButtonClick(SQUARE)) pc.printf("\r\nSquare"); if (PS3.getButtonClick(UP)) { pc.printf("\r\nUp"); PS3.setLedOff(); PS3.setLedOn(CONTROLLER_LED4); } if (PS3.getButtonClick(RIGHT)) { pc.printf("\r\nRight"); PS3.setLedOff(); PS3.setLedOn(CONTROLLER_LED1); } if (PS3.getButtonClick(DOWN)) { pc.printf("\r\nDown"); PS3.setLedOff(); PS3.setLedOn(CONTROLLER_LED2); } if (PS3.getButtonClick(LEFT)) { pc.printf("\r\nLeft"); PS3.setLedOff(); PS3.setLedOn(CONTROLLER_LED3); } if (PS3.getButtonClick(L1)) pc.printf("\r\nL1"); if (PS3.getButtonClick(L3)) pc.printf("\r\nL3"); if (PS3.getButtonClick(R1)) pc.printf("\r\nR1"); if (PS3.getButtonClick(R3)) pc.printf("\r\nR3"); if (PS3.getButtonClick(SELECT)) { pc.printf("\r\nSelect - "); PS3.printStatusString(); } if (PS3.getButtonClick(START)) { pc.printf("\r\nStart"); printAngle = !printAngle; } if (printAngle) { pc.printf("\r\nPitch: %.3lf", PS3.getAngle(Pitch)); pc.printf("\tRoll: %.3lf", PS3.getAngle(Roll)); } } else { pc.printf("not connect\n"); } } }
USB_Host/Usb.cpp@1:da31140f2a1c, 2020-05-02 (annotated)
- Committer:
- robo_ichinoseki_a
- Date:
- Sat May 02 05:56:48 2020 +0000
- Revision:
- 1:da31140f2a1c
- Parent:
- 0:b1ce54272580
update
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kotakku | 0:b1ce54272580 | 1 | /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. |
kotakku | 0:b1ce54272580 | 2 | |
kotakku | 0:b1ce54272580 | 3 | This software may be distributed and modified under the terms of the GNU |
kotakku | 0:b1ce54272580 | 4 | General Public License version 2 (GPL2) as published by the Free Software |
kotakku | 0:b1ce54272580 | 5 | Foundation and appearing in the file GPL2.TXT included in the packaging of |
kotakku | 0:b1ce54272580 | 6 | this file. Please note that GPL2 Section 2[b] requires that all works based |
kotakku | 0:b1ce54272580 | 7 | on this software must also be made publicly available under the terms of |
kotakku | 0:b1ce54272580 | 8 | the GPL2 ("Copyleft"). |
kotakku | 0:b1ce54272580 | 9 | |
kotakku | 0:b1ce54272580 | 10 | Contact information |
kotakku | 0:b1ce54272580 | 11 | ------------------- |
kotakku | 0:b1ce54272580 | 12 | |
kotakku | 0:b1ce54272580 | 13 | Circuits At Home, LTD |
kotakku | 0:b1ce54272580 | 14 | Web : http://www.circuitsathome.com |
kotakku | 0:b1ce54272580 | 15 | e-mail : support@circuitsathome.com |
kotakku | 0:b1ce54272580 | 16 | */ |
kotakku | 0:b1ce54272580 | 17 | /* USB functions */ |
kotakku | 0:b1ce54272580 | 18 | |
kotakku | 0:b1ce54272580 | 19 | // warning |
kotakku | 0:b1ce54272580 | 20 | // #define _usb_h_ |
kotakku | 0:b1ce54272580 | 21 | // #define MBED_H |
kotakku | 0:b1ce54272580 | 22 | |
kotakku | 0:b1ce54272580 | 23 | #include "Usb.h" |
kotakku | 0:b1ce54272580 | 24 | |
robo_ichinoseki_a | 1:da31140f2a1c | 25 | Timer USB::arduinoTimer; |
robo_ichinoseki_a | 1:da31140f2a1c | 26 | |
kotakku | 0:b1ce54272580 | 27 | static uint8_t usb_error = 0; |
kotakku | 0:b1ce54272580 | 28 | static uint8_t usb_task_state; |
kotakku | 0:b1ce54272580 | 29 | |
kotakku | 0:b1ce54272580 | 30 | /* constructor */ |
kotakku | 0:b1ce54272580 | 31 | USB::USB(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName intr) : |
kotakku | 0:b1ce54272580 | 32 | MAX3421E(mosi, miso, sclk, ssel, intr), |
kotakku | 0:b1ce54272580 | 33 | bmHubPre(0) |
kotakku | 0:b1ce54272580 | 34 | { |
kotakku | 0:b1ce54272580 | 35 | arduinoTimer.start(); |
kotakku | 0:b1ce54272580 | 36 | usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine |
kotakku | 0:b1ce54272580 | 37 | init(); |
kotakku | 0:b1ce54272580 | 38 | } |
kotakku | 0:b1ce54272580 | 39 | |
kotakku | 0:b1ce54272580 | 40 | |
kotakku | 0:b1ce54272580 | 41 | /* Initialize data structures */ |
kotakku | 0:b1ce54272580 | 42 | void USB::init() |
kotakku | 0:b1ce54272580 | 43 | { |
kotakku | 0:b1ce54272580 | 44 | //devConfigIndex = 0; |
kotakku | 0:b1ce54272580 | 45 | bmHubPre = 0; |
kotakku | 0:b1ce54272580 | 46 | } |
kotakku | 0:b1ce54272580 | 47 | |
kotakku | 0:b1ce54272580 | 48 | uint8_t USB::getUsbTaskState(void) |
kotakku | 0:b1ce54272580 | 49 | { |
kotakku | 0:b1ce54272580 | 50 | return (usb_task_state); |
kotakku | 0:b1ce54272580 | 51 | } |
kotakku | 0:b1ce54272580 | 52 | |
kotakku | 0:b1ce54272580 | 53 | void USB::setUsbTaskState(uint8_t state) |
kotakku | 0:b1ce54272580 | 54 | { |
kotakku | 0:b1ce54272580 | 55 | usb_task_state = state; |
kotakku | 0:b1ce54272580 | 56 | } |
kotakku | 0:b1ce54272580 | 57 | |
kotakku | 0:b1ce54272580 | 58 | EpInfo *USB::getEpInfoEntry(uint8_t addr, uint8_t ep) |
kotakku | 0:b1ce54272580 | 59 | { |
kotakku | 0:b1ce54272580 | 60 | UsbDevice *p = addrPool.GetUsbDevicePtr(addr); |
kotakku | 0:b1ce54272580 | 61 | |
kotakku | 0:b1ce54272580 | 62 | if (!p || !p->epinfo) |
kotakku | 0:b1ce54272580 | 63 | return NULL; |
kotakku | 0:b1ce54272580 | 64 | |
kotakku | 0:b1ce54272580 | 65 | EpInfo *pep = p->epinfo; |
kotakku | 0:b1ce54272580 | 66 | |
kotakku | 0:b1ce54272580 | 67 | for (uint8_t i = 0; i < p->epcount; i++) |
kotakku | 0:b1ce54272580 | 68 | { |
kotakku | 0:b1ce54272580 | 69 | if ((pep)->epAddr == ep) |
kotakku | 0:b1ce54272580 | 70 | return pep; |
kotakku | 0:b1ce54272580 | 71 | |
kotakku | 0:b1ce54272580 | 72 | pep++; |
kotakku | 0:b1ce54272580 | 73 | } |
kotakku | 0:b1ce54272580 | 74 | return NULL; |
kotakku | 0:b1ce54272580 | 75 | } |
kotakku | 0:b1ce54272580 | 76 | |
kotakku | 0:b1ce54272580 | 77 | /* set device table entry */ |
kotakku | 0:b1ce54272580 | 78 | |
kotakku | 0:b1ce54272580 | 79 | /* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */ |
kotakku | 0:b1ce54272580 | 80 | uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr) |
kotakku | 0:b1ce54272580 | 81 | { |
kotakku | 0:b1ce54272580 | 82 | if (!eprecord_ptr) |
kotakku | 0:b1ce54272580 | 83 | return USB_ERROR_INVALID_ARGUMENT; |
kotakku | 0:b1ce54272580 | 84 | |
kotakku | 0:b1ce54272580 | 85 | UsbDevice *p = addrPool.GetUsbDevicePtr(addr); |
kotakku | 0:b1ce54272580 | 86 | |
kotakku | 0:b1ce54272580 | 87 | if (!p) |
kotakku | 0:b1ce54272580 | 88 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 89 | |
kotakku | 0:b1ce54272580 | 90 | p->address.devAddress = addr; |
kotakku | 0:b1ce54272580 | 91 | p->epinfo = eprecord_ptr; |
kotakku | 0:b1ce54272580 | 92 | p->epcount = epcount; |
kotakku | 0:b1ce54272580 | 93 | |
kotakku | 0:b1ce54272580 | 94 | return 0; |
kotakku | 0:b1ce54272580 | 95 | } |
kotakku | 0:b1ce54272580 | 96 | |
kotakku | 0:b1ce54272580 | 97 | uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) |
kotakku | 0:b1ce54272580 | 98 | { |
kotakku | 0:b1ce54272580 | 99 | UsbDevice *p = addrPool.GetUsbDevicePtr(addr); |
kotakku | 0:b1ce54272580 | 100 | |
kotakku | 0:b1ce54272580 | 101 | if (!p) |
kotakku | 0:b1ce54272580 | 102 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 103 | |
kotakku | 0:b1ce54272580 | 104 | if (!p->epinfo) |
kotakku | 0:b1ce54272580 | 105 | return USB_ERROR_EPINFO_IS_NULL; |
kotakku | 0:b1ce54272580 | 106 | |
kotakku | 0:b1ce54272580 | 107 | *ppep = getEpInfoEntry(addr, ep); |
kotakku | 0:b1ce54272580 | 108 | |
kotakku | 0:b1ce54272580 | 109 | if (!*ppep) |
kotakku | 0:b1ce54272580 | 110 | return USB_ERROR_EP_NOT_FOUND_IN_TBL; |
kotakku | 0:b1ce54272580 | 111 | |
kotakku | 0:b1ce54272580 | 112 | *nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower)); |
kotakku | 0:b1ce54272580 | 113 | (*nak_limit)--; |
kotakku | 0:b1ce54272580 | 114 | /* |
kotakku | 0:b1ce54272580 | 115 | USBTRACE2("\r\nAddress: ", addr); |
kotakku | 0:b1ce54272580 | 116 | USBTRACE2(" EP: ", ep); |
kotakku | 0:b1ce54272580 | 117 | USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower); |
kotakku | 0:b1ce54272580 | 118 | USBTRACE2(" NAK Limit: ", nak_limit); |
kotakku | 0:b1ce54272580 | 119 | USBTRACE("\r\n"); |
kotakku | 0:b1ce54272580 | 120 | */ |
kotakku | 0:b1ce54272580 | 121 | regWr(rPERADDR, addr); //set peripheral address |
kotakku | 0:b1ce54272580 | 122 | |
kotakku | 0:b1ce54272580 | 123 | uint8_t mode = regRd(rMODE); |
kotakku | 0:b1ce54272580 | 124 | |
kotakku | 0:b1ce54272580 | 125 | //Serial.print("\r\nMode: "); |
kotakku | 0:b1ce54272580 | 126 | //Serial.println( mode, HEX); |
kotakku | 0:b1ce54272580 | 127 | //Serial.print("\r\nLS: "); |
kotakku | 0:b1ce54272580 | 128 | //Serial.println(p->lowspeed, HEX); |
kotakku | 0:b1ce54272580 | 129 | |
kotakku | 0:b1ce54272580 | 130 | // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise |
kotakku | 0:b1ce54272580 | 131 | regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); |
kotakku | 0:b1ce54272580 | 132 | |
kotakku | 0:b1ce54272580 | 133 | return 0; |
kotakku | 0:b1ce54272580 | 134 | } |
kotakku | 0:b1ce54272580 | 135 | |
kotakku | 0:b1ce54272580 | 136 | /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ |
kotakku | 0:b1ce54272580 | 137 | /* depending on request. Actual requests are defined as inlines */ |
kotakku | 0:b1ce54272580 | 138 | /* return codes: */ |
kotakku | 0:b1ce54272580 | 139 | /* 00 = success */ |
kotakku | 0:b1ce54272580 | 140 | |
kotakku | 0:b1ce54272580 | 141 | /* 01-0f = non-zero HRSLT */ |
kotakku | 0:b1ce54272580 | 142 | uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, |
kotakku | 0:b1ce54272580 | 143 | uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p) |
kotakku | 0:b1ce54272580 | 144 | { |
kotakku | 0:b1ce54272580 | 145 | bool direction = false; //request direction, IN or OUT |
kotakku | 0:b1ce54272580 | 146 | uint8_t rcode; |
kotakku | 0:b1ce54272580 | 147 | SETUP_PKT setup_pkt; |
kotakku | 0:b1ce54272580 | 148 | |
kotakku | 0:b1ce54272580 | 149 | EpInfo *pep = NULL; |
kotakku | 0:b1ce54272580 | 150 | uint16_t nak_limit = 0; |
kotakku | 0:b1ce54272580 | 151 | |
kotakku | 0:b1ce54272580 | 152 | rcode = SetAddress(addr, ep, &pep, &nak_limit); |
kotakku | 0:b1ce54272580 | 153 | |
kotakku | 0:b1ce54272580 | 154 | if (rcode) |
kotakku | 0:b1ce54272580 | 155 | return rcode; |
kotakku | 0:b1ce54272580 | 156 | |
kotakku | 0:b1ce54272580 | 157 | direction = ((bmReqType & 0x80) > 0); |
kotakku | 0:b1ce54272580 | 158 | |
kotakku | 0:b1ce54272580 | 159 | /* fill in setup packet */ |
kotakku | 0:b1ce54272580 | 160 | setup_pkt.ReqType_u.bmRequestType = bmReqType; |
kotakku | 0:b1ce54272580 | 161 | setup_pkt.bRequest = bRequest; |
kotakku | 0:b1ce54272580 | 162 | setup_pkt.wVal_u.wValueLo = wValLo; |
kotakku | 0:b1ce54272580 | 163 | setup_pkt.wVal_u.wValueHi = wValHi; |
kotakku | 0:b1ce54272580 | 164 | setup_pkt.wIndex = wInd; |
kotakku | 0:b1ce54272580 | 165 | setup_pkt.wLength = total; |
kotakku | 0:b1ce54272580 | 166 | |
kotakku | 0:b1ce54272580 | 167 | bytesWr(rSUDFIFO, 8, (uint8_t *)&setup_pkt); //transfer to setup packet FIFO |
kotakku | 0:b1ce54272580 | 168 | |
kotakku | 0:b1ce54272580 | 169 | rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet |
kotakku | 0:b1ce54272580 | 170 | |
kotakku | 0:b1ce54272580 | 171 | if (rcode) //return HRSLT if not zero |
kotakku | 0:b1ce54272580 | 172 | return (rcode); |
kotakku | 0:b1ce54272580 | 173 | |
kotakku | 0:b1ce54272580 | 174 | if (dataptr != NULL) //data stage, if present |
kotakku | 0:b1ce54272580 | 175 | { |
kotakku | 0:b1ce54272580 | 176 | if (direction) //IN transfer |
kotakku | 0:b1ce54272580 | 177 | { |
kotakku | 0:b1ce54272580 | 178 | uint16_t left = total; |
kotakku | 0:b1ce54272580 | 179 | |
kotakku | 0:b1ce54272580 | 180 | pep->bmRcvToggle = 1; //bmRCVTOG1; |
kotakku | 0:b1ce54272580 | 181 | |
kotakku | 0:b1ce54272580 | 182 | while (left) |
kotakku | 0:b1ce54272580 | 183 | { |
kotakku | 0:b1ce54272580 | 184 | // Bytes read into buffer |
kotakku | 0:b1ce54272580 | 185 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 186 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 187 | #endif |
kotakku | 0:b1ce54272580 | 188 | uint16_t read = nbytes; |
kotakku | 0:b1ce54272580 | 189 | //uint16_t read = (left<nbytes) ? left : nbytes; |
kotakku | 0:b1ce54272580 | 190 | |
kotakku | 0:b1ce54272580 | 191 | rcode = InTransfer(pep, nak_limit, &read, dataptr); |
kotakku | 0:b1ce54272580 | 192 | if (rcode == hrTOGERR) |
kotakku | 0:b1ce54272580 | 193 | { |
kotakku | 0:b1ce54272580 | 194 | // yes, we flip it wrong here so that next time it is actually correct! |
kotakku | 0:b1ce54272580 | 195 | pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; |
kotakku | 0:b1ce54272580 | 196 | continue; |
kotakku | 0:b1ce54272580 | 197 | } |
kotakku | 0:b1ce54272580 | 198 | |
kotakku | 0:b1ce54272580 | 199 | if (rcode) |
kotakku | 0:b1ce54272580 | 200 | return rcode; |
kotakku | 0:b1ce54272580 | 201 | |
kotakku | 0:b1ce54272580 | 202 | // Invoke callback function if inTransfer completed successfully and callback function pointer is specified |
kotakku | 0:b1ce54272580 | 203 | if (!rcode && p) |
kotakku | 0:b1ce54272580 | 204 | ((USBReadParser *)p)->Parse(read, dataptr, total - left); |
kotakku | 0:b1ce54272580 | 205 | |
kotakku | 0:b1ce54272580 | 206 | left -= read; |
kotakku | 0:b1ce54272580 | 207 | |
kotakku | 0:b1ce54272580 | 208 | if (read < nbytes) |
kotakku | 0:b1ce54272580 | 209 | break; |
kotakku | 0:b1ce54272580 | 210 | } |
kotakku | 0:b1ce54272580 | 211 | } |
kotakku | 0:b1ce54272580 | 212 | else //OUT transfer |
kotakku | 0:b1ce54272580 | 213 | { |
kotakku | 0:b1ce54272580 | 214 | pep->bmSndToggle = 1; //bmSNDTOG1; |
kotakku | 0:b1ce54272580 | 215 | rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); |
kotakku | 0:b1ce54272580 | 216 | } |
kotakku | 0:b1ce54272580 | 217 | if (rcode) //return error |
kotakku | 0:b1ce54272580 | 218 | return (rcode); |
kotakku | 0:b1ce54272580 | 219 | } |
kotakku | 0:b1ce54272580 | 220 | // Status stage |
kotakku | 0:b1ce54272580 | 221 | return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction |
kotakku | 0:b1ce54272580 | 222 | } |
kotakku | 0:b1ce54272580 | 223 | |
kotakku | 0:b1ce54272580 | 224 | /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ |
kotakku | 0:b1ce54272580 | 225 | /* Keep sending INs and writes data to memory area pointed by 'data' */ |
kotakku | 0:b1ce54272580 | 226 | |
kotakku | 0:b1ce54272580 | 227 | /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, |
kotakku | 0:b1ce54272580 | 228 | fe USB xfer timeout */ |
kotakku | 0:b1ce54272580 | 229 | uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval /*= 0*/) |
kotakku | 0:b1ce54272580 | 230 | { |
kotakku | 0:b1ce54272580 | 231 | EpInfo *pep = NULL; |
kotakku | 0:b1ce54272580 | 232 | uint16_t nak_limit = 0; |
kotakku | 0:b1ce54272580 | 233 | |
kotakku | 0:b1ce54272580 | 234 | uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit); |
kotakku | 0:b1ce54272580 | 235 | |
kotakku | 0:b1ce54272580 | 236 | if (rcode) |
kotakku | 0:b1ce54272580 | 237 | { |
kotakku | 0:b1ce54272580 | 238 | USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81); |
kotakku | 0:b1ce54272580 | 239 | USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81); |
kotakku | 0:b1ce54272580 | 240 | USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81); |
kotakku | 0:b1ce54272580 | 241 | return rcode; |
kotakku | 0:b1ce54272580 | 242 | } |
kotakku | 0:b1ce54272580 | 243 | return InTransfer(pep, nak_limit, nbytesptr, data, bInterval); |
kotakku | 0:b1ce54272580 | 244 | } |
kotakku | 0:b1ce54272580 | 245 | |
kotakku | 0:b1ce54272580 | 246 | uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval /*= 0*/) |
kotakku | 0:b1ce54272580 | 247 | { |
kotakku | 0:b1ce54272580 | 248 | uint8_t rcode = 0; |
kotakku | 0:b1ce54272580 | 249 | uint8_t pktsize; |
kotakku | 0:b1ce54272580 | 250 | |
kotakku | 0:b1ce54272580 | 251 | uint16_t nbytes = *nbytesptr; |
kotakku | 0:b1ce54272580 | 252 | //DEBUG("Requesting %i bytes ", nbytes); |
kotakku | 0:b1ce54272580 | 253 | uint8_t maxpktsize = pep->maxPktSize; |
kotakku | 0:b1ce54272580 | 254 | |
kotakku | 0:b1ce54272580 | 255 | *nbytesptr = 0; |
kotakku | 0:b1ce54272580 | 256 | regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value |
kotakku | 0:b1ce54272580 | 257 | |
kotakku | 0:b1ce54272580 | 258 | // use a 'break' to exit this loop |
kotakku | 0:b1ce54272580 | 259 | while (1) |
kotakku | 0:b1ce54272580 | 260 | { |
kotakku | 0:b1ce54272580 | 261 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 262 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 263 | #endif |
kotakku | 0:b1ce54272580 | 264 | rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS. |
kotakku | 0:b1ce54272580 | 265 | if (rcode == hrTOGERR) |
kotakku | 0:b1ce54272580 | 266 | { |
kotakku | 0:b1ce54272580 | 267 | // yes, we flip it wrong here so that next time it is actually correct! |
kotakku | 0:b1ce54272580 | 268 | pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1; |
kotakku | 0:b1ce54272580 | 269 | regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value |
kotakku | 0:b1ce54272580 | 270 | continue; |
kotakku | 0:b1ce54272580 | 271 | } |
kotakku | 0:b1ce54272580 | 272 | if (rcode) |
kotakku | 0:b1ce54272580 | 273 | { |
kotakku | 0:b1ce54272580 | 274 | //DEBUG(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode); |
kotakku | 0:b1ce54272580 | 275 | break; //should be 0, indicating ACK. Else return error code. |
kotakku | 0:b1ce54272580 | 276 | } |
kotakku | 0:b1ce54272580 | 277 | /* check for RCVDAVIRQ and generate error if not present |
kotakku | 0:b1ce54272580 | 278 | * the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. |
kotakku | 0:b1ce54272580 | 279 | * Need to add handling for that |
kotakku | 0:b1ce54272580 | 280 | * |
kotakku | 0:b1ce54272580 | 281 | * NOTE: I've seen this happen with SPI corruption -- xxxajk |
kotakku | 0:b1ce54272580 | 282 | */ |
kotakku | 0:b1ce54272580 | 283 | if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) |
kotakku | 0:b1ce54272580 | 284 | { |
kotakku | 0:b1ce54272580 | 285 | //DEBUG(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n"); |
kotakku | 0:b1ce54272580 | 286 | rcode = 0xf0; //receive error |
kotakku | 0:b1ce54272580 | 287 | break; |
kotakku | 0:b1ce54272580 | 288 | } |
kotakku | 0:b1ce54272580 | 289 | pktsize = regRd(rRCVBC); //number of received bytes |
kotakku | 0:b1ce54272580 | 290 | //DEBUG("Got %i bytes \r\n", pktsize); |
kotakku | 0:b1ce54272580 | 291 | // This would be OK, but... |
kotakku | 0:b1ce54272580 | 292 | //assert(pktsize <= nbytes); |
kotakku | 0:b1ce54272580 | 293 | if (pktsize > nbytes) |
kotakku | 0:b1ce54272580 | 294 | { |
kotakku | 0:b1ce54272580 | 295 | // This can happen. Use of assert on Arduino locks up the Arduino. |
kotakku | 0:b1ce54272580 | 296 | // So I will trim the value, and hope for the best. |
kotakku | 0:b1ce54272580 | 297 | //DEBUG(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize); |
kotakku | 0:b1ce54272580 | 298 | pktsize = nbytes; |
kotakku | 0:b1ce54272580 | 299 | } |
kotakku | 0:b1ce54272580 | 300 | |
kotakku | 0:b1ce54272580 | 301 | int16_t mem_left = (int16_t)nbytes - *((int16_t *)nbytesptr); |
kotakku | 0:b1ce54272580 | 302 | |
kotakku | 0:b1ce54272580 | 303 | if (mem_left < 0) |
kotakku | 0:b1ce54272580 | 304 | mem_left = 0; |
kotakku | 0:b1ce54272580 | 305 | |
kotakku | 0:b1ce54272580 | 306 | data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); |
kotakku | 0:b1ce54272580 | 307 | |
kotakku | 0:b1ce54272580 | 308 | regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer |
kotakku | 0:b1ce54272580 | 309 | *nbytesptr += pktsize; // add this packet's byte count to total transfer length |
kotakku | 0:b1ce54272580 | 310 | |
kotakku | 0:b1ce54272580 | 311 | /* The transfer is complete under two conditions: */ |
kotakku | 0:b1ce54272580 | 312 | /* 1. The device sent a short packet (L.T. maxPacketSize) */ |
kotakku | 0:b1ce54272580 | 313 | /* 2. 'nbytes' have been transferred. */ |
kotakku | 0:b1ce54272580 | 314 | if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? |
kotakku | 0:b1ce54272580 | 315 | { |
kotakku | 0:b1ce54272580 | 316 | // Save toggle value |
kotakku | 0:b1ce54272580 | 317 | pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0; |
kotakku | 0:b1ce54272580 | 318 | //DEBUG("\r\n"); |
kotakku | 0:b1ce54272580 | 319 | rcode = 0; |
kotakku | 0:b1ce54272580 | 320 | break; |
kotakku | 0:b1ce54272580 | 321 | } |
kotakku | 0:b1ce54272580 | 322 | else if (bInterval > 0) |
kotakku | 0:b1ce54272580 | 323 | delay(bInterval); // Delay according to polling interval |
kotakku | 0:b1ce54272580 | 324 | } //while( 1 ) |
kotakku | 0:b1ce54272580 | 325 | return (rcode); |
kotakku | 0:b1ce54272580 | 326 | } |
kotakku | 0:b1ce54272580 | 327 | |
kotakku | 0:b1ce54272580 | 328 | /* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ |
kotakku | 0:b1ce54272580 | 329 | /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */ |
kotakku | 0:b1ce54272580 | 330 | |
kotakku | 0:b1ce54272580 | 331 | /* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */ |
kotakku | 0:b1ce54272580 | 332 | uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data) |
kotakku | 0:b1ce54272580 | 333 | { |
kotakku | 0:b1ce54272580 | 334 | EpInfo *pep = NULL; |
kotakku | 0:b1ce54272580 | 335 | uint16_t nak_limit = 0; |
kotakku | 0:b1ce54272580 | 336 | |
kotakku | 0:b1ce54272580 | 337 | uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit); |
kotakku | 0:b1ce54272580 | 338 | |
kotakku | 0:b1ce54272580 | 339 | if (rcode) |
kotakku | 0:b1ce54272580 | 340 | return rcode; |
kotakku | 0:b1ce54272580 | 341 | |
kotakku | 0:b1ce54272580 | 342 | return OutTransfer(pep, nak_limit, nbytes, data); |
kotakku | 0:b1ce54272580 | 343 | } |
kotakku | 0:b1ce54272580 | 344 | |
kotakku | 0:b1ce54272580 | 345 | uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) |
kotakku | 0:b1ce54272580 | 346 | { |
kotakku | 0:b1ce54272580 | 347 | uint8_t rcode = hrSUCCESS, retry_count; |
kotakku | 0:b1ce54272580 | 348 | uint8_t *data_p = data; //local copy of the data pointer |
kotakku | 0:b1ce54272580 | 349 | uint16_t bytes_tosend, nak_count; |
kotakku | 0:b1ce54272580 | 350 | uint16_t bytes_left = nbytes; |
kotakku | 0:b1ce54272580 | 351 | |
kotakku | 0:b1ce54272580 | 352 | uint8_t maxpktsize = pep->maxPktSize; |
kotakku | 0:b1ce54272580 | 353 | |
kotakku | 0:b1ce54272580 | 354 | if (maxpktsize < 1 || maxpktsize > 64) |
kotakku | 0:b1ce54272580 | 355 | return USB_ERROR_INVALID_MAX_PKT_SIZE; |
kotakku | 0:b1ce54272580 | 356 | |
kotakku | 0:b1ce54272580 | 357 | uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT; |
kotakku | 0:b1ce54272580 | 358 | |
kotakku | 0:b1ce54272580 | 359 | regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value |
kotakku | 0:b1ce54272580 | 360 | |
kotakku | 0:b1ce54272580 | 361 | while (bytes_left) |
kotakku | 0:b1ce54272580 | 362 | { |
kotakku | 0:b1ce54272580 | 363 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 364 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 365 | #endif |
kotakku | 0:b1ce54272580 | 366 | retry_count = 0; |
kotakku | 0:b1ce54272580 | 367 | nak_count = 0; |
kotakku | 0:b1ce54272580 | 368 | bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; |
kotakku | 0:b1ce54272580 | 369 | bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO |
kotakku | 0:b1ce54272580 | 370 | regWr(rSNDBC, bytes_tosend); //set number of bytes |
kotakku | 0:b1ce54272580 | 371 | regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet |
kotakku | 0:b1ce54272580 | 372 | while (!(regRd(rHIRQ) & bmHXFRDNIRQ)) |
kotakku | 0:b1ce54272580 | 373 | { |
kotakku | 0:b1ce54272580 | 374 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 375 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 376 | #endif |
kotakku | 0:b1ce54272580 | 377 | } //wait for the completion IRQ |
kotakku | 0:b1ce54272580 | 378 | regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ |
kotakku | 0:b1ce54272580 | 379 | rcode = (regRd(rHRSL) & 0x0f); |
kotakku | 0:b1ce54272580 | 380 | |
kotakku | 0:b1ce54272580 | 381 | while (rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) |
kotakku | 0:b1ce54272580 | 382 | { |
kotakku | 0:b1ce54272580 | 383 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 384 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 385 | #endif |
kotakku | 0:b1ce54272580 | 386 | switch (rcode) |
kotakku | 0:b1ce54272580 | 387 | { |
kotakku | 0:b1ce54272580 | 388 | case hrNAK: |
kotakku | 0:b1ce54272580 | 389 | nak_count++; |
kotakku | 0:b1ce54272580 | 390 | if (nak_limit && (nak_count == nak_limit)) |
kotakku | 0:b1ce54272580 | 391 | goto breakout; |
kotakku | 0:b1ce54272580 | 392 | //return ( rcode); |
kotakku | 0:b1ce54272580 | 393 | break; |
kotakku | 0:b1ce54272580 | 394 | case hrTIMEOUT: |
kotakku | 0:b1ce54272580 | 395 | retry_count++; |
kotakku | 0:b1ce54272580 | 396 | if (retry_count == USB_RETRY_LIMIT) |
kotakku | 0:b1ce54272580 | 397 | goto breakout; |
kotakku | 0:b1ce54272580 | 398 | //return ( rcode); |
kotakku | 0:b1ce54272580 | 399 | break; |
kotakku | 0:b1ce54272580 | 400 | case hrTOGERR: |
kotakku | 0:b1ce54272580 | 401 | // yes, we flip it wrong here so that next time it is actually correct! |
kotakku | 0:b1ce54272580 | 402 | pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; |
kotakku | 0:b1ce54272580 | 403 | regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value |
kotakku | 0:b1ce54272580 | 404 | break; |
kotakku | 0:b1ce54272580 | 405 | default: |
kotakku | 0:b1ce54272580 | 406 | goto breakout; |
kotakku | 0:b1ce54272580 | 407 | } //switch( rcode |
kotakku | 0:b1ce54272580 | 408 | |
kotakku | 0:b1ce54272580 | 409 | /* process NAK according to Host out NAK bug */ |
kotakku | 0:b1ce54272580 | 410 | regWr(rSNDBC, 0); |
kotakku | 0:b1ce54272580 | 411 | regWr(rSNDFIFO, *data_p); |
kotakku | 0:b1ce54272580 | 412 | regWr(rSNDBC, bytes_tosend); |
kotakku | 0:b1ce54272580 | 413 | regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet |
kotakku | 0:b1ce54272580 | 414 | while (!(regRd(rHIRQ) & bmHXFRDNIRQ)) |
kotakku | 0:b1ce54272580 | 415 | { |
kotakku | 0:b1ce54272580 | 416 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 417 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 418 | #endif |
kotakku | 0:b1ce54272580 | 419 | } //wait for the completion IRQ |
kotakku | 0:b1ce54272580 | 420 | regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ |
kotakku | 0:b1ce54272580 | 421 | rcode = (regRd(rHRSL) & 0x0f); |
kotakku | 0:b1ce54272580 | 422 | } //while( rcode && .... |
kotakku | 0:b1ce54272580 | 423 | bytes_left -= bytes_tosend; |
kotakku | 0:b1ce54272580 | 424 | data_p += bytes_tosend; |
kotakku | 0:b1ce54272580 | 425 | } //while( bytes_left... |
kotakku | 0:b1ce54272580 | 426 | breakout: |
kotakku | 0:b1ce54272580 | 427 | |
kotakku | 0:b1ce54272580 | 428 | pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle |
kotakku | 0:b1ce54272580 | 429 | return (rcode); //should be 0 in all cases |
kotakku | 0:b1ce54272580 | 430 | } |
kotakku | 0:b1ce54272580 | 431 | /* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */ |
kotakku | 0:b1ce54272580 | 432 | /* If NAK, tries to re-send up to nak_limit times */ |
kotakku | 0:b1ce54272580 | 433 | /* If nak_limit == 0, do not count NAKs, exit after timeout */ |
kotakku | 0:b1ce54272580 | 434 | /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */ |
kotakku | 0:b1ce54272580 | 435 | |
kotakku | 0:b1ce54272580 | 436 | /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ |
kotakku | 0:b1ce54272580 | 437 | uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) |
kotakku | 0:b1ce54272580 | 438 | { |
kotakku | 0:b1ce54272580 | 439 | uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT; |
kotakku | 0:b1ce54272580 | 440 | uint8_t tmpdata; |
kotakku | 0:b1ce54272580 | 441 | uint8_t rcode = hrSUCCESS; |
kotakku | 0:b1ce54272580 | 442 | uint8_t retry_count = 0; |
kotakku | 0:b1ce54272580 | 443 | uint16_t nak_count = 0; |
kotakku | 0:b1ce54272580 | 444 | |
kotakku | 0:b1ce54272580 | 445 | while ((int32_t)((uint32_t)millis() - timeout) < 0L) |
kotakku | 0:b1ce54272580 | 446 | { |
kotakku | 0:b1ce54272580 | 447 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 448 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 449 | #endif |
kotakku | 0:b1ce54272580 | 450 | regWr(rHXFR, (token | ep)); //launch the transfer |
kotakku | 0:b1ce54272580 | 451 | rcode = USB_ERROR_TRANSFER_TIMEOUT; |
kotakku | 0:b1ce54272580 | 452 | |
kotakku | 0:b1ce54272580 | 453 | while ((int32_t)((uint32_t)millis() - timeout) < 0L) //wait for transfer completion |
kotakku | 0:b1ce54272580 | 454 | { |
kotakku | 0:b1ce54272580 | 455 | #if defined(ESP8266) || defined(ESP32) |
kotakku | 0:b1ce54272580 | 456 | yield(); // needed in order to reset the watchdog timer on the ESP8266 |
kotakku | 0:b1ce54272580 | 457 | #endif |
kotakku | 0:b1ce54272580 | 458 | tmpdata = regRd(rHIRQ); |
kotakku | 0:b1ce54272580 | 459 | |
kotakku | 0:b1ce54272580 | 460 | if (tmpdata & bmHXFRDNIRQ) |
kotakku | 0:b1ce54272580 | 461 | { |
kotakku | 0:b1ce54272580 | 462 | regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt |
kotakku | 0:b1ce54272580 | 463 | rcode = 0x00; |
kotakku | 0:b1ce54272580 | 464 | break; |
kotakku | 0:b1ce54272580 | 465 | } //if( tmpdata & bmHXFRDNIRQ |
kotakku | 0:b1ce54272580 | 466 | |
kotakku | 0:b1ce54272580 | 467 | } //while ( millis() < timeout |
kotakku | 0:b1ce54272580 | 468 | |
kotakku | 0:b1ce54272580 | 469 | //if (rcode != 0x00) //exit if timeout |
kotakku | 0:b1ce54272580 | 470 | // return ( rcode); |
kotakku | 0:b1ce54272580 | 471 | |
kotakku | 0:b1ce54272580 | 472 | rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result |
kotakku | 0:b1ce54272580 | 473 | |
kotakku | 0:b1ce54272580 | 474 | switch (rcode) |
kotakku | 0:b1ce54272580 | 475 | { |
kotakku | 0:b1ce54272580 | 476 | case hrNAK: |
kotakku | 0:b1ce54272580 | 477 | nak_count++; |
kotakku | 0:b1ce54272580 | 478 | if (nak_limit && (nak_count == nak_limit)) |
kotakku | 0:b1ce54272580 | 479 | return (rcode); |
kotakku | 0:b1ce54272580 | 480 | break; |
kotakku | 0:b1ce54272580 | 481 | case hrTIMEOUT: |
kotakku | 0:b1ce54272580 | 482 | retry_count++; |
kotakku | 0:b1ce54272580 | 483 | if (retry_count == USB_RETRY_LIMIT) |
kotakku | 0:b1ce54272580 | 484 | return (rcode); |
kotakku | 0:b1ce54272580 | 485 | break; |
kotakku | 0:b1ce54272580 | 486 | default: |
kotakku | 0:b1ce54272580 | 487 | return (rcode); |
kotakku | 0:b1ce54272580 | 488 | } //switch( rcode |
kotakku | 0:b1ce54272580 | 489 | |
kotakku | 0:b1ce54272580 | 490 | } //while( timeout > millis() |
kotakku | 0:b1ce54272580 | 491 | return (rcode); |
kotakku | 0:b1ce54272580 | 492 | } |
kotakku | 0:b1ce54272580 | 493 | |
kotakku | 0:b1ce54272580 | 494 | /* USB main task. Performs enumeration/cleanup */ |
kotakku | 0:b1ce54272580 | 495 | void USB::Task(void) //USB state machine |
kotakku | 0:b1ce54272580 | 496 | { |
kotakku | 0:b1ce54272580 | 497 | uint8_t rcode; |
kotakku | 0:b1ce54272580 | 498 | uint8_t tmpdata; |
kotakku | 0:b1ce54272580 | 499 | static uint32_t delay = 0; |
kotakku | 0:b1ce54272580 | 500 | //USB_DEVICE_DESCRIPTOR buf; |
kotakku | 0:b1ce54272580 | 501 | bool lowspeed = false; |
kotakku | 0:b1ce54272580 | 502 | |
kotakku | 0:b1ce54272580 | 503 | MAX3421E::Task(); // 割り込みがあったらコマンドで対応する |
kotakku | 0:b1ce54272580 | 504 | |
kotakku | 0:b1ce54272580 | 505 | tmpdata = getVbusState(); |
kotakku | 0:b1ce54272580 | 506 | |
kotakku | 0:b1ce54272580 | 507 | /* modify USB task state if Vbus changed */ |
kotakku | 0:b1ce54272580 | 508 | switch (tmpdata) |
kotakku | 0:b1ce54272580 | 509 | { |
kotakku | 0:b1ce54272580 | 510 | case SE1: //illegal state |
kotakku | 0:b1ce54272580 | 511 | usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; |
kotakku | 0:b1ce54272580 | 512 | lowspeed = false; |
kotakku | 0:b1ce54272580 | 513 | break; |
kotakku | 0:b1ce54272580 | 514 | case SE0: //disconnected |
kotakku | 0:b1ce54272580 | 515 | if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED) |
kotakku | 0:b1ce54272580 | 516 | usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; |
kotakku | 0:b1ce54272580 | 517 | lowspeed = false; |
kotakku | 0:b1ce54272580 | 518 | break; |
kotakku | 0:b1ce54272580 | 519 | case LSHOST: |
kotakku | 0:b1ce54272580 | 520 | |
kotakku | 0:b1ce54272580 | 521 | lowspeed = true; |
kotakku | 0:b1ce54272580 | 522 | //intentional fallthrough |
kotakku | 0:b1ce54272580 | 523 | case FSHOST: //attached |
kotakku | 0:b1ce54272580 | 524 | if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) |
kotakku | 0:b1ce54272580 | 525 | { |
kotakku | 0:b1ce54272580 | 526 | delay = (uint32_t)millis() + USB_SETTLE_DELAY; |
kotakku | 0:b1ce54272580 | 527 | usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; |
kotakku | 0:b1ce54272580 | 528 | } |
kotakku | 0:b1ce54272580 | 529 | break; |
kotakku | 0:b1ce54272580 | 530 | } // switch( tmpdata |
kotakku | 0:b1ce54272580 | 531 | |
kotakku | 0:b1ce54272580 | 532 | for (uint8_t i = 0; i < USB_NUMDEVICES; i++) |
kotakku | 0:b1ce54272580 | 533 | if (devConfig[i]) |
kotakku | 0:b1ce54272580 | 534 | { |
kotakku | 0:b1ce54272580 | 535 | DEBUG("dev %d, poll\n", i); |
kotakku | 0:b1ce54272580 | 536 | rcode = devConfig[i]->Poll(); |
kotakku | 0:b1ce54272580 | 537 | } |
kotakku | 0:b1ce54272580 | 538 | |
kotakku | 0:b1ce54272580 | 539 | switch (usb_task_state) |
kotakku | 0:b1ce54272580 | 540 | { |
kotakku | 0:b1ce54272580 | 541 | case USB_DETACHED_SUBSTATE_INITIALIZE: |
kotakku | 0:b1ce54272580 | 542 | init(); |
kotakku | 0:b1ce54272580 | 543 | |
kotakku | 0:b1ce54272580 | 544 | for (uint8_t i = 0; i < USB_NUMDEVICES; i++) |
kotakku | 0:b1ce54272580 | 545 | if (devConfig[i]) |
kotakku | 0:b1ce54272580 | 546 | rcode = devConfig[i]->Release(); |
kotakku | 0:b1ce54272580 | 547 | |
kotakku | 0:b1ce54272580 | 548 | usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; |
kotakku | 0:b1ce54272580 | 549 | break; |
kotakku | 0:b1ce54272580 | 550 | case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here |
kotakku | 0:b1ce54272580 | 551 | break; |
kotakku | 0:b1ce54272580 | 552 | case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here |
kotakku | 0:b1ce54272580 | 553 | break; |
kotakku | 0:b1ce54272580 | 554 | case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device |
kotakku | 0:b1ce54272580 | 555 | if ((int32_t)((uint32_t)millis() - delay) >= 0L) |
kotakku | 0:b1ce54272580 | 556 | usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; |
kotakku | 0:b1ce54272580 | 557 | else |
kotakku | 0:b1ce54272580 | 558 | break; // don't fall through |
kotakku | 0:b1ce54272580 | 559 | case USB_ATTACHED_SUBSTATE_RESET_DEVICE: |
kotakku | 0:b1ce54272580 | 560 | regWr(rHCTL, bmBUSRST); //issue bus reset |
kotakku | 0:b1ce54272580 | 561 | usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; |
kotakku | 0:b1ce54272580 | 562 | break; |
kotakku | 0:b1ce54272580 | 563 | case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: |
kotakku | 0:b1ce54272580 | 564 | if ((regRd(rHCTL) & bmBUSRST) == 0) |
kotakku | 0:b1ce54272580 | 565 | { |
kotakku | 0:b1ce54272580 | 566 | tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation |
kotakku | 0:b1ce54272580 | 567 | regWr(rMODE, tmpdata); |
kotakku | 0:b1ce54272580 | 568 | usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF; |
kotakku | 0:b1ce54272580 | 569 | //delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec |
kotakku | 0:b1ce54272580 | 570 | } |
kotakku | 0:b1ce54272580 | 571 | break; |
kotakku | 0:b1ce54272580 | 572 | case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order |
kotakku | 0:b1ce54272580 | 573 | if (regRd(rHIRQ) & bmFRAMEIRQ) |
kotakku | 0:b1ce54272580 | 574 | { |
kotakku | 0:b1ce54272580 | 575 | //when first SOF received _and_ 20ms has passed we can continue |
kotakku | 0:b1ce54272580 | 576 | /* |
kotakku | 0:b1ce54272580 | 577 | if (delay < (uint32_t)millis()) //20ms passed |
kotakku | 0:b1ce54272580 | 578 | usb_task_state = USB_STATE_CONFIGURING; |
kotakku | 0:b1ce54272580 | 579 | */ |
kotakku | 0:b1ce54272580 | 580 | usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET; |
kotakku | 0:b1ce54272580 | 581 | delay = (uint32_t)millis() + 20; |
kotakku | 0:b1ce54272580 | 582 | } |
kotakku | 0:b1ce54272580 | 583 | break; |
kotakku | 0:b1ce54272580 | 584 | case USB_ATTACHED_SUBSTATE_WAIT_RESET: |
kotakku | 0:b1ce54272580 | 585 | if ((int32_t)((uint32_t)millis() - delay) >= 0L) |
kotakku | 0:b1ce54272580 | 586 | usb_task_state = USB_STATE_CONFIGURING; |
kotakku | 0:b1ce54272580 | 587 | else |
kotakku | 0:b1ce54272580 | 588 | break; // don't fall through |
kotakku | 0:b1ce54272580 | 589 | case USB_STATE_CONFIGURING: |
kotakku | 0:b1ce54272580 | 590 | |
kotakku | 0:b1ce54272580 | 591 | //Serial.print("\r\nConf.LS: "); |
kotakku | 0:b1ce54272580 | 592 | //Serial.println(lowspeed, HEX); |
kotakku | 0:b1ce54272580 | 593 | |
kotakku | 0:b1ce54272580 | 594 | rcode = Configuring(0, 0, lowspeed); |
kotakku | 0:b1ce54272580 | 595 | |
kotakku | 0:b1ce54272580 | 596 | if (rcode) |
kotakku | 0:b1ce54272580 | 597 | { |
kotakku | 0:b1ce54272580 | 598 | if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) |
kotakku | 0:b1ce54272580 | 599 | { |
kotakku | 0:b1ce54272580 | 600 | usb_error = rcode; |
kotakku | 0:b1ce54272580 | 601 | usb_task_state = USB_STATE_ERROR; |
kotakku | 0:b1ce54272580 | 602 | } |
kotakku | 0:b1ce54272580 | 603 | } |
kotakku | 0:b1ce54272580 | 604 | else |
kotakku | 0:b1ce54272580 | 605 | usb_task_state = USB_STATE_RUNNING; |
kotakku | 0:b1ce54272580 | 606 | break; |
kotakku | 0:b1ce54272580 | 607 | case USB_STATE_RUNNING: |
kotakku | 0:b1ce54272580 | 608 | break; |
kotakku | 0:b1ce54272580 | 609 | case USB_STATE_ERROR: |
kotakku | 0:b1ce54272580 | 610 | //MAX3421E::Init(); |
kotakku | 0:b1ce54272580 | 611 | break; |
kotakku | 0:b1ce54272580 | 612 | } // switch( usb_task_state ) |
kotakku | 0:b1ce54272580 | 613 | } |
kotakku | 0:b1ce54272580 | 614 | |
kotakku | 0:b1ce54272580 | 615 | uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) |
kotakku | 0:b1ce54272580 | 616 | { |
kotakku | 0:b1ce54272580 | 617 | //uint8_t buf[12]; |
kotakku | 0:b1ce54272580 | 618 | uint8_t rcode; |
kotakku | 0:b1ce54272580 | 619 | UsbDevice *p0 = NULL, *p = NULL; |
kotakku | 0:b1ce54272580 | 620 | |
kotakku | 0:b1ce54272580 | 621 | // Get pointer to pseudo device with address 0 assigned |
kotakku | 0:b1ce54272580 | 622 | p0 = addrPool.GetUsbDevicePtr(0); |
kotakku | 0:b1ce54272580 | 623 | |
kotakku | 0:b1ce54272580 | 624 | if (!p0) |
kotakku | 0:b1ce54272580 | 625 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 626 | |
kotakku | 0:b1ce54272580 | 627 | if (!p0->epinfo) |
kotakku | 0:b1ce54272580 | 628 | return USB_ERROR_EPINFO_IS_NULL; |
kotakku | 0:b1ce54272580 | 629 | |
kotakku | 0:b1ce54272580 | 630 | p0->lowspeed = (lowspeed) ? true : false; |
kotakku | 0:b1ce54272580 | 631 | |
kotakku | 0:b1ce54272580 | 632 | // Allocate new address according to device class |
kotakku | 0:b1ce54272580 | 633 | uint8_t bAddress = addrPool.AllocAddress(parent, false, port); |
kotakku | 0:b1ce54272580 | 634 | |
kotakku | 0:b1ce54272580 | 635 | if (!bAddress) |
kotakku | 0:b1ce54272580 | 636 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; |
kotakku | 0:b1ce54272580 | 637 | |
kotakku | 0:b1ce54272580 | 638 | p = addrPool.GetUsbDevicePtr(bAddress); |
kotakku | 0:b1ce54272580 | 639 | |
kotakku | 0:b1ce54272580 | 640 | if (!p) |
kotakku | 0:b1ce54272580 | 641 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 642 | |
kotakku | 0:b1ce54272580 | 643 | p->lowspeed = lowspeed; |
kotakku | 0:b1ce54272580 | 644 | |
kotakku | 0:b1ce54272580 | 645 | // Assign new address to the device |
kotakku | 0:b1ce54272580 | 646 | rcode = setAddr(0, 0, bAddress); |
kotakku | 0:b1ce54272580 | 647 | |
kotakku | 0:b1ce54272580 | 648 | if (rcode) |
kotakku | 0:b1ce54272580 | 649 | { |
kotakku | 0:b1ce54272580 | 650 | addrPool.FreeAddress(bAddress); |
kotakku | 0:b1ce54272580 | 651 | bAddress = 0; |
kotakku | 0:b1ce54272580 | 652 | return rcode; |
kotakku | 0:b1ce54272580 | 653 | } |
kotakku | 0:b1ce54272580 | 654 | return 0; |
kotakku | 0:b1ce54272580 | 655 | }; |
kotakku | 0:b1ce54272580 | 656 | |
kotakku | 0:b1ce54272580 | 657 | uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) |
kotakku | 0:b1ce54272580 | 658 | { |
kotakku | 0:b1ce54272580 | 659 | //DEBUG("AttemptConfig: parent = %i, port = %i\r\n", parent, port); |
kotakku | 0:b1ce54272580 | 660 | uint8_t retries = 0; |
kotakku | 0:b1ce54272580 | 661 | |
kotakku | 0:b1ce54272580 | 662 | again: |
kotakku | 0:b1ce54272580 | 663 | uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed); |
kotakku | 0:b1ce54272580 | 664 | if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) |
kotakku | 0:b1ce54272580 | 665 | { |
kotakku | 0:b1ce54272580 | 666 | if (parent == 0) |
kotakku | 0:b1ce54272580 | 667 | { |
kotakku | 0:b1ce54272580 | 668 | // Send a bus reset on the root interface. |
kotakku | 0:b1ce54272580 | 669 | regWr(rHCTL, bmBUSRST); //issue bus reset |
kotakku | 0:b1ce54272580 | 670 | delay(102); // delay 102ms, compensate for clock inaccuracy. |
kotakku | 0:b1ce54272580 | 671 | } |
kotakku | 0:b1ce54272580 | 672 | else |
kotakku | 0:b1ce54272580 | 673 | { |
kotakku | 0:b1ce54272580 | 674 | // reset parent port |
kotakku | 0:b1ce54272580 | 675 | devConfig[parent]->ResetHubPort(port); |
kotakku | 0:b1ce54272580 | 676 | } |
kotakku | 0:b1ce54272580 | 677 | } |
kotakku | 0:b1ce54272580 | 678 | else if (rcode == hrJERR && retries < 3) |
kotakku | 0:b1ce54272580 | 679 | { // Some devices returns this when plugged in - trying to initialize the device again usually works |
kotakku | 0:b1ce54272580 | 680 | delay(100); |
kotakku | 0:b1ce54272580 | 681 | retries++; |
kotakku | 0:b1ce54272580 | 682 | goto again; |
kotakku | 0:b1ce54272580 | 683 | } |
kotakku | 0:b1ce54272580 | 684 | else if (rcode) |
kotakku | 0:b1ce54272580 | 685 | return rcode; |
kotakku | 0:b1ce54272580 | 686 | |
kotakku | 0:b1ce54272580 | 687 | rcode = devConfig[driver]->Init(parent, port, lowspeed); |
kotakku | 0:b1ce54272580 | 688 | if (rcode == hrJERR && retries < 3) |
kotakku | 0:b1ce54272580 | 689 | { // Some devices returns this when plugged in - trying to initialize the device again usually works |
kotakku | 0:b1ce54272580 | 690 | delay(100); |
kotakku | 0:b1ce54272580 | 691 | retries++; |
kotakku | 0:b1ce54272580 | 692 | goto again; |
kotakku | 0:b1ce54272580 | 693 | } |
kotakku | 0:b1ce54272580 | 694 | if (rcode) |
kotakku | 0:b1ce54272580 | 695 | { |
kotakku | 0:b1ce54272580 | 696 | // Issue a bus reset, because the device may be in a limbo state |
kotakku | 0:b1ce54272580 | 697 | if (parent == 0) |
kotakku | 0:b1ce54272580 | 698 | { |
kotakku | 0:b1ce54272580 | 699 | // Send a bus reset on the root interface. |
kotakku | 0:b1ce54272580 | 700 | regWr(rHCTL, bmBUSRST); //issue bus reset |
kotakku | 0:b1ce54272580 | 701 | delay(102); // delay 102ms, compensate for clock inaccuracy. |
kotakku | 0:b1ce54272580 | 702 | } |
kotakku | 0:b1ce54272580 | 703 | else |
kotakku | 0:b1ce54272580 | 704 | { |
kotakku | 0:b1ce54272580 | 705 | // reset parent port |
kotakku | 0:b1ce54272580 | 706 | devConfig[parent]->ResetHubPort(port); |
kotakku | 0:b1ce54272580 | 707 | } |
kotakku | 0:b1ce54272580 | 708 | } |
kotakku | 0:b1ce54272580 | 709 | return rcode; |
kotakku | 0:b1ce54272580 | 710 | } |
kotakku | 0:b1ce54272580 | 711 | |
kotakku | 0:b1ce54272580 | 712 | /* |
kotakku | 0:b1ce54272580 | 713 | * This is broken. We need to enumerate differently. |
kotakku | 0:b1ce54272580 | 714 | * It causes major problems with several devices if detected in an unexpected order. |
kotakku | 0:b1ce54272580 | 715 | * |
kotakku | 0:b1ce54272580 | 716 | * |
kotakku | 0:b1ce54272580 | 717 | * Oleg - I wouldn't do anything before the newly connected device is considered sane. |
kotakku | 0:b1ce54272580 | 718 | * i.e.(delays are not indicated for brevity): |
kotakku | 0:b1ce54272580 | 719 | * 1. reset |
kotakku | 0:b1ce54272580 | 720 | * 2. GetDevDescr(); |
kotakku | 0:b1ce54272580 | 721 | * 3a. If ACK, continue with allocating address, addressing, etc. |
kotakku | 0:b1ce54272580 | 722 | * 3b. Else reset again, count resets, stop at some number (5?). |
kotakku | 0:b1ce54272580 | 723 | * 4. When max.number of resets is reached, toggle power/fail |
kotakku | 0:b1ce54272580 | 724 | * If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD() |
kotakku | 0:b1ce54272580 | 725 | * it doesn't need to be reset again |
kotakku | 0:b1ce54272580 | 726 | * New steps proposal: |
kotakku | 0:b1ce54272580 | 727 | * 1: get address pool instance. exit on fail |
kotakku | 0:b1ce54272580 | 728 | * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail. |
kotakku | 0:b1ce54272580 | 729 | * 3: bus reset, 100ms delay |
kotakku | 0:b1ce54272580 | 730 | * 4: set address |
kotakku | 0:b1ce54272580 | 731 | * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail |
kotakku | 0:b1ce54272580 | 732 | * 6: while (configurations) { |
kotakku | 0:b1ce54272580 | 733 | * for(each configuration) { |
kotakku | 0:b1ce54272580 | 734 | * for (each driver) { |
kotakku | 0:b1ce54272580 | 735 | * 6a: Ask device if it likes configuration. Returns 0 on OK. |
kotakku | 0:b1ce54272580 | 736 | * If successful, the driver configured device. |
kotakku | 0:b1ce54272580 | 737 | * The driver now owns the endpoints, and takes over managing them. |
kotakku | 0:b1ce54272580 | 738 | * The following will need codes: |
kotakku | 0:b1ce54272580 | 739 | * Everything went well, instance consumed, exit with success. |
kotakku | 0:b1ce54272580 | 740 | * Instance already in use, ignore it, try next driver. |
kotakku | 0:b1ce54272580 | 741 | * Not a supported device, ignore it, try next driver. |
kotakku | 0:b1ce54272580 | 742 | * Not a supported configuration for this device, ignore it, try next driver. |
kotakku | 0:b1ce54272580 | 743 | * Could not configure device, fatal, exit with fail. |
kotakku | 0:b1ce54272580 | 744 | * } |
kotakku | 0:b1ce54272580 | 745 | * } |
kotakku | 0:b1ce54272580 | 746 | * } |
kotakku | 0:b1ce54272580 | 747 | * 7: for(each driver) { |
kotakku | 0:b1ce54272580 | 748 | * 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID |
kotakku | 0:b1ce54272580 | 749 | * 8: if we get here, no driver likes the device plugged in, so exit failure. |
kotakku | 0:b1ce54272580 | 750 | * |
kotakku | 0:b1ce54272580 | 751 | */ |
kotakku | 0:b1ce54272580 | 752 | uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) |
kotakku | 0:b1ce54272580 | 753 | { |
kotakku | 0:b1ce54272580 | 754 | //uint8_t bAddress = 0; |
kotakku | 0:b1ce54272580 | 755 | //DEBUG("Configuring: parent = %i, port = %i\r\n", parent, port); |
kotakku | 0:b1ce54272580 | 756 | uint8_t devConfigIndex; |
kotakku | 0:b1ce54272580 | 757 | uint8_t rcode = 0; |
kotakku | 0:b1ce54272580 | 758 | uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)]; |
kotakku | 0:b1ce54272580 | 759 | USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf); |
kotakku | 0:b1ce54272580 | 760 | UsbDevice *p = NULL; |
kotakku | 0:b1ce54272580 | 761 | EpInfo *oldep_ptr = NULL; |
kotakku | 0:b1ce54272580 | 762 | EpInfo epInfo; |
kotakku | 0:b1ce54272580 | 763 | |
kotakku | 0:b1ce54272580 | 764 | epInfo.epAddr = 0; |
kotakku | 0:b1ce54272580 | 765 | epInfo.maxPktSize = 8; |
kotakku | 0:b1ce54272580 | 766 | epInfo.bmSndToggle = 0; |
kotakku | 0:b1ce54272580 | 767 | epInfo.bmRcvToggle = 0; |
kotakku | 0:b1ce54272580 | 768 | epInfo.bmNakPower = USB_NAK_MAX_POWER; |
kotakku | 0:b1ce54272580 | 769 | |
kotakku | 0:b1ce54272580 | 770 | //delay(2000); |
kotakku | 0:b1ce54272580 | 771 | AddressPool &addrPool = GetAddressPool(); |
kotakku | 0:b1ce54272580 | 772 | // Get pointer to pseudo device with address 0 assigned |
kotakku | 0:b1ce54272580 | 773 | p = addrPool.GetUsbDevicePtr(0); |
kotakku | 0:b1ce54272580 | 774 | if (!p) |
kotakku | 0:b1ce54272580 | 775 | { |
kotakku | 0:b1ce54272580 | 776 | //DEBUG("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n"); |
kotakku | 0:b1ce54272580 | 777 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 778 | } |
kotakku | 0:b1ce54272580 | 779 | |
kotakku | 0:b1ce54272580 | 780 | // Save old pointer to EP_RECORD of address 0 |
kotakku | 0:b1ce54272580 | 781 | oldep_ptr = p->epinfo; |
kotakku | 0:b1ce54272580 | 782 | |
kotakku | 0:b1ce54272580 | 783 | // Temporary assign new pointer to epInfo to p->epinfo in order to |
kotakku | 0:b1ce54272580 | 784 | // avoid toggle inconsistence |
kotakku | 0:b1ce54272580 | 785 | |
kotakku | 0:b1ce54272580 | 786 | p->epinfo = &epInfo; |
kotakku | 0:b1ce54272580 | 787 | |
kotakku | 0:b1ce54272580 | 788 | p->lowspeed = lowspeed; |
kotakku | 0:b1ce54272580 | 789 | // Get device descriptor |
kotakku | 0:b1ce54272580 | 790 | rcode = getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t *)buf); |
kotakku | 0:b1ce54272580 | 791 | |
kotakku | 0:b1ce54272580 | 792 | // Restore p->epinfo |
kotakku | 0:b1ce54272580 | 793 | p->epinfo = oldep_ptr; |
kotakku | 0:b1ce54272580 | 794 | |
kotakku | 0:b1ce54272580 | 795 | if (rcode) |
kotakku | 0:b1ce54272580 | 796 | { |
kotakku | 0:b1ce54272580 | 797 | //DEBUG("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n"); |
kotakku | 0:b1ce54272580 | 798 | return rcode; |
kotakku | 0:b1ce54272580 | 799 | } |
kotakku | 0:b1ce54272580 | 800 | |
kotakku | 0:b1ce54272580 | 801 | // to-do? |
kotakku | 0:b1ce54272580 | 802 | // Allocate new address according to device class |
kotakku | 0:b1ce54272580 | 803 | //bAddress = addrPool.AllocAddress(parent, false, port); |
kotakku | 0:b1ce54272580 | 804 | |
kotakku | 0:b1ce54272580 | 805 | uint16_t vid = udd->idVendor; |
kotakku | 0:b1ce54272580 | 806 | uint16_t pid = udd->idProduct; |
kotakku | 0:b1ce54272580 | 807 | uint8_t klass = udd->bDeviceClass; |
kotakku | 0:b1ce54272580 | 808 | uint8_t subklass = udd->bDeviceSubClass; |
kotakku | 0:b1ce54272580 | 809 | // Attempt to configure if VID/PID or device class matches with a driver |
kotakku | 0:b1ce54272580 | 810 | // Qualify with subclass too. |
kotakku | 0:b1ce54272580 | 811 | // |
kotakku | 0:b1ce54272580 | 812 | // VID/PID & class tests default to false for drivers not yet ported |
kotakku | 0:b1ce54272580 | 813 | // subclass defaults to true, so you don't have to define it if you don't have to. |
kotakku | 0:b1ce54272580 | 814 | // |
kotakku | 0:b1ce54272580 | 815 | for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) |
kotakku | 0:b1ce54272580 | 816 | { |
kotakku | 0:b1ce54272580 | 817 | if (!devConfig[devConfigIndex]) |
kotakku | 0:b1ce54272580 | 818 | continue; // no driver |
kotakku | 0:b1ce54272580 | 819 | if (devConfig[devConfigIndex]->GetAddress()) |
kotakku | 0:b1ce54272580 | 820 | continue; // consumed |
kotakku | 0:b1ce54272580 | 821 | if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) |
kotakku | 0:b1ce54272580 | 822 | { |
kotakku | 0:b1ce54272580 | 823 | rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); |
kotakku | 0:b1ce54272580 | 824 | if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED) |
kotakku | 0:b1ce54272580 | 825 | break; |
kotakku | 0:b1ce54272580 | 826 | } |
kotakku | 0:b1ce54272580 | 827 | } |
kotakku | 0:b1ce54272580 | 828 | |
kotakku | 0:b1ce54272580 | 829 | if (devConfigIndex < USB_NUMDEVICES) |
kotakku | 0:b1ce54272580 | 830 | { |
kotakku | 0:b1ce54272580 | 831 | return rcode; |
kotakku | 0:b1ce54272580 | 832 | } |
kotakku | 0:b1ce54272580 | 833 | |
kotakku | 0:b1ce54272580 | 834 | // blindly attempt to configure |
kotakku | 0:b1ce54272580 | 835 | for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) |
kotakku | 0:b1ce54272580 | 836 | { |
kotakku | 0:b1ce54272580 | 837 | if (!devConfig[devConfigIndex]) |
kotakku | 0:b1ce54272580 | 838 | continue; |
kotakku | 0:b1ce54272580 | 839 | if (devConfig[devConfigIndex]->GetAddress()) |
kotakku | 0:b1ce54272580 | 840 | continue; // consumed |
kotakku | 0:b1ce54272580 | 841 | if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) |
kotakku | 0:b1ce54272580 | 842 | continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above |
kotakku | 0:b1ce54272580 | 843 | rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); |
kotakku | 0:b1ce54272580 | 844 | |
kotakku | 0:b1ce54272580 | 845 | //DEBUG("ERROR ENUMERATING %2.2x\r\n", rcode); |
kotakku | 0:b1ce54272580 | 846 | if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) |
kotakku | 0:b1ce54272580 | 847 | { |
kotakku | 0:b1ce54272580 | 848 | // in case of an error dev_index should be reset to 0 |
kotakku | 0:b1ce54272580 | 849 | // in order to start from the very beginning the |
kotakku | 0:b1ce54272580 | 850 | // next time the program gets here |
kotakku | 0:b1ce54272580 | 851 | //if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) |
kotakku | 0:b1ce54272580 | 852 | // devConfigIndex = 0; |
kotakku | 0:b1ce54272580 | 853 | return rcode; |
kotakku | 0:b1ce54272580 | 854 | } |
kotakku | 0:b1ce54272580 | 855 | } |
kotakku | 0:b1ce54272580 | 856 | // if we get here that means that the device class is not supported by any of registered classes |
kotakku | 0:b1ce54272580 | 857 | rcode = DefaultAddressing(parent, port, lowspeed); |
kotakku | 0:b1ce54272580 | 858 | |
kotakku | 0:b1ce54272580 | 859 | return rcode; |
kotakku | 0:b1ce54272580 | 860 | } |
kotakku | 0:b1ce54272580 | 861 | |
kotakku | 0:b1ce54272580 | 862 | uint8_t USB::ReleaseDevice(uint8_t addr) |
kotakku | 0:b1ce54272580 | 863 | { |
kotakku | 0:b1ce54272580 | 864 | if (!addr) |
kotakku | 0:b1ce54272580 | 865 | return 0; |
kotakku | 0:b1ce54272580 | 866 | |
kotakku | 0:b1ce54272580 | 867 | for (uint8_t i = 0; i < USB_NUMDEVICES; i++) |
kotakku | 0:b1ce54272580 | 868 | { |
kotakku | 0:b1ce54272580 | 869 | if (!devConfig[i]) |
kotakku | 0:b1ce54272580 | 870 | continue; |
kotakku | 0:b1ce54272580 | 871 | if (devConfig[i]->GetAddress() == addr) |
kotakku | 0:b1ce54272580 | 872 | return devConfig[i]->Release(); |
kotakku | 0:b1ce54272580 | 873 | } |
kotakku | 0:b1ce54272580 | 874 | return 0; |
kotakku | 0:b1ce54272580 | 875 | } |
kotakku | 0:b1ce54272580 | 876 | |
kotakku | 0:b1ce54272580 | 877 | #if 1 //!defined(USB_METHODS_INLINE) |
kotakku | 0:b1ce54272580 | 878 | //get device descriptor |
kotakku | 0:b1ce54272580 | 879 | |
kotakku | 0:b1ce54272580 | 880 | uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr) |
kotakku | 0:b1ce54272580 | 881 | { |
kotakku | 0:b1ce54272580 | 882 | return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL)); |
kotakku | 0:b1ce54272580 | 883 | } |
kotakku | 0:b1ce54272580 | 884 | //get configuration descriptor |
kotakku | 0:b1ce54272580 | 885 | |
kotakku | 0:b1ce54272580 | 886 | uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr) |
kotakku | 0:b1ce54272580 | 887 | { |
kotakku | 0:b1ce54272580 | 888 | return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL)); |
kotakku | 0:b1ce54272580 | 889 | } |
kotakku | 0:b1ce54272580 | 890 | |
kotakku | 0:b1ce54272580 | 891 | /* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this |
kotakku | 0:b1ce54272580 | 892 | total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */ |
kotakku | 0:b1ce54272580 | 893 | uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) |
kotakku | 0:b1ce54272580 | 894 | { |
kotakku | 0:b1ce54272580 | 895 | const uint8_t bufSize = 64; |
kotakku | 0:b1ce54272580 | 896 | uint8_t buf[bufSize]; |
kotakku | 0:b1ce54272580 | 897 | USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf); |
kotakku | 0:b1ce54272580 | 898 | |
kotakku | 0:b1ce54272580 | 899 | uint8_t ret = getConfDescr(addr, ep, 9, conf, buf); |
kotakku | 0:b1ce54272580 | 900 | |
kotakku | 0:b1ce54272580 | 901 | if (ret) |
kotakku | 0:b1ce54272580 | 902 | return ret; |
kotakku | 0:b1ce54272580 | 903 | |
kotakku | 0:b1ce54272580 | 904 | uint16_t total = ucd->wTotalLength; |
kotakku | 0:b1ce54272580 | 905 | |
kotakku | 0:b1ce54272580 | 906 | //USBTRACE2("\r\ntotal conf.size:", total); |
kotakku | 0:b1ce54272580 | 907 | |
kotakku | 0:b1ce54272580 | 908 | return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p)); |
kotakku | 0:b1ce54272580 | 909 | } |
kotakku | 0:b1ce54272580 | 910 | |
kotakku | 0:b1ce54272580 | 911 | //get string descriptor |
kotakku | 0:b1ce54272580 | 912 | |
kotakku | 0:b1ce54272580 | 913 | uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t *dataptr) |
kotakku | 0:b1ce54272580 | 914 | { |
kotakku | 0:b1ce54272580 | 915 | return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL)); |
kotakku | 0:b1ce54272580 | 916 | } |
kotakku | 0:b1ce54272580 | 917 | //set address |
kotakku | 0:b1ce54272580 | 918 | |
kotakku | 0:b1ce54272580 | 919 | uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) |
kotakku | 0:b1ce54272580 | 920 | { |
kotakku | 0:b1ce54272580 | 921 | uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL); |
kotakku | 0:b1ce54272580 | 922 | //delay(2); //per USB 2.0 sect.9.2.6.3 |
kotakku | 0:b1ce54272580 | 923 | delay(300); // Older spec says you should wait at least 200ms |
kotakku | 0:b1ce54272580 | 924 | return rcode; |
kotakku | 0:b1ce54272580 | 925 | //return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL)); |
kotakku | 0:b1ce54272580 | 926 | } |
kotakku | 0:b1ce54272580 | 927 | //set configuration |
kotakku | 0:b1ce54272580 | 928 | |
kotakku | 0:b1ce54272580 | 929 | uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) |
kotakku | 0:b1ce54272580 | 930 | { |
kotakku | 0:b1ce54272580 | 931 | return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL)); |
kotakku | 0:b1ce54272580 | 932 | } |
kotakku | 0:b1ce54272580 | 933 | |
kotakku | 0:b1ce54272580 | 934 | #endif // defined(USB_METHODS_INLINE) |