Fork of [[https://os.mbed.com/users/va009039/code/F401RE-USBHost/]]. Added support for Seeed Arch Max and STM32F407.
Dependents: STM32F407VET6_USBHostMSD STM32F407VET6_USBHostMouse STM32F407VET6_USBHostKeyboard STM32F407VET6_USBHostMSD_1
Revision 0:458bf947f46f, committed 2019-02-19
- Comitter:
- hudakz
- Date:
- Tue Feb 19 21:32:56 2019 +0000
- Commit message:
- Fork of [[https://os.mbed.com/users/va009039/code/F401RE-USBHost/]]. Added support for Seeed Arch Max and STM32F407.
Changed in this revision
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/IUSBEnumerator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/IUSBEnumerator.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,36 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IUSBENUMERATOR_H_ +#define IUSBENUMERATOR_H_ + +#include "stdint.h" +#include "USBEndpoint.h" + +/* +Generic interface to implement for "smart" USB enumeration +*/ + +class IUSBEnumerator +{ +public: + virtual void setVidPid(uint16_t vid, uint16_t pid) = 0; + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used +}; + +#endif /*IUSBENUMERATOR_H_*/ +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBDeviceConnected.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBDeviceConnected.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,89 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBDeviceConnected.h" +#include "dbg.h" + +USBDeviceConnected::USBDeviceConnected() { + init(); +} + +void USBDeviceConnected::init() { + port = 0; + vid = 0; + pid = 0; + nb_interf = 0; + enumerated = false; + device_class = 0; + device_subclass = 0; + proto = 0; + lowSpeed = false; + hub_parent = NULL; +} + +bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) { + USB_DBG("intf_nb=%d", intf_nb); + if (intf.count(intf_nb) > 0) { + return false; + } + intf[intf_nb] = new INTERFACE(intf_class, intf_subclass, intf_protocol); + return true; +} + +bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) { + if (intf.count(intf_nb) > 0) { + intf[intf_nb]->ep.push_back(ept); + return true; + } + return false; +} + +void USBDeviceConnected::init(USBDeviceConnected* parent, uint8_t port_, bool lowSpeed_) { + USB_DBG("init dev: %p", this); + init(); + hub_parent = parent; + port = port_; + lowSpeed = lowSpeed_; +} + +void USBDeviceConnected::disconnect() { + //for(int i = 0; i < MAX_INTF; i++) { + // intf[i].detach.call(); + //} + //init(); +} + + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) { + USB_DBG("intf_nb=%d", intf_nb); + USB_TEST_ASSERT(intf.count(intf_nb) > 0); + INTERFACE* inter = intf[intf_nb]; + for (int i = 0; i < inter->ep.size(); i++) { + if ((inter->ep[i]->getType() == type) && (inter->ep[i]->getDir() == dir)) { + if(index) { + index--; + } else { + return inter->ep[i]; + } + } + } + return NULL; +} + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) { + USB_TEST_ASSERT(intf.count(intf_nb) > 0); + return intf[intf_nb]->ep[index]; +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBDeviceConnected.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBDeviceConnected.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,133 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "USBEndpoint.h" +#include "USBHostConf.h" +#include "myvector.h" +#include "mymap.h" + +class USBEndpoint; + +struct INTERFACE { + INTERFACE(uint8_t _class, uint8_t _subclass, uint8_t _protocol) { + intf_class = _class; + intf_subclass = _subclass; + intf_protocol = _protocol; + } + uint8_t intf_class; + uint8_t intf_subclass; + uint8_t intf_protocol; + myvector<USBEndpoint*>ep; +}; + +/** +* USBDeviceConnected class +*/ +class USBDeviceConnected { +public: + + /** + * Constructor + */ + USBDeviceConnected(); + + /** + * Attach an USBEndpoint to this device + * + * @param intf_nb interface number + * @param ep pointeur on the USBEndpoint which will be attached + * @returns true if successful, false otherwise + */ + bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep); + + /** + * Retrieve an USBEndpoint by its TYPE and DIRECTION + * + * @param intf_nb the interface on which to lookup the USBEndpoint + * @param type type of the USBEndpoint looked for + * @param dir direction of the USBEndpoint looked for + * @param index the index of the USBEndpoint whitin the interface + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0); + + /** + * Retrieve an USBEndpoint by its index + * + * @param intf_nb interface number + * @param index index of the USBEndpoint + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index); + + /** + * Add a new interface to this device + * + * @param intf_nb interface number + * @param intf_class interface class + * @param intf_subclass interface subclass + * @param intf_protocol interface protocol + * @returns true if successful, false otherwise + */ + bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); + + /** + * Disconnect the device by calling a callback function registered by a driver + */ + void disconnect(); + + void init(USBDeviceConnected* parent, uint8_t _port, bool _lowSpeed); + void setAddress(uint8_t addr_) { addr = addr_; }; + void setVid(uint16_t vid_) { vid = vid_; }; + void setPid(uint16_t pid_) { pid = pid_; }; + void setClass(uint8_t device_class_) { device_class = device_class_; } + void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; }; + void setProtocol(uint8_t pr) { proto = pr; }; + void setEnumerated() { enumerated = true; }; + void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; }; + void setSpeed(bool _lowSpeed) { lowSpeed = _lowSpeed; } + void setName(const char * name_, uint8_t intf_nb) { return; }; + void setEpCtl(USBEndpoint* ep) { ep_ctl = ep; } + + static int getNewAddress() { + static int addr = 1; + return addr++; + } + uint8_t getAddress() { return addr; }; + uint16_t getVid() { return vid; }; + uint16_t getPid() { return pid; }; + uint8_t getClass() { return device_class; }; + bool getSpeed() { return lowSpeed; } + bool isEnumerated() { return enumerated; }; + USBEndpoint* getEpCtl() { return ep_ctl; } + +private: + USBDeviceConnected* hub_parent; + mymap<int,INTERFACE*>intf; + uint8_t port; + uint16_t vid; + uint16_t pid; + uint8_t addr; + uint8_t device_class; + uint8_t device_subclass; + uint8_t proto; + bool lowSpeed; + bool enumerated; + uint8_t nb_interf; + USBEndpoint* ep_ctl; + void init(); +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBEndpoint.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBEndpoint.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,167 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "FunctionPointer.h" +#include "USBHostTypes.h" +#include "USBDeviceConnected.h" + +class USBDeviceConnected; + +/** +* USBEndpoint class +*/ +class USBEndpoint { +public: + /** + * Constructor + */ + USBEndpoint(USBDeviceConnected* _dev) { + init(CONTROL_ENDPOINT, IN, 8, 0); + dev = _dev; + pData = NULL; + } + + /** + * Initialize an endpoint + * + * @param type endpoint type + * @param dir endpoint direction + * @param size endpoint size + * @param ep_number endpoint number + */ + void init(ENDPOINT_TYPE _type, ENDPOINT_DIRECTION _dir, uint32_t size, uint8_t ep_number) { + setState(USB_TYPE_FREE); + setType(_type); + dir = _dir; + MaxPacketSize = size; + address = ep_number; + data01_toggle = DATA0; + } + + void ohci_init(uint8_t frameCount, uint8_t queueLimit) { + ohci.frameCount = frameCount; + ohci.queueLimit = queueLimit; + } + + /** + * Attach a member function to call when a transfer is finished + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + inline void attach(T* tptr, void (T::*mptr)(void)) { + if((mptr != NULL) && (tptr != NULL)) { + rx.attach(tptr, mptr); + } + } + + /** + * Attach a callback called when a transfer is finished + * + * @param fptr function pointer + */ + inline void attach(void (*fptr)(void)) { + if(fptr != NULL) { + rx.attach(fptr); + } + } + + /** + * Call the handler associted to the end of a transfer + */ + inline void call() { + rx.call(); + }; + + void setType(ENDPOINT_TYPE _type) { type = _type; } + void setState(USB_TYPE st) { state = st; } + void setDevice(USBDeviceConnected* _dev) { dev = _dev; } + void setBuffer(uint8_t* buf, int size) { buf_start = buf, buf_size = size; } + void setLengthTransferred(int len) { transferred = len; }; + void setAddress(int addr) { address = addr; } + void setSize(int size) { MaxPacketSize = size; } + void setData01(uint8_t data01) { data01_toggle = data01; } + void setNextEndpoint(USBEndpoint* ep) { nextEp = ep; }; + template<class T> + void setHALData(T data) { pData = data; } + + USBDeviceConnected* getDevice() { return dev; } + ENDPOINT_TYPE getType() { return type; }; + USB_TYPE getState() { return state; } + int getLengthTransferred() { return transferred; } + uint8_t *getBufStart() { return buf_start; } + int getBufSize() { return buf_size; } + uint8_t getAddress(){ return address; }; + int getSize() { return MaxPacketSize; } + ENDPOINT_DIRECTION getDir() { return dir; } + uint8_t getData01() { return data01_toggle; } + void toggleData01() { + data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0; + } + USBEndpoint* nextEndpoint() { return nextEp; }; + template<class T> + T getHALData() { return reinterpret_cast<T>(pData); } + + struct { + uint8_t queueLimit; + uint8_t frameCount; // 1-8 + } ohci; +private: + USBEndpoint(){} + ENDPOINT_TYPE type; + USB_TYPE state; + ENDPOINT_DIRECTION dir; + USBDeviceConnected* dev; + uint8_t data01_toggle; // DATA0,DATA1 + uint8_t address; + int transferred; + uint8_t * buf_start; + int buf_size; + FunctionPointer rx; + int MaxPacketSize; + USBEndpoint* nextEp; + void* pData; +}; + +class EndpointQueue { +public: + EndpointQueue():head(NULL),tail(NULL) {} + void push(USBEndpoint* ep) { + if (head) { + tail->setNextEndpoint(ep); + } else { + head = ep; + } + tail = ep; + ep->setNextEndpoint(NULL); + } + USBEndpoint* pop() { + USBEndpoint* ep = head; + if (ep) { + head = ep->nextEndpoint(); + } + return ep; + } + bool empty() { return head == NULL; } + +private: + USBEndpoint* head; + USBEndpoint* tail; +}; + +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,34 @@ +#include "mbed.h" + +struct SETUP_PACKET { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + SETUP_PACKET(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length) { + bmRequestType = RequestType; + bRequest = Request; + wValue = Value; + wIndex = Index; + wLength = Length; + } +}; + +#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX) +#include "USBHALHost_F401RE.h" +#elif defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F) +#include "USBHALHost_KL46Z.h" +#elif defined(TARGET_LPC4088)||defined(TARGET_LPC1768) +#include "USBHALHost_LPC4088.h" +#else +#error "target error" +#endif + +#ifndef CTASSERT +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); +#endif // CTASSERT + +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost2_F401RE.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost2_F401RE.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,16 @@ +#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX) +#include "USBHALHost.h" + +// usbh_conf.c +HCD_HandleTypeDef hhcd_USB_OTG_FS; + +extern "C" { +void OTG_FS_IRQHandler(void) +{ + HAL_NVIC_ClearPendingIRQ(OTG_FS_IRQn); + HAL_HCD_IRQHandler(&hhcd_USB_OTG_FS); +} +} + +#endif +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost2_LPC4088.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost2_LPC4088.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,205 @@ +#if defined(TARGET_LPC4088)||defined(TARGET_LPC1768) +#include "USBHALHost.h" + +#undef USB_TEST_ASSERT +void usb_test_assert_internal(const char *expr, const char *file, int line); +#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); + +//#define DBG_USE_POSIX_MEMALIGN + +#ifdef DBG_USE_POSIX_MEMALIGN +void* usb_ram_malloc(size_t size, int aligment) +{ + TEST_ASSERT(aligment >= 4); + TEST_ASSERT(!(aligment & 3)); + void* p; + if (posix_memalign(&p, aligment, size) == 0) { + return p; + } + return NULL; +} + +void usb_ram_free(void* p) +{ + free(p); +} +#else + +#define CHUNK_SIZE 64 + +#if defined(TARGET_LPC1768) +#define USB_RAM_BASE 0x2007C000 +#define USB_RAM_SIZE 0x4000 +#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE) +#elif defined(TARGET_LPC4088) +#define USB_RAM_BASE 0x20000000 +#define USB_RAM_SIZE 0x4000 +#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE) +#else +#error "target error" +#endif + +static uint8_t* ram = NULL; +static uint8_t* map; + +static void usb_ram_init() +{ + USB_INFO("USB_RAM: 0x%p(%d)", USB_RAM_BASE, USB_RAM_SIZE); + ram = (uint8_t*)USB_RAM_BASE; + USB_TEST_ASSERT((int)ram%256 == 0); + map = (uint8_t*)malloc(BLOCK_COUNT); + USB_TEST_ASSERT(map); + memset(map, 0, BLOCK_COUNT); +} + +// first fit malloc +void* usb_ram_malloc(size_t size, int aligment) +{ + USB_TEST_ASSERT(aligment >= 4); + USB_TEST_ASSERT(!(aligment & 3)); + if (ram == NULL) { + usb_ram_init(); + } + int needs = (size+CHUNK_SIZE-1)/CHUNK_SIZE; + void* p = NULL; + for(int idx = 0; idx < BLOCK_COUNT;) { + bool found = true; + for(int i = 0; i < needs; i++) { + int block = map[idx + i]; + if (block != 0) { + idx += block; + found = false; + break; + } + } + if (!found) { + continue; + } + p = ram+idx*CHUNK_SIZE; + if ((int)p % aligment) { + idx++; + continue; + } + USB_TEST_ASSERT((idx + needs) <= BLOCK_COUNT); + for(int i = 0; i < needs; i++) { + map[idx + i] = needs - i; + } + break; + } + USB_TEST_ASSERT(p); + return p; +} + +void usb_ram_free(void* p) +{ + USB_TEST_ASSERT(p >= ram); + USB_TEST_ASSERT(p < (ram+CHUNK_SIZE*BLOCK_COUNT)); + int idx = ((int)p-(int)ram)/CHUNK_SIZE; + int block = map[idx]; + USB_TEST_ASSERT(block >= 1); + for(int i =0; i < block; i++) { + map[idx + i] = 0; + } +} + +#endif // DBG_USE_POSIX_MEMALIGN + +void print_td(FILE* stream, HCTD* td) +{ + if (td == NULL) { + fprintf(stream, "TD %p:\n", td); + return; + } + uint32_t* p = reinterpret_cast<uint32_t*>(td); + fprintf(stream, "TD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]); + fprintf(stream, " ep=%p\n", td->parent); + uint8_t* bp = reinterpret_cast<uint8_t*>(p[1]); + uint8_t* be = reinterpret_cast<uint8_t*>(p[3]); + if (bp) { + fprintf(stream, "BF %p:", bp); + while(bp <= be) { + fprintf(stream, " %02X", *bp); + bp++; + } + fprintf(stream, "\n"); + } +} + +void print_ed(FILE* stream, HCED* ed) +{ + uint32_t* p = reinterpret_cast<uint32_t*>(ed); + while(p) { + fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]); + HCTD* td = reinterpret_cast<HCTD*>(p[2] & ~3); + HCTD* tdtail = reinterpret_cast<HCTD*>(p[1]); + while(td != NULL && td != tdtail) { + print_td(stream, td); + td = td->Next; + } + p = reinterpret_cast<uint32_t*>(p[3]); + } +} + +void print_itd(FILE* stream, HCITD* itd) +{ + if (itd == NULL) { + fprintf(stream, "ITD %p:\n", itd); + return; + } + uint32_t* p = reinterpret_cast<uint32_t*>(itd); + fprintf(stream, "ITD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]); + fprintf(stream, " ep=%p\n", itd->parent); + uint16_t* offset = reinterpret_cast<uint16_t*>(p+4); + fprintf(stream, "ITD %p: %04X %04X %04X %04X %04X %04X %04X %04X\n", offset, + offset[0], offset[1], offset[2], offset[3], offset[4], offset[5], offset[6], offset[7]); +} + +void print_ied(FILE* stream, HCED* ed) +{ + uint32_t* p = reinterpret_cast<uint32_t*>(ed); + while(p) { + fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]); + HCITD* itd = reinterpret_cast<HCITD*>(p[2] & ~3); + HCITD* itdtail = reinterpret_cast<HCITD*>(p[1]); + while(itd != NULL && itd != itdtail) { + print_itd(stream, itd); + itd = itd->Next; + } + p = reinterpret_cast<uint32_t*>(p[3]); + } +} + +void print_bytes(FILE* stream, char* s, uint8_t* buf, int len) +{ + fprintf(stream, "%s %d:", s, len); + for(int i = 0; i < len; i++) { + fprintf(stream, " %02X", buf[i]); + } + fprintf(stream, "\n"); +} + +void print_hex(FILE* stream, uint8_t* p, int len) +{ + for(int i = 0; i < len; i++) { + if (i%16 == 0) { + fprintf(stream, "%p:", p); + } + fprintf(stream, " %02X", *p); + p++; + if (i%16 == 15) { + fprintf(stream, "\n"); + } + } + fprintf(stream, "\n"); +} + +void assert_print(const char* pf, int line, const char* msg) { + printf("\n\n%s@%d %s ASSERT!\n\n", pf, line, msg); + exit(1); +} + +#endif // defined(TARGET_LPC4088)||defined(TARGET_LPC1768) + +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_F401RE.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_F401RE.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,539 @@ +#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX) +#include "USBHALHost.h" +#include <algorithm> + +#ifdef _USB_DBG +extern RawSerial pc; +//RawSerial pc(USBTX,USBRX); +#include "mydebug.h" +#define USB_DBG(...) do{pc.printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);pc.printf(__VA_ARGS__);pc.puts("\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex<RawSerial>(pc,A,B) + +#else +#define USB_DBG(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#undef USB_TEST_ASSERT +void usb_test_assert_internal(const char *expr, const char *file, int line); +#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} + +#define USB_TRACE1(A) while(0) + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); + +__IO bool attach_done = false; + +void delay_ms(uint32_t t) +{ + HAL_Delay(t); +} + +// usbh_conf.c +extern HCD_HandleTypeDef hhcd_USB_OTG_FS; + +void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + if(hhcd->Instance == USB_OTG_FS) + { + /* + * Configure USB FS GPIOs + * PA11 ------> USB_OTG_FS_DM + * PA12 ------> USB_OTG_FS_DP + */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + + GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* Enable USB FS Clocks */ + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + + /* Set USBFS Interrupt to the lowest priority */ + HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0); + + /* Enable USBFS Interrupt */ + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + +} + +// stm32f4xx_it.c +extern "C" { +void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd) +{ + USB_TRACE1(hhcd); + attach_done = true; +} + +} // extern "C" + +USBHALHost* USBHALHost::instHost; + +USBHALHost::USBHALHost() { + instHost = this; +} + +void USBHALHost::init() { + hhcd_USB_OTG_FS.Instance = USB_OTG_FS; + hhcd_USB_OTG_FS.Init.Host_channels = 8; + hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL; + hhcd_USB_OTG_FS.Init.dma_enable = DISABLE; + hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED; + hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE; + hhcd_USB_OTG_FS.Init.low_power_enable = ENABLE; + hhcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE; + hhcd_USB_OTG_FS.Init.use_external_vbus = DISABLE; + + HAL_HCD_Init(&hhcd_USB_OTG_FS); + HAL_HCD_Start(&hhcd_USB_OTG_FS); + + bool lowSpeed = wait_attach(); + delay_ms(200); + HAL_HCD_ResetPort(&hhcd_USB_OTG_FS); + delay_ms(100); // Wait for 100 ms after Reset + addDevice(NULL, 0, lowSpeed); +} + +bool USBHALHost::wait_attach() { + Timer t; + t.reset(); + t.start(); + while(!attach_done) { + if (t.read_ms() > 5*1000) { + t.reset(); + USB_INFO("Please attach USB device."); + } + } + wait_ms(100); + return HAL_HCD_GetCurrentSpeed(&hhcd_USB_OTG_FS) == USB_OTG_SPEED_LOW; +} + +int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + const uint8_t ep_addr = 0x00; + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init(ep_addr, + dev->getAddress(), + dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL, + EP_TYPE_CTRL, ep->getSize()); + + setup->wLength = wLength; + hc.SubmitRequest((uint8_t*)setup, 8, true); // PID_SETUP + while(hc.GetURBState() == URB_IDLE); + + switch(hc.GetURBState()) { + case URB_DONE: + LastStatus = ACK; + break; + default: + LastStatus = 0xff; + break; + } + ep->setData01(DATA1); + return 8; +} + +int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + switch(ep->getType()) { + case CONTROL_ENDPOINT: + return token_ctl_in(ep, data, size, retryLimit); + case INTERRUPT_ENDPOINT: + return token_int_in(ep, data, size); + case BULK_ENDPOINT: + return token_blk_in(ep, data, size, retryLimit); + } + return -1; +} + +int USBHALHost::token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + const uint8_t ep_addr = 0x80; + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init(ep_addr, + dev->getAddress(), + dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL, + EP_TYPE_CTRL, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + hc.SubmitRequest(data, size); + while(hc.GetURBState() == URB_IDLE); + + switch(hc.GetURBState()) { + case URB_DONE: + LastStatus = ACK; + break; + default: + LastStatus = 0xff; + return -1; + } + ep->toggleData01(); + return hc.GetXferCount(); +} + +int USBHALHost::token_int_in(USBEndpoint* ep, uint8_t* data, int size) { + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init( + ep->getAddress(), + dev->getAddress(), + dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL, + EP_TYPE_INTR, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + hc.SubmitRequest(data, size); + //while(hc.GetURBState() == URB_IDLE); + wait_ms(2); + switch(hc.GetURBState()) { + case URB_DONE: + switch(hc.GetState()) { + case HC_XFRC: + LastStatus = ep->getData01(); + ep->toggleData01(); + return hc.GetXferCount(); + case HC_NAK: + LastStatus = NAK; + return -1; + } + break; + } + LastStatus = STALL; + return -1; +} + +int USBHALHost::token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init( + ep->getAddress(), + dev->getAddress(), + HCD_SPEED_FULL, + EP_TYPE_BULK, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + int retry = 0; + do { + hc.SubmitRequest(data, size); + while(hc.GetURBState() == URB_IDLE); + + switch(hc.GetURBState()) { + case URB_DONE: + switch(hc.GetState()) { + case HC_XFRC: + LastStatus = ep->getData01(); + ep->toggleData01(); + return hc.GetXferCount(); + case HC_NAK: + LastStatus = NAK; + if (retryLimit > 0) { + delay_ms(1 + 10 * retry); + } + break; + default: + break; + } + break; + case URB_STALL: + LastStatus = STALL; + return -1; + default: + LastStatus = STALL; + delay_ms(500 + 100 * retry); + break; + } + }while(retry++ < retryLimit); + return -1; +} + +int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + switch(ep->getType()) { + case CONTROL_ENDPOINT: + return token_ctl_out(ep, data, size, retryLimit); + case INTERRUPT_ENDPOINT: + return token_int_out(ep, data, size); + case BULK_ENDPOINT: + return token_blk_out(ep, data, size, retryLimit); + } + return -1; +} + +int USBHALHost::token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + const uint8_t ep_addr = 0x00; + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init(ep_addr, + dev->getAddress(), + dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL, + EP_TYPE_CTRL, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + do { + hc.SubmitRequest((uint8_t*)data, size); + while(hc.GetURBState() == URB_IDLE); + + switch(hc.GetURBState()) { + case URB_DONE: + LastStatus = ACK; + ep->toggleData01(); + return size; + + default: + break; + } + delay_ms(1); + }while(retryLimit-- > 0); + return -1; +} + +int USBHALHost::token_int_out(USBEndpoint* ep, const uint8_t* data, int size) { + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init( + ep->getAddress(), + dev->getAddress(), + dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL, + EP_TYPE_INTR, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + hc.SubmitRequest((uint8_t*)data, size); + while(hc.GetURBState() == URB_IDLE); + if (hc.GetURBState() != URB_DONE) { + return -1; + } + ep->toggleData01(); + return size; +} + +int USBHALHost::token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + HC hc; + USBDeviceConnected* dev = ep->getDevice(); + hc.Init( + ep->getAddress(), dev->getAddress(), + HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize()); + + hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1); + + int retry = 0; + do { + hc.SubmitRequest((uint8_t*)data, size); + while(hc.GetURBState() == URB_IDLE); + + switch(hc.GetURBState()) { + case URB_DONE: + switch(hc.GetState()) { + case HC_XFRC: // ACK + LastStatus = ep->getData01(); + ep->toggleData01(); + return size; + default: + break; + } + break; + case URB_NOTREADY: // HC_NAK + LastStatus = NAK; + delay_ms(100 * retry); + break; + default: + LastStatus = STALL; + return -1; + } + } while(retry++ < retryLimit); + return -1; +} + +int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { + HC* hc = ep->getHALData<HC*>(); + if (hc == NULL) { + hc = new HC; + ep->setHALData<HC*>(hc); + USBDeviceConnected* dev = ep->getDevice(); + hc->Init( + ep->getAddress(), dev->getAddress(), + HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize()); + } + hc->SubmitRequest(data, size); + while(hc->GetURBState() == URB_IDLE); + return hc->GetXferCount(); +} + +int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block) { + if (total == 0) { + return token_in(ep); + } + int retryLimit = block ? 10 : 0; + int read_len = 0; + for(int n = 0; read_len < total; n++) { + int size = std::min((int)total-read_len, ep->getSize()); + int result = token_in(ep, data+read_len, size, retryLimit); + if (result < 0) { + if (block) { + return -1; + } + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + return result; + } + read_len += result; + if (result < ep->getSize()) { + break; + } + } + return read_len; +} + +int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total) { + if (total == 0) { + return token_out(ep); + } + int write_len = 0; + for(int n = 0; write_len < total; n++) { + int size = std::min((int)total-write_len, ep->getSize()); + int result = token_out(ep, data+write_len, size); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_out result=%d %02x", result, LastStatus); + return result; + } + write_len += result; + if (result < ep->getSize()) { + break; + } + } + return write_len; +} +void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) { + USB_TRACE1(size); + USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING); + ep->setBuffer(data, size); + ep->setState(USB_TYPE_PROCESSING); +} + +USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) { + USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING); + uint8_t* buf = ep->getBufStart(); + int size = ep->getBufSize(); + int result = multi_token_in(ep, buf, size, false); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_PROCESSING; + } + ep->setLengthTransferred(result); + ep->setState(USB_TYPE_IDLE); + return USB_TYPE_OK; + +} + +void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) { + USB_TEST_ASSERT(toggle == 1); + ep->setData01(toggle == 0 ? DATA0 : DATA1); +} + +uint8_t HC::slot = 0x00; + +HC::HC() { + static const int start = 1; + uint8_t mask = (1<<start); + for(int i = start; i < 8; i++, mask <<= 1) { + if (!(slot & mask)) { + slot |= mask; + _ch = i; + return; + } + } + _ch = 0; // ERROR!!! +} + +HC::HC(int ch) { + _ch = ch; + slot |= (1<<_ch); +} + +HC::~HC() { + slot &= ~(1<<_ch); +} + +HAL_StatusTypeDef HC::Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps) { + _ep_addr = epnum; + _ep_type = ep_type; + return HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, _ch, + epnum, dev_address, speed, ep_type, mps); +} + +HAL_StatusTypeDef HC::SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup) { + uint8_t direction = (_ep_addr & 0x80) ? DIR_IN : DIR_OUT; + if (_ep_type == EP_TYPE_CTRL) { + HCD_HCTypeDef* hc = &hhcd_USB_OTG_FS.hc[_ch]; + if (setup) { + hc->data_pid = HC_PID_SETUP; + hc->toggle_out = 0; + } else { + if (direction == DIR_IN) { + if (hc->toggle_in == 0) { + hc->data_pid = HC_PID_DATA0; + } else { + hc->data_pid = HC_PID_DATA1; + } + } else { // OUT + if (hc->toggle_out == 0) { + hc->data_pid = HC_PID_DATA0; + } else { + hc->data_pid = HC_PID_DATA1; + } + } + } + hc->xfer_buff = pbuff; + hc->xfer_len = length; + hc->urb_state = URB_IDLE; + hc->xfer_count = 0; + hc->ch_num = _ch; + hc->state = HC_IDLE; + + return USB_HC_StartXfer(hhcd_USB_OTG_FS.Instance, hc, 0); + } + return HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, _ch, + direction, _ep_type, 0, pbuff, length, 0); +} + +HCD_URBStateTypeDef HC::GetURBState() { + return HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, _ch); +} + +HCD_HCStateTypeDef HC::GetState() { + return HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, _ch); +} + +uint32_t HC::GetXferCount() { + return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, _ch); +} + +void HC::SetToggle(uint8_t toggle) { + if (_ep_addr & 0x80) { // IN + hhcd_USB_OTG_FS.hc[_ch].toggle_in = toggle; + } else { // OUT + hhcd_USB_OTG_FS.hc[_ch].toggle_out = toggle; + } +} + +#endif + +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_F401RE.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_F401RE.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,58 @@ +#pragma once +#include "mbed.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +class HC { + static const uint8_t DIR_IN = 1; + static const uint8_t DIR_OUT = 0; + +public: + HC(); + HC(int ch); + ~HC(); + HAL_StatusTypeDef Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps); + HAL_StatusTypeDef SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup = false); + HCD_URBStateTypeDef GetURBState(); + HCD_HCStateTypeDef GetState(); + uint32_t GetXferCount(); + void SetToggle(uint8_t toggle); + + static uint8_t slot; + +private: + int _ch; + uint8_t _ep_addr; + uint8_t _ep_type; +}; + +class USBHALHost { +public: + uint8_t LastStatus; + uint8_t prev_LastStatus; + +protected: + USBHALHost(); + void init(); + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0; + int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); + int token_iso_in(USBEndpoint* ep, uint8_t* data, int size); + int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, size_t total = 0, bool block = true); + int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, size_t total = 0); + void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size); + USB_TYPE multi_token_inNB_result(USBEndpoint* ep); + void setToggle(USBEndpoint* ep, uint8_t toggle); + +private: + int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit); + int token_int_in(USBEndpoint* ep, uint8_t* data, int size); + int token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit); + int token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit); + int token_int_out(USBEndpoint* ep, const uint8_t* data, int size); + int token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit); + bool wait_attach(); + static USBHALHost * instHost; +}; +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_KL46Z.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_KL46Z.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,520 @@ +// Simple USBHost for FRDM-KL46Z +#if defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F) +#include "USBHALHost.h" +#include <algorithm> + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#undef USB_TEST_ASSERT +extern void usb_test_assert_internal(const char *expr, const char *file, int line); +#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} + +#define USB_TRACE1(A) while(0) + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); + +#define BD_OWN_MASK (1<<7) +#define BD_DATA01_MASK (1<<6) +#define BD_KEEP_MASK (1<<5) +#define BD_NINC_MASK (1<<4) +#define BD_DTS_MASK (1<<3) +#define BD_STALL_MASK (1<<2) + +#define TX 1 +#define RX 0 + +#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd))) + +#define SETUP_TOKEN 0x0D +#define IN_TOKEN 0x09 +#define OUT_TOKEN 0x01 + +// for each endpt: 8 bytes +struct BDT { + uint8_t info; // BD[0:7] + uint8_t dummy; // RSVD: BD[8:15] + uint16_t byte_count; // BD[16:32] + uint32_t address; // Addr + void setBuffer(uint8_t* buf, int size) { + address = (uint32_t)buf; + byte_count = size; + } + uint8_t getStatus() { + return (info>>2)&0x0f; + } +}; + +__attribute__((__aligned__(512))) BDT bdt[64]; + +USBHALHost* USBHALHost::instHost; + +USBHALHost::USBHALHost() { + instHost = this; + report.clear(); +} + +void USBHALHost::init() { + // Disable IRQ + NVIC_DisableIRQ(USB0_IRQn); + +#if defined(TARGET_K64F) + MPU->CESR=0; +#endif + + // choose usb src as PLL + SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK); + + // enable OTG clock + SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; + + // USB Module Configuration + // Reset USB Module + USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; + while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); + + // Clear interrupt flag + USB0->ISTAT = 0xff; + + // Set BDT Base Register + USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8); + USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16); + USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24); + + // Set SOF threshold + USB0->SOFTHLD = USB_SOFTHLD_CNT(1); + + // pulldown D+ and D- + USB0->USBCTRL = USB_USBCTRL_PDE_MASK; + + USB0->USBTRC0 |= 0x40; + + // Host mode + USB0->CTL |= USB_CTL_HOSTMODEEN_MASK; + // Desable SOF packet generation + USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; + + NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); + NVIC_EnableIRQ(USB0_IRQn); + + bool lowSpeed = wait_attach(); + + for(int retry = 2; retry > 0; retry--) { + // Enable RESET + USB0->CTL |= USB_CTL_RESET_MASK; + wait_ms(500); + USB0->CTL &= ~USB_CTL_RESET_MASK; + + // Enable SOF + USB0->CTL |= USB_CTL_USBENSOFEN_MASK; + wait_ms(100); + + // token transfer initialize + token_transfer_init(); + + USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK| + USB_INTEN_ERROREN_MASK; + USB0->ERREN |= USB_ERREN_PIDERREN_MASK| + USB_ERREN_CRC5EOFEN_MASK| + USB_ERREN_CRC16EN_MASK| + USB_ERREN_DFN8EN_MASK| + USB_ERREN_BTOERREN_MASK| + USB_ERREN_DMAERREN_MASK| + USB_ERREN_BTSERREN_MASK; + + if (addDevice(NULL, 0, lowSpeed)) { + break; + } + USB_DBG("retry=%d", retry); + USB_TEST_ASSERT(retry > 1); + } +} + +bool USBHALHost::wait_attach() { + attach_done = false; + USB0->INTEN = USB_INTEN_ATTACHEN_MASK; + Timer t; + t.reset(); + t.start(); + while(!attach_done) { + if (t.read_ms() > 5*1000) { + t.reset(); + USB_INFO("Please attach USB device."); + } + } + wait_ms(100); + USB_TEST_ASSERT(!(USB0->CTL & USB_CTL_SE0_MASK)); + root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; + return root_lowSpeed; +} + +void USBHALHost::setAddr(int _addr, bool _lowSpeed) { + USB0->ADDR = (_lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); +} + +void USBHALHost::setEndpoint() { + USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| + USB_ENDPT_RETRYDIS_MASK| + USB_ENDPT_EPCTLDIS_MASK| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK| + USB_ENDPT_EPHSHK_MASK; +} + +void USBHALHost::token_transfer_init() { + tx_ptr = ODD; + rx_ptr = ODD; +} + +int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + USBDeviceConnected* dev = ep->getDevice(); + setAddr(dev->getAddress(), dev->getSpeed()); + + for(int retry = 0;; retry++) { + token_ready(); + USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | + USB_ENDPT_RETRYDIS_MASK| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK| + USB_ENDPT_EPHSHK_MASK; + CTASSERT(sizeof(SETUP_PACKET) == 8); + setup->wLength = wLength; + int idx = EP0_BDT_IDX(TX, tx_ptr); + bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET)); + bdt[idx].info = BD_OWN_MASK | + BD_DTS_MASK; // always data0 + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress() & 0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + if (LastStatus == ACK) { + if (retry > 0) { + USB_DBG("retry=%d %02x", retry, prev_LastStatus); + } + break; + } else if (LastStatus == STALL) { + report.stall++; + return STALL; + } + if (retry > 10) { + USB_DBG("retry=%d", retry); + break; + } + prev_LastStatus = LastStatus; + wait_ms(100 * retry); + } + ep->setData01(DATA1); // next toggle + return LastStatus; +} + +int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + USBDeviceConnected* dev = ep->getDevice(); + setAddr(dev->getAddress(), dev->getSpeed()); + setEndpoint(); + + for(int retry = 0;; retry++) { + token_ready(); + int idx = EP0_BDT_IDX(RX, rx_ptr); + bdt[idx].setBuffer(data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK| + (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + if (LastStatus == DATA0 || LastStatus == DATA1) { + USB_TEST_ASSERT(ep->getData01() == LastStatus); + ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0); + if (retry > 0) { + //USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == STALL) { + report.stall++; + return -1; + } else if (LastStatus == NAK) { + report.nak++; + if (retry >= retryLimit) { + if (retryLimit > 0) { + USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); + } + return -1; + } + wait_ms(100 * retry); + } else if (LastStatus == Bus_Timeout) { + if (retry >= retryLimit) { + if (retryLimit > 0) { + USB_DBG("Bus_Timeout retry=%d retryLimit=%d", retry, retryLimit); + } + return -1; + } + wait_ms(500 + 100 * retry); + } else { + return -1; + } + prev_LastStatus = LastStatus; + } +} + +int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress(), dev->getSpeed()); + setEndpoint(); + + for(int retry = 0;; retry++) { + token_ready(); + int idx = EP0_BDT_IDX(TX, tx_ptr); + bdt[idx].setBuffer((uint8_t*)data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK| + (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + //USB_DBG("len=%d %02x", len, LastStatus); + if (LastStatus == ACK) { + ep->toggleData01(); + if (retry > 0) { + USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == STALL) { + report.stall++; + return -1; + } else if (LastStatus == NAK) { + report.nak++; + if (retry > retryLimit) { + USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); + return -1; + } + wait_ms(100 * retry); + } else { + return -1; + } + prev_LastStatus = LastStatus; + } +} + +void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) { + USB_TRACE1(size); + USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING); + ep->setBuffer(data, size); + ep->setState(USB_TYPE_PROCESSING); +} + +USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) { + USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING); + uint8_t* buf = ep->getBufStart(); + int size = ep->getBufSize(); + int result = multi_token_in(ep, buf, size, false); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_PROCESSING; + } + ep->setLengthTransferred(result); + ep->setState(USB_TYPE_IDLE); + return USB_TYPE_OK; +} + +void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) { + USB_TEST_ASSERT(toggle == 1); + ep->setData01(toggle == 0 ? DATA0 : DATA1); +} + +int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress()); + + while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ? + USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF + while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); + USB0->SOFTHLD = 0; // this is needed as without this you can get errors + USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF + + USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK| + USB_ENDPT_RETRYDIS_MASK| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK; + int idx = EP0_BDT_IDX(RX, rx_ptr); + bdt[idx].setBuffer(data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK; // always DATA0 + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + if (LastStatus == DATA0) { + return len; + } + return -1; +} + +void USBHALHost::token_ready() { + while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ? + wait_ms(1); + } + USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF + while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); + USB0->SOFTHLD = 0; // this is needed as without this you can get errors + USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF +} + +int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block) { + if (total == 0) { + return token_in(ep); + } + int retryLimit = block ? 10 : 0; + int read_len = 0; + for(int n = 0; read_len < total; n++) { + int size = std::min((int)total-read_len, ep->getSize()); + int result = token_in(ep, data+read_len, size, retryLimit); + if (result < 0) { + if (block) { + return -1; + } + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + return result; + } + read_len += result; + if (result < ep->getSize()) { + break; + } + } + return read_len; +} + +int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total) { + if (total == 0) { + return token_out(ep); + } + int write_len = 0; + for(int n = 0; write_len < total; n++) { + int size = std::min((int)total-write_len, ep->getSize()); + int result = token_out(ep, data+write_len, size); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_out result=%d %02x", result, LastStatus); + return result; + } + write_len += result; + if (result < ep->getSize()) { + break; + } + } + return write_len; +} + +void USBHALHost::_usbisr(void) { + if (instHost) { + instHost->UsbIrqhandler(); + } +} + +void USBHALHost::UsbIrqhandler() { + if (USB0->ISTAT & USB_ISTAT_TOKDNE_MASK) { + uint8_t stat = USB0->STAT; + ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN; + if (stat & USB_STAT_TX_MASK) { + tx_ptr = next_ptr; + } else { + rx_ptr = next_ptr; + } + USB0->ISTAT = USB_ISTAT_TOKDNE_MASK; + token_done = true; + } + if (USB0->ISTAT & USB_ISTAT_ATTACH_MASK) { + USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK; + USB0->ISTAT = USB_ISTAT_ATTACH_MASK; + attach_done = true; + } + if (USB0->ISTAT & USB_ISTAT_ERROR_MASK) { + uint8_t errstat = USB0->ERRSTAT; + if (errstat & USB_ERRSTAT_PIDERR_MASK) { + report.errstat_piderr++; + } + if (errstat & USB_ERRSTAT_CRC5EOF_MASK) { + report.errstat_crc5eof++; + } + if (errstat & USB_ERRSTAT_CRC16_MASK) { + report.errstat_crc16++; + } + if (errstat & USB_ERRSTAT_DFN8_MASK) { + report.errstat_dfn8++; + } + if (errstat & USB_ERRSTAT_BTOERR_MASK) { + report.errstat_btoerr++; + } + if (errstat & USB_ERRSTAT_DMAERR_MASK) { + report.errstat_dmaerr++; + } + if (errstat & USB_ERRSTAT_BTSERR_MASK) { + report.errstat_btoerr++; + } + USB0->ERRSTAT = errstat; + USB0->ISTAT = USB_ISTAT_ERROR_MASK; + } +} + +void Report::clear() { + errstat_piderr = 0; + errstat_crc5eof = 0; + errstat_crc16 = 0; + errstat_dfn8 = 0; + errstat_btoerr = 0; + errstat_dmaerr = 0; + errstat_bsterr = 0; + // + nak = 0; +} + +void Report::print_errstat() { + printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n", + errstat_piderr, errstat_crc5eof, + errstat_crc16, errstat_dfn8, + errstat_btoerr, errstat_dmaerr, errstat_bsterr); +} + +void debug_hex(uint8_t* buf, int size) { + int n = 0; + for(int i = 0; i < size; i++) { + fprintf(stderr, "%02x ", buf[i]); + if (++n >= 16) { + fprintf(stderr, "\n"); + n = 0; + } + } + if (n > 0) { + fprintf(stderr, "\n"); + } +} + +#endif + +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_KL46Z.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_KL46Z.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,68 @@ +#pragma once +#include "mbed.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +#define GET_CONFIGURATION 8 + +// TOK_PID[5:2] +#define Bus_Timeout 0x00 +#define Data_Error 0x0f + +enum ODD_EVEN { + ODD = 0, + EVEN = 1, +}; + +class Report { +public: + void clear(); + void print_errstat(); + // error count + uint32_t errstat_piderr; // USBx_ERRSTAT[PIDERR] + uint32_t errstat_crc5eof;// USBx_ERRSTAT[CRC5EOF] + uint32_t errstat_crc16; // USBx_ERRSTAT[CRC16] + uint32_t errstat_dfn8; // USBx_ERRSTAT[DFN8] + uint32_t errstat_btoerr; // USBx_ERRSTAT[BTOERR] + uint32_t errstat_dmaerr; // USBx_ERRSTAT[DMAERR] + uint32_t errstat_bsterr; // USBx_ERRSTAT[BTSERR] + // + uint32_t nak; + uint32_t stall; +}; + +class USBHALHost { +public: + uint8_t LastStatus; + uint8_t prev_LastStatus; + Report report; + +protected: + USBHALHost(); + void init(); + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0; + int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); + int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, size_t total = 0, bool block = true); + int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, size_t total = 0); + void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size); + USB_TYPE multi_token_inNB_result(USBEndpoint* ep); + void setToggle(USBEndpoint* ep, uint8_t toggle); + int token_iso_in(USBEndpoint* ep, uint8_t* data, int size); + +private: + void setAddr(int addr, bool lowSpeed = false); + void setEndpoint(); + void token_transfer_init(); + void token_ready(); + int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10); + static void _usbisr(void); + void UsbIrqhandler(); + __IO bool attach_done; + __IO bool token_done; + bool wait_attach(); + bool root_lowSpeed; + ODD_EVEN tx_ptr; + ODD_EVEN rx_ptr; + static USBHALHost * instHost; +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_LPC4088.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_LPC4088.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,604 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(TARGET_LPC4088)||defined(TARGET_LPC1768) +#include "USBHALHost.h" + +#ifndef CTASSERT +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); +#endif + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +#define USB_DBG_ED(A) while(0) +#define USB_DBG_TD(A) while(0) +#define USB_DBG_ED_IF(A,B) while(0) +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG_ED(A) while(0) +#define USB_DBG_TD(A) while(0) +#define USB_DBG_ED_IF(A,B) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#define USB_TRACE1(A) while(0) + +#ifdef _USB_TEST +#undef USB_TEST_ASSERT +void usb_test_assert_internal(const char *expr, const char *file, int line); +#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} +#else +#define USB_TEST_ASSERT(EXPR) while(0) +#endif + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); + +// bits of the USB/OTG clock control register +#define HOST_CLK_EN (1<<0) +#define DEV_CLK_EN (1<<1) +#define PORTSEL_CLK_EN (1<<3) +#define AHB_CLK_EN (1<<4) + +// bits of the USB/OTG clock status register +#define HOST_CLK_ON (1<<0) +#define DEV_CLK_ON (1<<1) +#define PORTSEL_CLK_ON (1<<3) +#define AHB_CLK_ON (1<<4) + +// we need host clock, OTG/portsel clock and AHB clock +#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) +#define FI 0x2EDF /* 12000 bits per frame (-1) */ +#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI) + +USBHALHost* USBHALHost::instHost; + +USBHALHost::USBHALHost() { + instHost = this; +} + +void USBHALHost::init() { + NVIC_DisableIRQ(USB_IRQn); + m_pHcca = new HCCA(); + init_hw_ohci(m_pHcca); + ResetRootHub(); + NVIC_SetVector(USB_IRQn, (uint32_t)_usbisr); + NVIC_SetPriority(USB_IRQn, 0); + NVIC_EnableIRQ(USB_IRQn); + + USB_INFO("Simple USBHost Library for LPC4088/LPC1768"); + bool lowSpeed = wait_attach(); + addDevice(NULL, 0, lowSpeed); +} + +void USBHALHost::init_hw_ohci(HCCA* pHcca) { + LPC_SC->PCONP &= ~(1UL<<31); //Cut power + wait_ms(1000); + LPC_SC->PCONP |= (1UL<<31); // turn on power for USB + LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock + // Wait for clocks to become available + while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) + ; + LPC_USB->OTGStCtrl |= 1; + LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; + +#if defined(TARGET_LPC1768) + LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); + LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 +#elif defined(TARGET_LPC4088) + LPC_IOCON->P0_29 = 0x01; // USB_D+1 + LPC_IOCON->P0_30 = 0x01; // USB_D-1 + // DO NOT CHANGE P1_19. +#else +#error "target error" +#endif + USB_DBG("initialize OHCI\n"); + wait_ms(100); /* Wait 50 ms before apply reset */ + USB_TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision + LPC_USB->HcControl = 0; /* HARDWARE RESET */ + LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */ + LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */ + /* SOFTWARE RESET */ + LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; + LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ + LPC_USB->HcPeriodicStart = FI*90/100; + /* Put HC in operational state */ + LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; + LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ + USB_TEST_ASSERT(pHcca); + for (int i = 0; i < 32; i++) { + pHcca->InterruptTable[i] = NULL; + } + LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca); + LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */ + LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO; + + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; +} + +void USBHALHost::ResetRootHub() { + wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset + USB_DBG("Before loop\n"); + while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS) + ; + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal + USB_DBG("After loop\n"); + wait_ms(200); /* Wait for 100 MS after port reset */ +} + +bool USBHALHost::wait_attach() { + bool lowSpeed = false; + uint32_t status = LPC_USB->HcRhPortStatus1; + if (status & OR_RH_PORT_LSDA) { // lowSpeedDeviceAttached + lowSpeed = true; + } + return lowSpeed; +} + +void enable(ENDPOINT_TYPE type) { + switch(type) { + case CONTROL_ENDPOINT: + LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF; + LPC_USB->HcControl |= OR_CONTROL_CLE; + break; + case ISOCHRONOUS_ENDPOINT: + LPC_USB->HcControl |= OR_CONTROL_PLE; + break; + case BULK_ENDPOINT: + LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF; + LPC_USB->HcControl |= OR_CONTROL_BLE; + break; + case INTERRUPT_ENDPOINT: + LPC_USB->HcControl |= OR_CONTROL_PLE; + break; + } +} + +void USBHALHost::token_init(USBEndpoint* ep) { + HCED* ed = ep->getHALData<HCED*>(); + if (ed == NULL) { + ed = new HCED(ep); + ep->setHALData<HCED*>(ed); + } + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + if (dev) { + uint8_t devAddr = dev->getAddress(); + USB_DBG("devAddr=%02x", devAddr); + ed->setFunctionAddress(devAddr); + } + uint16_t size = ep->getSize(); + USB_DBG("MaxPacketSize=%d", size); + ed->setMaxPacketSize(size); + if (ed->HeadTd == NULL) { + HCTD* td = new HCTD(ed); + ed->TailTd = td; + ed->HeadTd = td; + switch(ep->getType()) { + case CONTROL_ENDPOINT: + ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED); + LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(ed); + break; + case BULK_ENDPOINT: + ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcBulkHeadED); + LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(ed); + break; + case INTERRUPT_ENDPOINT: + HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA); + ed->Next = pHcca->InterruptTable[0]; + pHcca->InterruptTable[0] = ed; + break; + } + } +} + +int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + token_init(ep); + HCED* ed = ep->getHALData<HCED*>(); + HCTD* td = ed->TailTd; + setup->wLength = wLength; + TBUF* tbuf = new(sizeof(SETUP_PACKET))TBUF(setup, sizeof(SETUP_PACKET)); + td->transfer(tbuf, sizeof(SETUP_PACKET)); + td->Control |= TD_TOGGLE_0|TD_SETUP; // DATA0 + HCTD* blank = new HCTD(ed); + ed->enqueue(blank); + //DBG_ED(ed); + enable(ep->getType()); + + td = ed->get_queue_HCTD(); + USB_TEST_ASSERT(td); + int result = td->getLengthTransferred(); + USB_DBG_TD(td); + delete tbuf; + delete td; + return result; +} + +static HCED* getHCED_iso(USBEndpoint* ep) { + HCED* ed = ep->getHALData<HCED*>(); + if (ed != NULL) { + return ed; + } + ed = new HCED(ep); + ep->setHALData<HCED*>(ed); + ed->setFormat(); // F Format ITD + ed->iso.FrameCount = ep->ohci.frameCount; + ed->iso.queue_limit = ep->ohci.queueLimit; + ed->iso.queue_count = 0; + ed->iso.Current_FrameCount = 0; + ed->iso.Current_itd = NULL; + ed->iso.FrameNumber = LPC_USB->HcFmNumber + 10; // after 10msec + HCITD* itd = ed->new_HCITD(); + ed->init_queue(reinterpret_cast<HCTD*>(itd)); + HCCA* hcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA); + hcca->enqueue(ed); + LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable + LPC_USB->HcControl |= OR_CONTROL_IE; // IsochronousEnable + return ed; +} + +static void enablePeriodic() { + LPC_USB->HcControl |= OR_CONTROL_PLE; +} + +HCITD* isochronousReceive(USBEndpoint* ep) { + HCED* ed = getHCED_iso(ep); + USB_TEST_ASSERT(ed); + while(ed->iso.queue_count < ed->iso.queue_limit) { + HCITD* blank_itd = ed->new_HCITD(); + if (ed->enqueue(reinterpret_cast<HCTD*>(blank_itd))) { + ed->iso.queue_count++; + } + enablePeriodic(); + } + + HCITD* itd = ed->get_queue_HCITD(); + if (itd) { + ed->iso.queue_count--; + } + return itd; +} + +int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { + HCED* ed = getHCED_iso(ep); + if (ed->iso.Current_FrameCount == 0) { + HCITD* itd = isochronousReceive(ep); + if (itd == NULL) { + return -1; + } + if (itd->ConditionCode() != 0) { + delete itd; + return -1; + } + ed->iso.Current_itd = itd; + } + + HCITD* itd = ed->iso.Current_itd; + int fc = ed->iso.Current_FrameCount; + int result = -1; + uint8_t cc = itd->ConditionCode(fc); + if (cc == 0 || cc == 9) { + result = itd->Length(fc); + memcpy(data, itd->Buffer(fc), result); + } + + if (++ed->iso.Current_FrameCount >= itd->FrameCount()) { + ed->iso.Current_FrameCount = 0; + delete ed->iso.Current_itd; + } + return result; +} + +int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, int size) { + token_init(ep); + HCED* ed = ep->getHALData<HCED*>(); + HCTD* td = ed->TailTd; + TBUF* tbuf = NULL; + if (data != NULL) { + tbuf = new(size)TBUF(); + td->transfer(tbuf, size); + } + td->Control |= TD_IN; + HCTD* blank = new HCTD(ed); + ed->enqueue(blank); + USB_DBG_ED_IF(ed->EndpointNumber()==0, ed); // control transfer + enable(ep->getType()); + + td = ed->get_queue_HCTD(); + USB_TEST_ASSERT(td); + if (data != NULL) { + memcpy(data, tbuf->buf, size); + delete tbuf; + } + int result = td->getLengthTransferred(); + delete td; + return result; +} + +int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, int size) { + token_init(ep); + HCED* ed = ep->getHALData<HCED*>(); + HCTD* td = ed->TailTd; + TBUF* tbuf = NULL; + if (data != NULL) { + tbuf = new(size)TBUF(data, size); + td->transfer(tbuf, size); + } + td->Control |= TD_OUT; + HCTD* blank = new HCTD(ed); + ed->enqueue(blank); + USB_DBG_ED(ed); + enable(ep->getType()); + + td = ed->get_queue_HCTD(); + USB_TEST_ASSERT(td); + if (data != NULL) { + delete tbuf; + } + int result = td->getLengthTransferred(); + delete td; + return result; +} + +void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) { + token_init(ep); + HCED* ed = ep->getHALData<HCED*>(); + HCTD* td = ed->TailTd; + TBUF* tbuf = new(size)TBUF(); + td->transfer(tbuf, size); + td->Control |= TD_IN; + HCTD* blank = new HCTD(ed); + ed->enqueue(blank); + enable(ep->getType()); +} + +USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) { + HCED* ed = ep->getHALData<HCED*>(); + if (ed == NULL) { + return USB_TYPE_ERROR; + } + HCTD* td = ed->get_queue_HCTD(0); + if (td) { + int len = td->getLengthTransferred(); + TBUF* tbuf = (TBUF*)td->buf_top; + memcpy(ep->getBufStart(), tbuf->buf, len); + ep->setLengthTransferred(len); + ep->setState((USB_TYPE)td->ConditionCode()); + delete td; + delete tbuf; + return USB_TYPE_OK; + } + return USB_TYPE_PROCESSING; +} + +void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) { + USB_TEST_ASSERT(toggle == 1); + HCED* ed = ep->getHALData<HCED*>(); + ed->setToggle(toggle); +} + +void USBHALHost::_usbisr(void) { + if (instHost) { + instHost->UsbIrqhandler(); + } +} + +HCTD* td_reverse(HCTD* td) +{ + HCTD* result = NULL; + HCTD* next; + while(td) { + next = const_cast<HCTD*>(td->Next); + td->Next = result; + result = td; + td = next; + } + return result; +} + +void USBHALHost::UsbIrqhandler() { + if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) { + return; + } + m_report_irq++; + uint32_t status = LPC_USB->HcInterruptStatus; + if (status & OR_INTR_STATUS_FNO) { + m_report_FNO++; + } + if (status & OR_INTR_STATUS_WDH) { + union { + HCTD* done_td; + uint32_t lsb; + }; + done_td = const_cast<HCTD*>(m_pHcca->DoneHead); + USB_TEST_ASSERT(done_td); + m_pHcca->DoneHead = NULL; // reset + if (lsb & 1) { // error ? + lsb &= ~1; + } + HCTD* td = td_reverse(done_td); + while(td) { + HCED* ed = td->parent; + USB_TEST_ASSERT(ed); + if (ed) { + ed->irqWdhHandler(td); + } + td = td->Next; + } + m_report_WDH++; + } + LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status +} + +TBUF::TBUF(const void* data, int size) { + if (size > 0) { + memcpy(buf, data, size); + } +} + +HCTD::HCTD(HCED* obj) { + CTASSERT(sizeof(HCTD) == 36); + USB_TEST_ASSERT(obj); + Control = TD_CC|TD_ROUNDING; + CurrBufPtr = NULL; + Next = NULL; + BufEnd = NULL; + buf_top = NULL; + buf_size = 0; + parent = obj; +} + +HCITD::HCITD(HCED* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) { + Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED + ((FrameCount-1) << 24)| // FC FrameCount + TD_DELAY_INT(0) | // DI DelayInterrupt + FrameNumber; // SF StartingFrame + BufferPage0 = const_cast<uint8_t*>(buf); + BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1; + Next = NULL; + parent = obj; + uint32_t addr = reinterpret_cast<uint32_t>(buf); + for(int i = 0; i < FrameCount; i++) { + uint16_t offset = addr & 0x0fff; + if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) { + offset |= 0x1000; + } + OffsetPSW[i] = 0xe000|offset; + addr += PacketSize; + } +} + +uint8_t* HCITD::Buffer(int fc) { + int offset = fc * parent->getMaxPacketSize(); + return const_cast<uint8_t*>(buf) + offset; +} + +HCED::HCED(USBEndpoint* ep) { + CTASSERT(sizeof(HCED) <= (64*2)); + USBDeviceConnected* dev = ep->getDevice(); + int devAddr = 0; + bool lowSpeed = false; + if (dev) { + devAddr = dev->getAddress(); + lowSpeed = dev->getSpeed(); + } + int ep_number = ep->getAddress(); + int MaxPacketSize = ep->getSize(); + Control = devAddr | /* USB address */ + ((ep_number & 0x7F) << 7) | /* Endpoint address */ + (ep_number!=0?(((ep_number&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */ + ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */ + (MaxPacketSize << 16); /* MaxPkt Size */ + TailTd = NULL; + HeadTd = NULL; + Next = NULL; +} + +bool HCED::enqueue(HCTD* td) { + if (td) { + HCTD* tail = reinterpret_cast<HCTD*>(TailTd); + if (tail) { + tail->Next = td; + TailTd = reinterpret_cast<HCTD*>(td); + return true; + } + } + return false; +} + +void HCED::init_queue(HCTD* td) { + TailTd = reinterpret_cast<HCTD*>(td); + HeadTd = reinterpret_cast<HCTD*>(td); +} + +void HCED::setToggle(uint8_t toggle) { + uint32_t c = reinterpret_cast<uint32_t>(HeadTd); + if (toggle == 0) { // DATA0 + c &= ~0x02; + } else { // DATA1 + c |= 0x02; + } + HeadTd = reinterpret_cast<HCTD*>(c); +} + +uint8_t HCED::getToggle() { + uint32_t c = reinterpret_cast<uint32_t>(HeadTd); + return (c&0x02) ? 1 : 0; +} + +HCTD* HCED::get_queue_HCTD(uint32_t millisec) +{ + for(int i = 0; i < 16; i++) { + osEvent evt = done_queue_get(millisec); + if (evt.status == osEventMessage) { + HCTD* td = reinterpret_cast<HCTD*>(evt.value.p); + USB_TEST_ASSERT(td); + uint8_t cc = td->ConditionCode(); + if (cc != 0) { + m_ConditionCode = cc; + USB_DBG_TD(td); + } + return td; + } else if (evt.status == osOK) { + continue; + } else if (evt.status == osEventTimeout) { + return NULL; + } else { + USB_DBG("evt.status: %02x\n", evt.status); + USB_TEST_ASSERT(evt.status == osEventMessage); + } + } + return NULL; +} + +HCITD* HCED::get_queue_HCITD() { + osEvent evt = done_queue_get(0); + if (evt.status == osEventMessage) { + HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p); + USB_TEST_ASSERT(itd); + return itd; + } + return NULL; +} +HCITD* HCED::new_HCITD() { + uint16_t mps = getMaxPacketSize(); + int total_size = mps * iso.FrameCount; + HCITD* itd = new(total_size)HCITD(this, iso.FrameNumber, iso.FrameCount, mps); + iso.FrameNumber += iso.FrameCount; + return itd; +} + +void HCCA::enqueue(HCED* ed) { + for(int i = 0; i < 32; i++) { + if (InterruptTable[i] == NULL) { + InterruptTable[i] = ed; + } else { + HCED* nextEd = InterruptTable[i]; + while(nextEd->Next && nextEd->Next != ed) { + nextEd = nextEd->Next; + } + nextEd->Next = ed; + } + } +} + +#endif // defined(TARGET_LPC4088)||defined(TARGET_LPC1768) +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_LPC4088.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHALHost_LPC4088.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,284 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "mbed.h" +#include "rtos.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +#if defined(TARGET_LPC4088) +#define HcRevision Revision +#define HcControl Control +#define HcCommandStatus CommandStatus +#define HcInterruptStatus InterruptStatus +#define HcInterruptEnable InterruptEnable +#define HcHCCA HCCA +#define HcControlHeadED ControlHeadED +#define HcBulkHeadED BulkHeadED +#define HcFmInterval FmInterval +#define HcFmNumber FmNumber +#define HcPeriodicStart PeriodicStart +#define HcRhStatus RhStatus +#define HcRhPortStatus1 RhPortStatus1 +#define OTGStCtrl StCtrl +#endif +// ------------------ HcControl Register --------------------- +#define OR_CONTROL_PLE 0x00000004 +#define OR_CONTROL_IE 0x00000008 +#define OR_CONTROL_CLE 0x00000010 +#define OR_CONTROL_BLE 0x00000020 +#define OR_CONTROL_HCFS 0x000000C0 +#define OR_CONTROL_HC_OPER 0x00000080 +// ----------------- HcCommandStatus Register ----------------- +#define OR_CMD_STATUS_HCR 0x00000001 +#define OR_CMD_STATUS_CLF 0x00000002 +#define OR_CMD_STATUS_BLF 0x00000004 +// --------------- HcInterruptStatus Register ----------------- +#define OR_INTR_STATUS_WDH 0x00000002 +#define OR_INTR_STATUS_UE 0x00000010 +#define OR_INTR_STATUS_FNO 0x00000020 +#define OR_INTR_STATUS_RHSC 0x00000040 +// --------------- HcInterruptEnable Register ----------------- +#define OR_INTR_ENABLE_WDH 0x00000002 +#define OR_INTR_ENABLE_FNO 0x00000020 +#define OR_INTR_ENABLE_RHSC 0x00000040 +#define OR_INTR_ENABLE_MIE 0x80000000 +// ---------------- HcRhDescriptorA Register ------------------ +#define OR_RH_STATUS_LPSC 0x00010000 +#define OR_RH_STATUS_DRWE 0x00008000 +// -------------- HcRhPortStatus[1:NDP] Register -------------- +#define OR_RH_PORT_CCS 0x00000001 +#define OR_RH_PORT_PRS 0x00000010 +#define OR_RH_PORT_LSDA 0x00000200 +#define OR_RH_PORT_CSC 0x00010000 +#define OR_RH_PORT_PRSC 0x00100000 + +// TRANSFER DESCRIPTOR CONTROL FIELDS +#define TD_ROUNDING (uint32_t)(0x00040000) /* Buffer Rounding */ +#define TD_SETUP (uint32_t)(0x00000000) /* Direction of Setup Packet */ +#define TD_IN (uint32_t)(0x00100000) /* Direction In */ +#define TD_OUT (uint32_t)(0x00080000) /* Direction Out */ +#define TD_DELAY_INT(x) (uint32_t)((x) << 21) /* Delay Interrupt */ +#define TD_DI (uint32_t)(7<<21) /* desable interrupt */ +#define TD_TOGGLE_0 (uint32_t)(0x02000000) /* Toggle 0 */ +#define TD_TOGGLE_1 (uint32_t)(0x03000000) /* Toggle 1 */ +#define TD_CC (uint32_t)(0xF0000000) /* Completion Code */ + +void* usb_ram_malloc(size_t size, int aligment); // USBHALHost2_LPC4088.cpp +void usb_ram_free(void* p); + +struct TBUF { + uint8_t buf[0]; + TBUF(const void* data = NULL, int size = 0); + void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 4); } + void operator delete(void* p) { usb_ram_free(p); } +}; + +class HCED; + +struct HCTD { // HostController Transfer Descriptor + __IO uint32_t Control; // +0 Transfer descriptor control + __IO uint8_t* CurrBufPtr; // +4 Physical address of current buffer pointer + HCTD* Next; // +8 Physical pointer to next Transfer Descriptor + uint8_t* BufEnd; // +12 Physical address of end of buffer + uint8_t* buf_top; // +16 Buffer start address + uint16_t buf_size; // +20 buffer size size + uint8_t _dummy[10]; // +22 dummy + HCED* parent; // +32 HCED object + // +36 + HCTD(HCED* ed); + void* operator new(size_t size) { return usb_ram_malloc(size, 16); } + void operator delete(void* p) { usb_ram_free(p); } + + void transfer(TBUF* tbuf, int len) { + CurrBufPtr = tbuf->buf; + buf_top = tbuf->buf; + buf_size = len; + BufEnd = const_cast<uint8_t*>(tbuf->buf)+len-1; + } + int getLengthTransferred() { + if (CurrBufPtr) { + return CurrBufPtr - buf_top; + } + return buf_size; + } + int status() { + if (CurrBufPtr) { + return CurrBufPtr - buf_top; + } + return buf_size; + } + + uint8_t ConditionCode() { + return Control>>28; + } +}; + +struct HCITD { // HostController Isochronous Transfer Descriptor + __IO uint32_t Control; // +0 Transfer descriptor control + uint8_t* BufferPage0; // +4 Buffer Page 0 + HCITD* Next; // +8 Physical pointer to next Isochronous Transfer Descriptor + uint8_t* BufferEnd; // +12 buffer End + __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW + HCED* parent; // +32 HCED object + __IO uint8_t buf[0]; // +36 buffer + // +36 + HCITD(HCED* ed, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize); + uint8_t* Buffer(int fc); + void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 32); } + void operator delete(void* p) { usb_ram_free(p); } + + uint16_t StartingFrame() { + return Control & 0xffff; + } + + uint8_t FrameCount() { + return ((Control>>24)&7)+1; + } + + uint8_t ConditionCode() { + return Control>>28; + } + + uint8_t ConditionCode(int fc) { + uint16_t psw = OffsetPSW[fc]; + return psw>>12; + } + + uint16_t Length(int fc) { + uint16_t psw = OffsetPSW[fc]; + return psw & 0x7ff; + } +}; + +#define HCTD_QUEUE_SIZE 3 + +struct HCED { // HostController EndPoint Descriptor + __IO uint32_t Control; // +0 Endpoint descriptor control + HCTD* TailTd; // +4 Physical address of tail in Transfer descriptor list + __IO HCTD* HeadTd; // +8 Physcial address of head in Transfer descriptor list + HCED* Next; // +12 Physical address of next Endpoint descriptor + // +16 + uint8_t m_ConditionCode; + Queue<HCTD, HCTD_QUEUE_SIZE> _done_queue; // TD done queue + struct { + uint8_t queue_count; + uint8_t queue_limit; + uint16_t FrameNumber; + uint8_t FrameCount; // 1-8 + HCITD* Current_itd; + uint8_t Current_FrameCount; + } iso; + inline osEvent done_queue_get(uint32_t millisec) { return _done_queue.get(millisec); } + inline void irqWdhHandler(HCTD* td) {_done_queue.put(td);} // WDH + HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever); + HCITD* get_queue_HCITD(); + HCITD* new_HCITD(); + HCED(USBEndpoint* ep); + void* operator new(size_t size) { return usb_ram_malloc(size, 16); } + void operator delete(void* p) { usb_ram_free(p); } + + uint8_t FunctionAddress() { + return Control & 0x7f; + } + + uint8_t EndpointNumber() { + return (Control>>7) & 0x7f; + } + + int Speed() { + return (Control>>13)&1; + } + + void setFunctionAddress(int addr) { + Control &= ~0x7f; + Control |= addr; + } + + void setMaxPacketSize(uint16_t size) { + Control &= ~0x07ff0000; + Control |= size<<16; + } + + uint16_t getMaxPacketSize() { + return (Control>>16)&0x7ff; + } + + void setToggle(uint8_t toggle); + uint8_t getToggle(); + + int Skip() { + return (Control>>14) & 1; + } + + void setSkip() { + Control |= (1<<14); + } + + void setFormat() { + Control |= (1<<15); + } + + bool enqueue(HCTD* td); + void init_queue(HCTD* td); +}; + +struct HCCA { // Host Controller Communication Area + HCED* InterruptTable[32]; // +0 Interrupt Table + __IO uint16_t FrameNumber;// +128 Frame Number + __IO uint16_t Pad1; // +130 + __IO HCTD* DoneHead; // +132 Done Head + uint8_t Reserved[116]; // +136 Reserved for future use + uint8_t Unknown[4]; // +252 Unused + // +256 + void* operator new(size_t size) { return usb_ram_malloc(size, 256); } + void operator delete(void* p) { usb_ram_free(p); } + void enqueue(HCED* ed); +}; + +class USBHALHost { +protected: + USBHALHost(); + void init(); + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0; + int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); + int token_iso_in(USBEndpoint* ep, uint8_t* data, int size); + int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0); + int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0); + void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size); + USB_TYPE multi_token_inNB_result(USBEndpoint* ep); + void setToggle(USBEndpoint* ep, uint8_t toggle); + + // report + uint32_t m_report_irq; + uint32_t m_report_RHSC; + uint32_t m_report_FNO; + uint32_t m_report_WDH; + uint32_t m_report_sp; + +private: + void init_hw_ohci(HCCA* pHcca); + void ResetRootHub(); + void token_init(USBEndpoint* ep); + static void _usbisr(void); + void UsbIrqhandler(); + HCCA* m_pHcca; + bool wait_attach(); + bool root_lowSpeed; + static USBHALHost * instHost; +}; +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHost.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHost.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,351 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHost.h" + +#define USB_TRACE1(A) while(0) +#undef USB_TEST_ASSERT +void usb_test_assert_internal(const char *expr, const char *file, int line); +#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} + +USBHost* USBHost::inst = NULL; + +USBHost* USBHost::getHostInst() { + if (inst == NULL) { + inst = new USBHost(); + inst->init(); + } + return inst; +} + +void USBHost::poll() +{ + if (inst) { + inst->task(); + } +} + +USBHost::USBHost() { +} + +/* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) { + USBDeviceConnected* dev = new USBDeviceConnected; + USBEndpoint* ep = new USBEndpoint(dev); + dev->init(0, port, lowSpeed); + dev->setAddress(0); + dev->setEpCtl(ep); + uint8_t desc[18]; + wait_ms(100); + + int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + USB_ERR("ADD DEVICE FAILD"); + } + USB_DBG_HEX(desc, 8); + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + ep->setSize(dev_desc->bMaxPacketSize); + + int new_addr = USBDeviceConnected::getNewAddress(); + rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + dev->setAddress(new_addr); + wait_ms(100); + + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); + + dev->setVid(dev_desc->idVendor); + dev->setPid(dev_desc->idProduct); + dev->setClass(dev_desc->bDeviceClass); + USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d", + parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(), + dev->getAddress()); + + DeviceLists.push_back(dev); + + if (dev->getClass() == HUB_CLASS) { + const int config = 1; + int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + wait_ms(100); + Hub(dev); + } + return true; +} + +// enumerate a device with the control USBEndpoint +USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) +{ + if (dev->getClass() == HUB_CLASS) { // skip hub class + return USB_TYPE_OK; + } + uint8_t desc[18]; + USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); + if (rc != USB_TYPE_OK) { + return rc; + } + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + dev->setClass(dev_desc->bDeviceClass); + pEnumerator->setVidPid(dev->getVid(), dev->getPid()); + + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, 4); + + int TotalLength = desc[2]|desc[3]<<8; + uint8_t* buf = new uint8_t[TotalLength]; + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + //USB_DBG_HEX(buf, TotalLength); + + // Parse the configuration descriptor + parseConfDescr(dev, buf, TotalLength, pEnumerator); + delete[] buf; + // only set configuration if not enumerated before + if (!dev->isEnumerated()) { + USB_DBG("Set configuration 1 on dev: %p", dev); + // sixth step: set configuration (only 1 supported) + int config = 1; + USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + if (res != USB_TYPE_OK) { + USB_ERR("SET CONF FAILED"); + return res; + } + // Some devices may require this delay + wait_ms(100); + dev->setEnumerated(); + // Now the device is enumerated! + USB_DBG("dev %p is enumerated", dev); + } + return USB_TYPE_OK; +} + +// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor. +void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) +{ + uint32_t index = 0; + uint32_t len_desc = 0; + uint8_t id = 0; + USBEndpoint * ep = NULL; + uint8_t intf_nb = 0; + bool parsing_intf = false; + uint8_t current_intf = 0; + EndpointDescriptor* ep_desc; + + while (index < len) { + len_desc = conf_descr[index]; + id = conf_descr[index+1]; + USB_DBG_HEX(conf_descr+index, len_desc); + switch (id) { + case CONFIGURATION_DESCRIPTOR: + USB_DBG("dev: %p has %d intf", dev, conf_descr[4]); + dev->setNbIntf(conf_descr[4]); + break; + case INTERFACE_DESCRIPTOR: + if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) { + intf_nb++; + current_intf = conf_descr[index + 2]; + dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]); + USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]); + parsing_intf = true; + } else { + parsing_intf = false; + } + break; + case ENDPOINT_DESCRIPTOR: + ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index); + if (parsing_intf && (intf_nb <= MAX_INTF) ) { + ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03); + ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT; + if(pEnumerator->useEndpoint(current_intf, type, dir)) { + ep = new USBEndpoint(dev); + ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress); + USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev); + dev->addEndpoint(current_intf, ep); + } + } + break; + case HID_DESCRIPTOR: + //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8); + break; + default: + break; + } + index += len_desc; + } +} + +USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + USBEndpoint* ep = dev->getEpCtl(); + SETUP_PACKET setup(requestType, request, value, index, len); + + int result = token_setup(ep, &setup, len); // setup stage + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + + int read_len = multi_token_in(ep, buf, len); // data stage + USB_TRACE1(read_len); + if (read_len < 0) { + return USB_TYPE_ERROR; + } + + setToggle(ep, 1); // DATA1 + result = multi_token_out(ep); // status stage + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(read_len); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + USBEndpoint* ep = dev->getEpCtl(); + SETUP_PACKET setup(requestType, request, value, index, len); + + int result = token_setup(ep, &setup, len); // setup stage + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + int write_len = 0; + if (buf != NULL) { + write_len = multi_token_out(ep, buf, len); // data stage + USB_TRACE1(write_len); + if (write_len < 0) { + return USB_TYPE_ERROR; + } + } + + setToggle(ep, 1); // DATA1 + result = multi_token_in(ep); // status stage + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(write_len); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + if (blocking == false) { + ep->setBuffer(buf, len); + ep_queue.push(ep); + multi_token_inNB(ep, buf, len); + return USB_TYPE_PROCESSING; + } + int result = multi_token_in(ep, buf, len); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(result); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::bulkWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = multi_token_out(ep, buf, len); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(result); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::interruptRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + if (blocking == false) { + ep->setBuffer(buf, len); + ep_queue.push(ep); + multi_token_inNB(ep, buf, len); + return USB_TYPE_PROCESSING; + } + int result = multi_token_in(ep, buf, len); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(result); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::interruptWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = multi_token_out(ep, buf, len); + USB_TRACE1(result); + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(result); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + isochronousReadNB(ep, buf, len); + return USB_TYPE_OK; +} + +int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) { + USB_TRACE1(size); + if (ep->getState() != USB_TYPE_PROCESSING) { + ep->setState(USB_TYPE_PROCESSING); + ep->setBuffer(data, size); + multi_token_inNB(ep, data, size); + } + if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) { + return ep->getLengthTransferred(); + } + return -1; +} + +int USBHost::bulkReadNB(USBEndpoint* ep, uint8_t* data, int size) { + USB_TRACE1(size); + return interruptReadNB(ep, data, size); +} + +int USBHost::isochronousReadNB(USBEndpoint* ep, uint8_t* data, int size) { + USB_TRACE1(size); + int result = token_iso_in(ep, data, size); + if (result >= 0) { + ep->setLengthTransferred(result); + } + return result; +} + +void USBHost::task() { + USBEndpoint* ep = ep_queue.pop(); + if (ep) { + USB_TEST_ASSERT(ep->getDir() == IN); + if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) { + ep->call(); + } else { + ep_queue.push(ep); + } + } +} + +void usb_test_assert_internal(const char *expr, const char *file, int line){ + error("\n\n%s@%d %s ASSERT!\n\n", file, line, expr); +} +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHost.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHost.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,194 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "mbed.h" +#include "USBHALHost.h" +#include "USBDeviceConnected.h" +#include "IUSBEnumerator.h" +#include "USBHostConf.h" +#include "dbg.h" +#include "myvector.h" + +/** +* USBHost class +* This class is a singleton. All drivers have a reference on the static USBHost instance +*/ +class USBHost : public USBHALHost { +public: + /** + * Static method to create or retrieve the single USBHost instance + */ + static USBHost* getHostInst(); + + /** + * Control read: setup stage, data stage and status stage + * + * @param dev the control read will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * + * @returns status of the control read + */ + USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + + /** + * Control write: setup stage, data stage and status stage + * + * @param dev the control write will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * + * @returns status of the control write + */ + USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + + /** + * Bulk read + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to read a packet + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the bulk read + */ + USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Bulk write + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the write is blocking (wait for completion) + * + * @returns status of the bulk write + */ + USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Interrupt read + * + * @param dev the interrupt transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the interrupt read + */ + USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Interrupt write + * + * @param dev the interrupt transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the write is blocking (wait for completion) + * + * @returns status of the interrupt write + */ + USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Isochronous read + * + * @param dev the isochronous transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the interrupt read + */ + USB_TYPE isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking = true); + + /** + * Enumerate a device. + * + * @param dev device which will be enumerated + * + * @returns status of the enumeration + */ + USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator); + + /** + * Get a device + * + * @param index index of the device which will be returned + * + * @returns pointer on the "index" device + */ + USBDeviceConnected * getDevice(uint8_t index) { + return index < DeviceLists.size() ? DeviceLists[index] : NULL; + } + + /** + * register a driver into the host associated with a callback function called when the device is disconnected + * + * @param dev device + * @param intf interface number + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) { + } + + // KL46Z-USBHost extensions + int interruptReadNB(USBEndpoint* ep, uint8_t* data, int size); + int bulkReadNB(USBEndpoint*ep, uint8_t* data, int size); + int isochronousReadNB(USBEndpoint*ep, uint8_t* data, int size); + + /** + * non-blocking processing + */ + static void poll(); + +private: + USBHost(); + static USBHost* inst; + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed); + void root_enumeration(USBDeviceConnected* dev); + void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator); + myvector<USBDeviceConnected*>DeviceLists; + void task(); + EndpointQueue ep_queue; + + // USB HUB + bool Hub(USBDeviceConnected* dev); + int SetPortPower(USBDeviceConnected* dev, int port); + int ClearPortPower(USBDeviceConnected* dev, int port); + int PortReset(USBDeviceConnected* dev, int port); + int SetPortFeature(USBDeviceConnected* dev, int feature, int index); + int ClearPortFeature(USBDeviceConnected* dev, int feature, int index); + int SetPortReset(USBDeviceConnected* dev, int port); + int GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status); +}; +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostConf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHostConf.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,71 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOST_CONF_H +#define USBHOST_CONF_H + +/* +* Maximum number of devices that can be connected +* to the usb host +*/ +#define MAX_DEVICE_CONNECTED 5 + +/* +* Maximum of Hub connected to the usb host +*/ +#define MAX_HUB_NB 2 + +/* +* Maximum number of ports on a USB hub +*/ +#define MAX_HUB_PORT 4 + +/* +* Enable USBHostMSD +*/ +#define USBHOST_MSD 1 + +/* +* Enable USBHostKeyboard +*/ +#define USBHOST_KEYBOARD 1 + +/* +* Enable USBHostMouse +*/ +#define USBHOST_MOUSE 1 + +/* +* Enable USBHostSerial or USBHostMultiSerial (if set > 1) +*/ +#define USBHOST_SERIAL 1 + +/* +* Enable USB3Gmodule +*/ +#define USBHOST_3GMODULE 1 + +/* +* Maximum number of interfaces of a usb device +*/ +#define MAX_INTF 4 + +/* +* usb_thread stack size +*/ +#define USB_THREAD_STACK (256*4 + MAX_HUB_NB*256*4) + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostHub.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHostHub.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,112 @@ +#include "USBHost.h" + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVER_CURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 + +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 +#define C_PORT_OVER_CURRENT 19 +#define C_PORT_RESET 20 + +bool USBHost::Hub(USBDeviceConnected* dev) { + USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p]", dev->getVid(), dev->getPid(), dev); + HubDescriptor hubdesc; + // get HUB descriptor + int rc = controlRead(dev, + USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + GET_DESCRIPTOR, + 0x29 << 8, 0, reinterpret_cast<uint8_t*>(&hubdesc), + sizeof(HubDescriptor)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG_HEX((uint8_t*)&hubdesc, sizeof(hubdesc)); + + uint32_t status; + rc = controlRead( dev, + 0xa0, 0, 0, 0, reinterpret_cast<uint8_t*>(&status), 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG("HUB STATUS: %08X\n", status); + + for(int i = 1; i <= hubdesc.bNbrPorts; i++) { + SetPortPower(dev, i); // power on + wait_ms(hubdesc.bPwrOn2PwrGood*2); + uint32_t status; + GetPortStatus(dev, i, &status); + USB_DBG("port: %d status: %08X\n", i, status); + if (status & 0x010000) { // Connect Status Change, has changed + USB_TEST_ASSERT(status & 0x000001); + ClearPortFeature(dev, C_PORT_CONNECTION, i); + int lowSpeed = 0; + if (status & 0x0200) { + lowSpeed = 1; + } + PortReset(dev, i); + if (!addDevice(dev, i, lowSpeed)) { + ClearPortPower(dev, i); // power off + } + } else { + ClearPortPower(dev, i); // power off + } + } + return false; +} + + +int USBHost::SetPortPower(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_POWER, port); +} + +int USBHost::ClearPortPower(USBDeviceConnected* dev, int port) +{ + return ClearPortFeature(dev, PORT_POWER, port); +} + +int USBHost::SetPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, SET_FEATURE,feature,index,0,0); +} + +int USBHost::ClearPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, CLEAR_FEATURE,feature,index,0,0); +} + +int USBHost::SetPortReset(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_RESET, port); +} + +int USBHost::GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status) +{ + return controlRead(dev, 0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4); +} + +int USBHost::PortReset(USBDeviceConnected* dev, int port) +{ + USB_DBG("%p port=%d\n", this, port); + USB_TEST_ASSERT(port >= 1); + SetPortReset(dev, port); + // wait reset + for(int i = 0; i < 100; i++) { + uint32_t status; + GetPortStatus(dev, port, &status); + USB_DBG("RESET port: %d status: %08X\n", port, status); + if (status & 0x100000) { // Reset change , Reset complete + return USB_TYPE_OK; + } + wait_ms(5); + } + return USB_TYPE_ERROR; +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostTypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/USBHostTypes.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,167 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USB_INC_H +#define USB_INC_H + +#include "mbed.h" +#include "toolchain.h" + +enum USB_TYPE { + USB_TYPE_OK = 0, + + // completion code + USB_TYPE_CRC_ERROR = 1, + USB_TYPE_BIT_STUFFING_ERROR = 2, + USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3, + USB_TYPE_STALL_ERROR = 4, + USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5, + USB_TYPE_PID_CHECK_FAILURE_ERROR = 6, + USB_TYPE_UNEXPECTED_PID_ERROR = 7, + USB_TYPE_DATA_OVERRUN_ERROR = 8, + USB_TYPE_DATA_UNDERRUN_ERROR = 9, + USB_TYPE_RESERVED = 9, + USB_TYPE_RESERVED_ = 10, + USB_TYPE_BUFFER_OVERRUN_ERROR = 12, + USB_TYPE_BUFFER_UNDERRUN_ERROR = 13, + + // general usb state + USB_TYPE_DISCONNECTED = 14, + USB_TYPE_FREE = 15, + USB_TYPE_IDLE = 16, + USB_TYPE_PROCESSING = 17, + + USB_TYPE_ERROR = 18, +}; + + +enum ENDPOINT_DIRECTION { + OUT = 1, + IN +}; + +enum ENDPOINT_TYPE { + CONTROL_ENDPOINT = 0, + ISOCHRONOUS_ENDPOINT, + BULK_ENDPOINT, + INTERRUPT_ENDPOINT +}; + +#define AUDIO_CLASS 0x01 +#define CDC_CLASS 0x02 +#define HID_CLASS 0x03 +#define MSD_CLASS 0x08 +#define HUB_CLASS 0x09 +#define SERIAL_CLASS 0x0A + +#define DEVICE_DESCRIPTOR (1) +#define CONFIGURATION_DESCRIPTOR (2) +#define INTERFACE_DESCRIPTOR (4) +#define ENDPOINT_DESCRIPTOR (5) +#define HID_DESCRIPTOR (33) + +// ----------- Control RequestType Fields ----------- +#define USB_DEVICE_TO_HOST 0x80 +#define USB_HOST_TO_DEVICE 0x00 +#define USB_REQUEST_TYPE_CLASS 0x20 +#define USB_REQUEST_TYPE_STANDARD 0x00 +#define USB_RECIPIENT_DEVICE 0x00 +#define USB_RECIPIENT_INTERFACE 0x01 +#define USB_RECIPIENT_ENDPOINT 0x02 + +// -------------- USB Standard Requests -------------- +#define GET_STATUS 0x00 +#define SET_FEATURE 0x03 +#define SET_ADDRESS 0x05 +#define GET_DESCRIPTOR 0x06 +#define SET_CONFIGURATION 0x09 +#define SET_INTERFACE 0x0b +#define CLEAR_FEATURE 0x01 + +// -------------- USB Descriptor Length -------------- +#define DEVICE_DESCRIPTOR_LENGTH 0x12 +#define CONFIGURATION_DESCRIPTOR_LENGTH 0x09 + +// PID +#define DATA0 0x03 +#define DATA1 0x0b +#define ACK 0x02 +#define STALL 0x0e +#define NAK 0x0a + +#pragma pack(push,1) +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} PACKED DeviceDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} PACKED ConfigurationDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} InterfaceDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} EndpointDescriptor; + +typedef struct { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable; + uint8_t PortPweCtrlMak; +} HubDescriptor; +#pragma pack(pop) + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/dbg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/dbg.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,89 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USB_DEBUG_H +#define USB_DEBUG_H + +//Debug is disabled by default +#ifndef DEBUG +#define DEBUG 3 /*INFO,ERR,WARN*/ +#endif +#ifndef DEBUG2 +#define DEBUG2 0 +#endif +#define DEBUG_TRANSFER 0 +#define DEBUG_EP_STATE 0 +#define DEBUG_EVENT 0 + +#if (DEBUG > 3) +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +//#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +extern void debug_hex(uint8_t* buf, int size); +#define USB_DBG_ERRSTAT() report.print_errstat(); +#else +#define USB_DBG(x, ...) +#define USB_DBG_HEX(A,B) while(0) +#define USB_DBG_ERRSTAT() while(0) +#endif + +#if (DEBUG2 > 3) +#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define USB_DBG2(...) while(0); +#endif + +#if (DEBUG > 2) +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0); +//#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_INFO(x, ...) +#endif + +#if (DEBUG > 1) +#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_WARN(x, ...) +#endif + +#if (DEBUG > 0) +#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_ERR(x, ...) +#endif + +#if (DEBUG_TRANSFER) +#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_DBG_TRANSFER(x, ...) +#endif + +#if (DEBUG_EVENT) +#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_DBG_EVENT(x, ...) +#endif + +#ifdef _USB_TEST +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif + +#endif +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/mydebug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/mydebug.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,13 @@ +#pragma once +template<class SERIAL_T> +void debug_hex(SERIAL_T& pc, const uint8_t* buf, int size) +{ + for(int i = 0; i < size; i++) { + pc.printf("%02x ", buf[i]); + if (i%16 == 15) { + pc.puts("\n"); + } + } + pc.puts("\n"); +} +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/mymap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/mymap.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,65 @@ +#pragma once + +template<class K,class T> +class mymap { + struct mypair { + K first; + T second; + }; +public: + mymap() { + m_size = 0; + } + T& operator[](const K& key) { + int it; + if (count(key) == 0) { + it = insert(key, 0); + } else { + it = find(key); + } + return m_buf[it].second; + } + bool empty() { return m_size == 0 ? true : false; } + int size() { return m_size; } + void clear() { m_size = 0; } + int count(K key) { + for(int i = 0; i < m_size; i++) { + if (m_buf[i].first == key) { + return 1; + } + } + return 0; + } + +private: + int find(K key) { + for(int i = 0; i < m_size; i++) { + if (m_buf[i].first == key) { + return i; + } + } + return -1; + } + int insert(K key, T value) { + int it = find(key); + if (it != -1) { + m_buf[it].second = value; + return it; + } + mypair* new_buf = new mypair[m_size+1]; + if (m_size > 0) { + for(int i = 0; i < m_size; i++) { + new_buf[i] = m_buf[i]; + } + delete[] m_buf; + } + m_buf = new_buf; + it = m_size++; + m_buf[it].first = key; + m_buf[it].second = value; + return it; + } + + int m_size; + mypair *m_buf; +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/myvector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHost/myvector.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,34 @@ +#pragma once + +template<class T> +class myvector { +public: + myvector() { + m_size = 0; + m_buf = NULL; + } + ~myvector() { + if (m_buf) { + delete[] m_buf; + } + } + void push_back(T v) { + T* new_buf = new T[m_size+1]; + if (m_size > 0) { + for(int i = 0; i < m_size; i++) { + new_buf[i] = m_buf[i]; + } + delete[] m_buf; + } + m_buf = new_buf; + m_buf[m_size++] = v; + } + T& operator[](const int index) { + return m_buf[index]; + } + int size() { return m_size; } + +private: + int m_size; + T *m_buf; +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/BaseUvc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/BaseUvc.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,52 @@ +// BaseUvc.cpp +#include "USBHostConf.h" +#include "USBHost.h" +#include "BaseUvc.h" + +void BaseUvc::poll() { + uint8_t buf[ep_iso_in->getSize()]; + int result = host->isochronousReadNB(ep_iso_in, buf, sizeof(buf)); + if (result >= 0) { + const uint16_t frame = 0; + onResult(frame, buf, ep_iso_in->getLengthTransferred()); + } +} + +USB_TYPE BaseUvc::Control(int req, int cs, int index, uint8_t* buf, int size) { + if (req == SET_CUR) { + return host->controlWrite(dev, + USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, + req, cs<<8, index, buf, size); + } + return host->controlRead(dev, + USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, + req, cs<<8, index, buf, size); +} + +USB_TYPE BaseUvc::setInterfaceAlternate(uint8_t intf, uint8_t alt) { + return host->controlWrite(dev, USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, + SET_INTERFACE, alt, intf, NULL, 0); +} + +void BaseUvc::onResult(uint16_t frame, uint8_t* buf, int len) +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(frame, buf, len); + else if(m_pCb) + m_pCb(frame, buf, len); +} + +void BaseUvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) ) +{ + m_pCb = pMethod; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void BaseUvc::clearOnResult() +{ + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/BaseUvc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/BaseUvc.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,50 @@ +// BaseUvc.h +#pragma once + +// --- UVC -------------------------------------------------- +#define _30FPS 333333 +#define _25FPS 400000 +#define _20FPS 500000 +#define _15FPS 666666 +#define _10FPS 1000000 +#define _5FPS 2000000 +#define _1FPS 10000000 + +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 + +#define VS_PROBE_CONTROL 0x01 +#define VS_COMMIT_CONTROL 0x02 + +class BaseUvc { +public: + void poll(); + USB_TYPE Control(int req, int cs, int index, uint8_t* buf, int size); + USB_TYPE setInterfaceAlternate(uint8_t intf, uint8_t alt); + //IsochronousEp* m_isoEp; + // callback + void onResult(uint16_t frame, uint8_t* buf, int len); + void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) ); + class CDummy; + template<class T> + void setOnResult( T* pItem, void (T::*pMethod)(uint16_t, uint8_t*, int) ) + { + m_pCb = NULL; + m_pCbItem = (CDummy*) pItem; + m_pCbMeth = (void (CDummy::*)(uint16_t, uint8_t*, int)) pMethod; + } + void clearOnResult(); + CDummy* m_pCbItem; + void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int); + void (*m_pCb)(uint16_t, uint8_t*, int); +protected: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint* ep_iso_in; +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/CamInfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/CamInfo.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,193 @@ +// CamInfo.cpp +#include "USBHostCam.h" + +// Logitech C270 +#define C270_VID 0x046d +#define C270_PID 0x0825 +#define C270_160x120 2 +#define C270_176x144 3 +#define C270_320x176 4 +#define C270_320x240 5 +#define C270_352x288 6 +#define C270_432x240 7 +#define C270_640x480 1 +#define C270_544x288 8 +#define C270_640x360 9 +#define C270_752x416 10 +#define C270_800x448 11 +#define C270_800x600 12 + +#define C270_MJPEG 2 +#define C270_YUV2 1 + +#define C270_EN 0x81 +#define C270_MPS 192 +#define C270_IF_ALT_192 1 +#define C270_IF_ALT(A) C270_IF_ALT_##A + +#define C270_INFO(SIZE) {C270_VID, C270_PID, _##SIZE, 0, \ + "C270", \ + C270_MJPEG, \ + C270_##SIZE, \ + _5FPS, \ + C270_EN, \ + 192, \ + C270_IF_ALT(192), \ + 4, \ + 3} + +#define C210_PID 0x819 +#define C210_INFO(SIZE) {C270_VID, C210_PID, _##SIZE, 0, \ + "C210", \ + C270_MJPEG, \ + C270_##SIZE, \ + _5FPS, \ + C270_EN, \ + 192, \ + C270_IF_ALT(192), \ + 4, \ + 3} + +// Logitech Qcam Orbit AF QCAM-200R +#define Q200R_VID 0x046d +#define Q200R_PID 0x0994 +#define Q200R_160x120 1 +#define Q200R_176x144 2 +#define Q200R_320x240 3 +#define Q200R_352x288 4 +#define Q200R_640x480 5 +#define Q200R_800x600 6 + +#define Q200R_MJPEG 1 +#define Q200R_YUV2 2 + +#define Q200R_EN 0x81 +#define Q200R_MPS 192 +#define Q200R_IF_ALT_192 1 +#define Q200R_IF_ALT_384 2 +#define Q200R_IF_ALT_512 3 +#define Q200R_IF_ALT_640 4 +#define Q200R_IF_ALT_800 5 +#define Q200R_IF_ALT_944 6 +#define Q200R_IF_ALT(A) Q200R_IF_ALT_##A +#define Q200R_INFO(SIZE) {Q200R_VID, Q200R_PID, _##SIZE, 0, \ + "Q200R", \ + Q200R_MJPEG, \ + Q200R_##SIZE, \ + _5FPS, \ + Q200R_EN, \ + 192, \ + Q200R_IF_ALT(192), \ + 4, \ + 3} + +//LifeCam VX700 / VX500 +#define VX700_VID 0x045e +#define VX700_PID 0x074a + +#define VX700_160x120 5 +#define VX700_176x144 4 +#define VX700_320x240 3 +#define VX700_352x288 2 +#define VX700_640x480 1 + +#define VX700_MJPEG 1 + +#define VX700_EN 0x81 +#define VX700_MPS 128 +#define VX700_IF_ALT_128 1 +#define VX700_IF_ALT(A) VX700_IF_ALT_##A +#define VX700_INFO(SIZE) {VX700_VID, VX700_PID, _##SIZE, 0, \ + "VX700", \ + VX700_MJPEG, \ + VX700_##SIZE, \ + _5FPS, \ + VX700_EN, \ + 128, \ + VX700_IF_ALT(128), \ + 4, \ + 3} + +//Sonix USB 2.0 Camera +#define SONIX_160x120 5 +#define SONIX_176x144 4 +#define SONIX_320x240 3 +#define SONIX_352x288 2 +#define SONIX_640x480 1 + +#define SONIX_IF_ALT_128 1 +#define SONIX_IF_ALT_256 2 +#define SONIX_IF_ALT_512 3 +#define SONIX_IF_ALT_600 4 +#define SONIX_IF_ALT_800 5 +#define SONIX_IF_ALT_956 6 +#define SONIX_IF_ALT(A) SONIX_IF_ALT_##A +#define SONIX_INFO(SIZE) {0x0c45, 0x62c0, _##SIZE, 0, \ + "SONIX", \ + 1, \ + SONIX_##SIZE, \ + _5FPS, \ + 0x81, \ + 128, \ + SONIX_IF_ALT(128), \ + 4, \ + 3} + +static const CamInfo CamInfoList[] = { +// Logitech C270 +C270_INFO(160x120), +C270_INFO(176x144), +C270_INFO(320x176), +C270_INFO(320x240), +C270_INFO(352x288), +C270_INFO(432x240), +C270_INFO(640x480), +C270_INFO(544x288), +C270_INFO(640x360), +C270_INFO(752x416), +C270_INFO(800x448), +C270_INFO(800x600), + +// Logitech C210 +C210_INFO(160x120), +C210_INFO(176x144), +C210_INFO(320x176), +C210_INFO(320x240), +C210_INFO(352x288), +C210_INFO(432x240), +C210_INFO(640x480), +C210_INFO(544x288), +C210_INFO(640x360), +C210_INFO(752x416), +C210_INFO(800x448), +C210_INFO(800x600), + +// Logitech Qcam Orbit AF QCAM-200R +Q200R_INFO(160x120), +Q200R_INFO(176x144), +Q200R_INFO(320x240), +Q200R_INFO(352x288), +Q200R_INFO(640x480), +Q200R_INFO(800x600), + +// LifeCam VX700 +VX700_INFO(160x120), +VX700_INFO(176x144), +VX700_INFO(320x240), +VX700_INFO(352x288), +VX700_INFO(640x480), + +// Sonix USB 2.0 Camera +SONIX_INFO(160x120), +SONIX_INFO(176x144), +SONIX_INFO(320x240), +SONIX_INFO(352x288), +SONIX_INFO(640x480), + +// Not found +{0,0,0,0}, +}; + +CamInfo* getCamInfoList() { + return const_cast<CamInfo*>(CamInfoList); +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/USBHostCam.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/USBHostCam.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,154 @@ +// USBHostCam.cpp +#include "USBHostCam.h" + +#if 0 +#define CAM_DBG(x, ...) std::printf("[%s:%d]"x"\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); +#else +#define CAM_DBG(...) while(0); +#endif +#define CAM_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); + +CamInfo* getCamInfoList(); // CamInfo.cpp + +USBHostCam::USBHostCam(uint8_t size, uint8_t option, CamInfo* user_caminfo) +{ + CAM_DBG("size: %d, option: %d", size, option); + _caminfo_size = size; + _caminfo_option = option; + if (user_caminfo) { + CamInfoList = user_caminfo; + } else { + CamInfoList = getCamInfoList(); + } + clearOnResult(); + host = USBHost::getHostInst(); + init(); +} + +void USBHostCam::init() +{ + CAM_DBG(""); + dev_connected = false; + dev = NULL; + ep_iso_in = NULL; + cam_intf = -1; + device_found = false; + caminfo_found = false; +} + +bool USBHostCam::connected() +{ + return dev_connected; +} + +bool USBHostCam::connect() +{ + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + CAM_DBG("Trying to connect Cam device\r\n"); + + if(host->enumerate(dev, this)) { + break; + } + if (device_found) { + USB_INFO("New Cam: %s device: VID:%04x PID:%04x [dev: %p - intf: %d]", caminfo->name, dev->getVid(), dev->getPid(), dev, cam_intf); + ep_iso_in = new USBEndpoint(dev); + ep_iso_in->init(ISOCHRONOUS_ENDPOINT, IN, caminfo->mps, caminfo->en); + ep_iso_in->ohci_init(caminfo->frameCount, caminfo->queueLimit); + uint8_t buf[26]; + memset(buf, 0, sizeof(buf)); + buf[2] = caminfo->formatIndex; + buf[3] = caminfo->frameIndex; + *reinterpret_cast<uint32_t*>(buf+4) = caminfo->interval; + USB_TYPE res = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, sizeof(buf)); + if (res != USB_TYPE_OK) { + USB_ERR("SET_CUR VS_COMMIT_CONTROL FAILED"); + } + res = setInterfaceAlternate(1, caminfo->if_alt); + if (res != USB_TYPE_OK) { + USB_ERR("SET_INTERFACE FAILED"); + } + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +/*virtual*/ void USBHostCam::setVidPid(uint16_t vid, uint16_t pid) +{ + CAM_DBG("vid:%04x,pid:%04x", vid, pid); + caminfo = CamInfoList; + while(caminfo->vid != 0) { + if (caminfo->vid == vid && caminfo->pid == pid && + caminfo->size == _caminfo_size && caminfo->option == _caminfo_option) { + caminfo_found = true; + break; + } + caminfo++; + } +} + +/*virtual*/ bool USBHostCam::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + CAM_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol); + if ((cam_intf == -1) && caminfo_found) { + cam_intf = intf_nb; + device_found = true; + return true; + } + return false; +} + +/*virtual*/ bool USBHostCam::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + CAM_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir); + return false; +} + +#define SEQ_READ_IDLE 0 +#define SEQ_READ_EXEC 1 +#define SEQ_READ_DONE 2 + +int USBHostCam::readJPEG(uint8_t* buf, int size, int timeout_ms) { + _buf = buf; + _pos = 0; + _size = size; + _seq = SEQ_READ_IDLE; + setOnResult(this, &USBHostCam::callback_motion_jpeg); + Timer timeout_t; + timeout_t.reset(); + timeout_t.start(); + while(timeout_t.read_ms() < timeout_ms && _seq != SEQ_READ_DONE) { + poll(); + } + return _pos; +} + +/* virtual */ void USBHostCam::outputJPEG(uint8_t c, int status) { // from decodeMJPEG + if (_seq == SEQ_READ_IDLE) { + if (status == JPEG_START) { + _pos = 0; + _seq = SEQ_READ_EXEC; + } + } + if (_seq == SEQ_READ_EXEC) { + if (_pos < _size) { + _buf[_pos++] = c; + } + if (status == JPEG_END) { + _seq = SEQ_READ_DONE; + } + } +} + +void USBHostCam::callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) { + inputPacket(buf, len); +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/USBHostCam.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/USBHostCam.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,100 @@ +// USBHostCam.h +#include "USBHostConf.h" +#include "USBHost.h" +#include "BaseUvc.h" +#include "decodeMJPEG.h" +#pragma once + +#define _160x120 2 +#define _176x144 3 +#define _320x176 4 +#define _320x240 5 +#define _352x288 6 +#define _432x240 7 +#define _640x480 1 +#define _544x288 8 +#define _640x360 9 +#define _752x416 10 +#define _800x448 11 +#define _800x600 12 + +#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; + +struct CamInfo { + uint16_t vid; + uint16_t pid; + uint8_t size; + uint8_t option; +// + const char* name; + uint8_t formatIndex; + uint8_t frameIndex; + uint32_t interval; + uint8_t en; + uint8_t mps; + uint8_t if_alt; + uint8_t frameCount; // ITD frame count 1-8 + uint8_t queueLimit; // ITD queue limit 1-3 +}; + +/** + * A class to communicate a Cam + */ +class USBHostCam : public IUSBEnumerator, public BaseUvc, public decodeMJPEG { +public: + /** + * Constructor + * + */ + USBHostCam(uint8_t size = _160x120, uint8_t option = 0, CamInfo* user_caminfo = NULL); + + /** + * Check if a Cam device is connected + * + * @return true if a Cam device is connected + */ + bool connected(); + + /** + * Try to connect to a Cam device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * read jpeg image + * + * @param buf read buffer + * @param size buffer size + * @param timeout_ms timeout default 15sec + * @return jpeg size if read success else -1 + */ + int readJPEG(uint8_t* buf, int size, int timeout_ms = 15*1000); + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + bool dev_connected; + + int cam_intf; + bool device_found; + bool caminfo_found; + + uint8_t _seq; + uint8_t* _buf; + int _pos; + int _size; + CamInfo* CamInfoList; + CamInfo* caminfo; + uint8_t _caminfo_size; + uint8_t _caminfo_option; + + virtual void outputJPEG(uint8_t c, int status); // from decodeMJPEG + void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len); + void init(); +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/decodeMJPEG.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/decodeMJPEG.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,180 @@ +// decodeMJPEG.cpp 2012/12/8 +// decode motion-jpeg to jpeg +#include "mbed.h" +#include "decodeMJPEG.h" + +#define MARK_SOF0 0xc0 +#define MARK_DHT 0xc4 +#define MARK_RST0 0xd0 +#define MARK_RST7 0xd7 +#define MARK_SOI 0xd8 +#define MARK_EOI 0xd9 +#define MARK_SOS 0xda +#define MARK_DQT 0xdb +#define MARK_DRI 0xdd +#define MARK_APP 0xe0 + +#define SEQ_INIT 0 +#define SEQ_SOI 1 +#define SEQ_FRAME 2 +#define SEQ_MARK 3 +#define SEQ_SEG_LEN 4 +#define SEQ_SEG_LEN2 5 +#define SEQ_SEG_BODY 6 +#define SEQ_SOS 7 +#define SEQ_SOS2 8 + +static const uint8_t dht[] = { +0xFF,0xC4,0x01,0xA2,0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A, +0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x10,0x00, +0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D,0x01, +0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22, +0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24, +0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29, +0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A, +0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A, +0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A, +0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8, +0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6, +0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,0xE3, +0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9, +0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01, +0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07, +0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33, +0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19, +0x1A,0x26,0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46, +0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66, +0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85, +0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3, +0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA, +0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8, +0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6, +0xF7,0xF8,0xF9,0xFA, +}; + +decodeMJPEG::decodeMJPEG() +{ + m_seq = SEQ_INIT; +} + +void decodeMJPEG::inputPacket(const uint8_t* buf, int len) +{ + for(int i = 12; i < len; i++) { + input(buf[i]); + } +} + +void decodeMJPEG::input(uint8_t c) +{ + switch(m_seq) { + case SEQ_INIT: + if (c == 0xff) { + m_seq = SEQ_SOI; + } + break; + case SEQ_SOI: + if (c == MARK_SOI) { + outputJPEG(0xff, JPEG_START); // start + outputJPEG(c); + m_bDHT = false; + m_seq = SEQ_FRAME; + } else { + m_seq = SEQ_INIT; + } + break; + case SEQ_FRAME: + if (c == 0xff) { + m_seq = SEQ_MARK; + } else { + m_seq = SEQ_INIT; + } + break; + case SEQ_MARK: + if (c == MARK_SOI || c == MARK_EOI || c == 0x00) { + m_seq = SEQ_INIT; + break; + } + m_mark = c; + m_seq = SEQ_SEG_LEN; + break; + case SEQ_SEG_LEN: + m_seg_len = c; + m_seq = SEQ_SEG_LEN2; + break; + case SEQ_SEG_LEN2: + m_seg_len <<= 8; + m_seg_len |= c; + m_seg_len -= 2; + m_seg_pos = 0; + m_seq = SEQ_SEG_BODY; + if (m_mark == MARK_SOS) { + if (m_bDHT == false) { + for(int i = 0; i < sizeof(dht); i++) { + outputJPEG(dht[i]); + } + } + m_output_desable = false; + } else if (m_mark == MARK_DHT) { + m_bDHT = true; + m_output_desable = false; + } else { + m_output_desable = false; + } + if (!m_output_desable) { + outputJPEG(0xff); + outputJPEG(m_mark); + outputJPEG((m_seg_len+2) >> 8); + outputJPEG((m_seg_len+2) & 0xff); + } + break; + case SEQ_SEG_BODY: + if (!m_output_desable) { + outputJPEG(c); + } + if (++m_seg_pos < m_seg_len) { + break; + } + if (m_mark == MARK_SOS) { + m_seq = SEQ_SOS; + break; + } + m_seq = SEQ_FRAME; + break; + case SEQ_SOS: + if (c == 0xff) { + m_seq = SEQ_SOS2; + break; + } + outputJPEG(c); + break; + case SEQ_SOS2: + if (c == 0x00) { + outputJPEG(0xff); + outputJPEG(0x00); + m_seq = SEQ_SOS; + break; + } else if (c >= MARK_RST0 && c <= MARK_RST7) { + outputJPEG(0xff); + outputJPEG(c); + m_seq = SEQ_SOS; + break; + } else if (c == MARK_EOI) { + outputJPEG(0xff); + outputJPEG(c, JPEG_END); + m_seq = SEQ_INIT; + break; + } else if (c == MARK_SOI) { + outputJPEG(0xff); + outputJPEG(c); + m_seq = SEQ_INIT; + break; + } + m_seq = SEQ_INIT; + break; + default: + m_seq = SEQ_INIT; + break; + } +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/decodeMJPEG.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostC270/decodeMJPEG.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,25 @@ +// decodeMJPEG.h 2012/12/9 +#ifndef DECODE_MJPEG_H +#define DECODE_MJPEG_H + +#define JPEG_NONE 0 +#define JPEG_START 1 +#define JPEG_END 2 +#define JPEG_ERROR 3 + +class decodeMJPEG { +public: + decodeMJPEG(); + void inputPacket(const uint8_t* buf, int len); + virtual void outputJPEG(uint8_t c, int status = JPEG_NONE) = 0; +protected: + void input(uint8_t c); + int m_seq; + uint8_t m_mark; + uint16_t m_seg_pos; + uint16_t m_seg_len; + bool m_bDHT; + bool m_output_desable; +}; + +#endif // DECODE_MJPEG_H
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/USBHostGPS.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostGPS/USBHostGPS.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,98 @@ +#include "USBHostGPS.h" + +USBHostGPS::USBHostGPS(int baud_) +{ + host = USBHost::getHostInst(); + init(); + baud = baud_; +} + +void USBHostGPS::init() { + dev = NULL; + bulk_in = NULL; + onUpdateRaw = NULL; + dev_connected = false; + gps_device_found = false; + gps_intf = -1; +} + +bool USBHostGPS::connected() { + return dev_connected; +} + +bool USBHostGPS::connect() { + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + if(host->enumerate(dev, this)) { + break; + } + if (gps_device_found) { + bulk_in = dev->getEndpoint(gps_intf, BULK_ENDPOINT, IN); + USB_TEST_ASSERT(bulk_in); + // stop bit = 1, parity = none, 8bit + uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08}; + USB_TYPE rc = host->controlWrite(dev, 0x21, PL2303_SET_LINE_CODING, 0, 0, data, sizeof(data)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_INFO("New GPS device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, gps_intf); + bulk_in->attach(this, &USBHostGPS::rxHandler); + host->bulkRead(dev, bulk_in, bulk_buf, bulk_in->getSize(), false); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostGPS::rxHandler() { + int len = bulk_in->getLengthTransferred(); + if (onUpdateRaw) { + (*onUpdateRaw)((char*)bulk_buf, len); + } + nmea.inputNMEA((char*)bulk_buf, len); + + if (dev) { + host->bulkRead(dev, bulk_in, bulk_buf, bulk_in->getSize(), false); + } +} + +/*virtual*/ void USBHostGPS::setVidPid(uint16_t vid, uint16_t pid) +{ + USB_DBG("vid:%04x pid:%04x", vid, pid); + if (pid == 0x2303) { + gps_device_found = true; + } +} + +/*virtual*/ bool USBHostGPS::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol); + if (gps_device_found) { + if (gps_intf == -1) { + gps_intf = intf_nb; + return true; + } + } + return false; +} + +/*virtual*/ bool USBHostGPS::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir); + if (gps_device_found) { + if (intf_nb == gps_intf) { + if (type == BULK_ENDPOINT && dir == IN) { + return true; + } + } + } + return false; +} +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/USBHostGPS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostGPS/USBHostGPS.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,60 @@ +// Simple USBHost GPS Dongle for FRDM-KL46Z +#include "USBHost.h" +#include "decodeNMEA.h" + +#define PL2303_SET_LINE_CODING 0x20 + +class USBHostGPS : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostGPS(int baud = 38400); + + /** + * Try to connect a USB GPS device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a USB GPS is connected + * + * @returns true if a mouse is connected + */ + bool connected(); + + int readNMEA(char* data, int size, int timeout_ms) { + host->bulkRead(dev, bulk_in, (uint8_t*)data, size); + return bulk_in->getLengthTransferred(); + } + void attachEventRaw(void (*ptr)(char* data, int size)) { + if (ptr != NULL) { + onUpdateRaw = ptr; + } + } + + decodeNMEA nmea; + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected* dev; + USBEndpoint* bulk_in; + bool dev_connected; + bool gps_device_found; + int gps_intf; + + void rxHandler(); + void (*onUpdateRaw)(char* data, int size); + uint8_t bulk_buf[64]; + int baud; + void init(); +};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/decodeNMEA.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostGPS/decodeNMEA.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,159 @@ +// decodeNMEA.cpp 2012/12/13 +#include "mbed.h" +#include "decodeNMEA.h" + +#define SEQ_INIT 0 +#define SEQ_DATA 1 +#define SEQ_SUM0 2 +#define SEQ_SUM1 3 + +#define GPGGA 1 +#define GPGLL 2 +#define GPGSV 3 +#define GPRMC 4 +#define GPVTG 5 +#define GPZDA 6 + +decodeNMEA::decodeNMEA():m_seq(0) { + gprmc_t = 0; + update_t = 0; + m_status = false; +} + +void decodeNMEA::inputNMEA(char* buf, int len) { + for(int i = 0; i < len; i++) { + inputNMEA(buf[i]); + } +} + +static int ctoh(char c) { + if (c >= '0' && c <= '9') { + return c-'0'; + } + return c-'A'+10; +} + +void decodeNMEA::inputNMEA(char c) { + switch(m_seq) { + case SEQ_INIT: + if (c == '$') { + m_type = 0; + m_row = 0; + m_buf_pos = 0; + m_sum = 0x00; + m_seq = SEQ_DATA; + } + break; + case SEQ_DATA: + m_sum ^= c; + if (c == ',' || c == '*') { + m_buf[m_buf_pos] = '\0'; + parse(m_type, m_row, m_buf); + m_row++; + m_buf_pos =0; + if (c == '*') { // check sum ? + m_sum ^= c; + m_seq = SEQ_SUM0; + } + } else { + if (m_buf_pos < sizeof(m_buf)-1) { + m_buf[m_buf_pos++] = c; + } + } + break; + case SEQ_SUM0: + if (ctoh(c) == (m_sum>>4)) { + m_seq = SEQ_SUM1; + } else { + m_seq = SEQ_INIT; + } + break; + case SEQ_SUM1: + if (ctoh(c) == (m_sum&0x0f)) { + update(m_type, m_row); + } else { + + m_seq = SEQ_INIT; + } + break; + default: + m_seq = SEQ_INIT; + break; + } +} + +float DMMtoDegree(const char *s) +{ + char *p = strchr(const_cast<char*>(s), '.'); + if (p == NULL) { + return 0.0; + } + const uint32_t k[] = {10000,1000,100,10,1}; + uint32_t i3 = atoi(p+1) * k[strlen(p+1)]; + uint32_t i2 = atoi(p-2); + uint32_t i1 = atoi(s) / 100; + + uint32_t i = i1*10000*60 + (i2*10000 + i3); + return i / 10000.0 / 60.0; +} + +void decodeNMEA::parse(int type, int row, char* buf) { + if (row == 0) { + if (strcmp(buf, "GPRMC") == 0) { + m_type = GPRMC; + m_status = false; + } else { + m_type = 0; + } + return; + } + if (type == GPRMC) { + switch(row) { + case 1: + tmp_timeinfo.tm_sec = atoi(buf+4); + buf[4] = '\0'; + tmp_timeinfo.tm_min = atoi(buf+2); + buf[2] = '\0'; + tmp_timeinfo.tm_hour = atoi(buf); + break; + case 2: + if (buf[0] == 'A') { + m_status = true; + } + break; + case 3: + tmp_lat = DMMtoDegree(buf); + break; + case 4: + if (buf[0] == 'S') { + tmp_lat *= -1; + } + break; + case 5: + tmp_lon = DMMtoDegree(buf); + break; + case 6: + if (buf[0] == 'W') { + tmp_lon *= -1; + } + break; + case 9: + tmp_timeinfo.tm_year = 2000 - 1900 + atoi(buf+4); + buf[4] = '\0'; + tmp_timeinfo.tm_mon = atoi(buf+2) - 1; + buf[2] = '\0'; + tmp_timeinfo.tm_mday = atoi(buf); + break; + } + } +} + +void decodeNMEA::update(int type, int row) { + if (type == GPRMC && m_status) { + lat = tmp_lat; + lon = tmp_lon; + gprmc_t = mktime(&tmp_timeinfo); + update_t = gprmc_t; + } +} +
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/decodeNMEA.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostGPS/decodeNMEA.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,28 @@ +// decodeNMEA.h 2012/12/15 +#ifndef DECODE_NMEA_H +#define DECODE_NMEA_H + +class decodeNMEA { +public: + decodeNMEA(); + void inputNMEA(char* buf, int len); + void inputNMEA(char c); + float lat,lon; + time_t gprmc_t; + time_t update_t; + +private: + void parse(int type, int row, char* buf); + void update(int type, int row); + int m_seq; + int m_type; + int m_row; + uint8_t m_sum; + char m_buf[12]; + int m_buf_pos; + bool m_status; + float tmp_lat,tmp_lon; + struct tm tmp_timeinfo; +}; + +#endif // DECODE_NMEA_H
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostGamepad.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostGamepad.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,254 @@ +/* mbed USBHost Gamepad driver sample + * Copyright (c) 2014 Yuuichi Akagawa + * + * modified from mbed USBHostMouse + * + * mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "USBHostGamepad.h" + +//#if USBHOST_GAMEPAD +USBHostGamepad::USBHostGamepad() +{ + host = USBHost::getHostInst(); + init(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void USBHostGamepad::init() +{ + dev = NULL; + int_in = NULL; + onUpdate = NULL; + report_id = 0; + dev_connected = false; + gamepad_device_found = false; + gamepad_intf = -1; + + btnX = 0; + btnY = 0; + btnABCD = 0; + btnSpecial = 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool USBHostGamepad::connected() +{ + return dev_connected; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool USBHostGamepad::connect() +{ + int len_listen; + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + if (host->enumerate(dev, this)) + break; + + if (gamepad_device_found) { + int_in = dev->getEndpoint(gamepad_intf, INTERRUPT_ENDPOINT, IN); + if (!int_in) + break; + + USB_INFO + ( + "New Gamepad/Joystick device: VID:%04x PID:%04x [dev: %p - intf: %d]", + dev->getVid(), + dev->getPid(), + dev, + gamepad_intf + ); +#if DEBUG > 3 + //Parse HID Report Descriptor + + parseHidDescr(); +#endif + dev->setName("Gamepad", gamepad_intf); + host->registerDriver(dev, gamepad_intf, this, &USBHostGamepad::init); + + int_in->attach(this, &USBHostGamepad::rxHandler); + len_listen = int_in->getSize(); + if (len_listen > sizeof(report)) { + len_listen = sizeof(report); + } + + host->interruptRead(dev, int_in, report, len_listen, false); + + dev_connected = true; + return true; + } + } + } + + init(); + return false; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void USBHostGamepad::rxHandler() +{ + int len_listen = int_in->getSize(); +#if DEBUG > 3 + USB_DBG("USBHostGamepad::rxHandler() len_listen=%d\r\n", len_listen); + for (int i = 0; i < len_listen; i++) + printf("%02X ", report[i]); + printf("\r\n\r\n"); +#endif + if (onUpdate) { + (*onUpdate) (report[0], report[1], report[5], report[6]); + } + + // update gamepad state + btnX = report[0]; + btnY = report[1]; + btnABCD = report[5]; + btnSpecial = report[6]; + + if (len_listen > sizeof(report)) { + len_listen = sizeof(report); + } + + if (dev) + host->interruptRead(dev, int_in, report, len_listen, false); +} + +/*virtual*/ +void USBHostGamepad::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for gamepad driver +} + +/*virtual*/ +bool USBHostGamepad::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((gamepad_intf == -1) && (intf_class == HID_CLASS) && (intf_subclass == 0x00) && (intf_protocol == 0x00)) { + gamepad_intf = intf_nb; + return true; + } + + return false; +} + +//Must return true if the endpoint will be used + +/*virtual*/ +bool USBHostGamepad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) +{ + if (intf_nb == gamepad_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + gamepad_device_found = true; + return true; + } + } + + return false; +} + +/** + * @brief + * @note + * @param + * @retval + */ +USB_TYPE USBHostGamepad::getReportDescriptor +( + USBDeviceConnected* dev, + uint8_t* buf, + uint16_t max_len_buf, + uint16_t* len_rep_descr +) +{ + USB_TYPE t = host->controlRead + ( + dev, + USB_DEVICE_TO_HOST | USB_RECIPIENT_INTERFACE | USB_REQUEST_TYPE_STANDARD, + HID_GET_DESCRIPTOR, + 0x2200, + 0, + buf, + max_len_buf + ); + if (len_rep_descr) + *len_rep_descr = max_len_buf; + + return t; +} + +/* + * HID Report Descriptor parser + */ +//bool USBHostGamepad::parseHidDescr() +//{ +// bool ret = true; +// uint8_t* buf; +// uint16_t desclen = host->getLengthReportDescr(); +// //allocate report descriptor's buffer +// buf = (uint8_t*)malloc(desclen); +// if (buf == NULL) { +// return false; +// } +// getReportDescriptor(dev, buf, desclen); +//#if (DEBUG > 3) +// USB_DBG("HID REPORT DESCRIPTOR:\r\n"); +// for (int i = 0; i < desclen; i++) +// printf("%02X ", buf[i]); +// printf("\r\n\r\n"); +//#endif +// if (buf[0] == 0x05 //Usage page +// && buf[1] == 0x01 //Generic Desktop +// && buf[2] == 0x09 //Usage +// ) { +// if (buf[3] == 0x04) { +// USB_DBG("GAMEPAD"); +// } +// else +// if (buf[3] == 0x05) { +// USB_DBG("JOYSTICK"); +// } +// else { +// ret = false; +// } +// } +// free(buf); +// return ret; +//} +//#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostGamepad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostGamepad.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,126 @@ +/* mbed USBHost Gamepad driver sample + * Copyright (c) 2014 Yuuichi Akagawa + * + * modified from mbed USBHostMouse + * + * Copyright (c) 2014 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef USBHOSTGAMEPAD_H +#define USBHOSTGAMEPAD_H + +#include "USBHostConf.h" + +//#if USBHOST_GAMEPAD + +#include "USBHost.h" +//HID Class Request + +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_GET_DESCRIPTOR 0x06 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0a +#define HID_SET_PROTOCOL 0x0b + +/** + * A class to communicate a USB MIDI device + */ + +class USBHostGamepad : + public IUSBEnumerator +{ +public: + /** + * Constructor + */ + USBHostGamepad(); + + /** + * Try to connect a gamepad device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a gamepad is connected + * + * @returns true if a gamepad is connected + */ + bool connected(); + + /** + * Attach a callback called when a gamepad event is received + * + * @param ptr function pointer + */ + inline void attachEvent(void (*ptr) (uint8_t btnX, uint8_t btnY, uint8_t btnABCD, uint8_t btnSpecial)) + { + if (ptr != NULL) { + onUpdate = ptr; + } + } + + /** + * Request the HID report descriptor + * + * @param dev request the device descriptor on this device + * @param buf buffer to store the device descriptor + * @param max_len_buf maximum size of buf + * @param len_dev_descr pointer to store the length of the packet transferred + */ + USB_TYPE getReportDescriptor + ( + USBDeviceConnected* dev, + uint8_t* buf, + uint16_t max_len_buf, + uint16_t* len_rep_descr = NULL + ); +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost* host; + USBDeviceConnected* dev; + USBEndpoint* int_in; + + bool dev_connected; + bool gamepad_device_found; + int gamepad_intf; + + uint8_t report[8]; + + void rxHandler(); + void (*onUpdate) (uint8_t btnX, uint8_t btnY, uint8_t btnABCD, uint8_t btnSpecial); + int report_id; + void init(); + +// bool parseHidDescr(); +public: + uint8_t btnX; + uint8_t btnY; + uint8_t btnABCD; + uint8_t btnSpecial; +}; + +//#endif +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostKeyboard.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostKeyboard.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,163 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostKeyboard.h" + +#if USBHOST_KEYBOARD + +/*$off*/ +static uint8_t keymap[4][0x39] = { + { 0, 0, 0, 0, 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + 0x0A /*enter*/, 0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', '=', '[', ']', '\\', + '#', ';', '\'', 0, ',', '.', '/' + }, + + /* CTRL MODIFIER */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, + + /* SHIFT MODIFIER */ + { 0, 0, 0, 0, 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + 0, 0, 0, 0, 0, 0, '+', '{', '}', '|', + '~', ':', '"', 0, '<', '>', '?' + }, + + /* ALT MODIFIER */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, +}; +/*$on*/ + +USBHostKeyboard::USBHostKeyboard() { + host = USBHost::getHostInst(); + init(); +} + +void USBHostKeyboard::init() { + dev = NULL; + int_in = NULL; + report_id = 0; + onKey = NULL; + onKeyCode = NULL; + dev_connected = false; + keyboard_intf = -1; + keyboard_device_found = false; +} + +bool USBHostKeyboard::connected() { + return dev_connected; +} + + +bool USBHostKeyboard::connect() { + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + if (host->enumerate(dev, this)) + break; + + if (keyboard_device_found) { + int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN); + + if (!int_in) + break; + + USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf); + dev->setName("Keyboard", keyboard_intf); + host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init); + + int_in->attach(this, &USBHostKeyboard::rxHandler); + host->interruptRead(dev, int_in, report, int_in->getSize(), false); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostKeyboard::rxHandler() { + int len = int_in->getLengthTransferred(); + int index = (len == 9) ? 1 : 0; + int len_listen = int_in->getSize(); + uint8_t key = 0; + if (len == 8 || len == 9) { + uint8_t modifier = (report[index] == 4) ? 3 : report[index]; + len_listen = len; + key = keymap[modifier][report[index + 2]]; + if (key && onKey) { + (*onKey)(key); + } + if ((report[index + 2] || modifier) && onKeyCode) { + (*onKeyCode)(report[index + 2], modifier); + } + } + if (dev && int_in) + host->interruptRead(dev, int_in, report, len_listen, false); +} + +/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for keyboard driver +} + +/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((keyboard_intf == -1) && + (intf_class == HID_CLASS) && + (intf_subclass == 0x01) && + (intf_protocol == 0x01)) { + keyboard_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == keyboard_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + keyboard_device_found = true; + return true; + } + } + return false; +} + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostKeyboard.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostKeyboard.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,102 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTKEYBOARD_H +#define USBHOSTKEYBOARD_H + +#include "USBHostConf.h" + +#if USBHOST_KEYBOARD + +#include "USBHost.h" + +/** + * A class to communicate a USB keyboard + */ +class USBHostKeyboard : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostKeyboard(); + + /** + * Try to connect a keyboard device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a keyboard is connected + * + * @returns true if a keyboard is connected + */ + bool connected(); + + /** + * Attach a callback called when a keyboard event is received + * + * @param ptr function pointer + */ + inline void attach(void (*ptr)(uint8_t key)) { + if (ptr != NULL) { + onKey = ptr; + } + } + + /** + * Attach a callback called when a keyboard event is received + * + * @param ptr function pointer + */ + inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) { + if (ptr != NULL) { + onKeyCode = ptr; + } + } + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * int_in; + uint8_t report[9]; + int keyboard_intf; + bool keyboard_device_found; + + bool dev_connected; + + void rxHandler(); + + void (*onKey)(uint8_t key); + void (*onKeyCode)(uint8_t key, uint8_t modifier); + + int report_id; + + void init(); + +}; + +#endif + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostMouse.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostMouse.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,191 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "USBHostMouse.h" + +#if USBHOST_MOUSE + +/** + * @brief + * @note + * @param + * @retval + */ +USBHostMouse::USBHostMouse() +{ + host = USBHost::getHostInst(); + init(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void USBHostMouse::init() +{ + dev = NULL; + int_in = NULL; + onUpdate = NULL; + onButtonUpdate = NULL; + onXUpdate = NULL; + onYUpdate = NULL; + onZUpdate = NULL; + report_id = 0; + dev_connected = false; + mouse_device_found = false; + mouse_intf = -1; + + buttons = 0; + x = 0; + y = 0; + z = 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool USBHostMouse::connected() +{ + return dev_connected; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool USBHostMouse::connect() +{ + int len_listen; + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + if (host->enumerate(dev, this)) + break; + + if (mouse_device_found) { + int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN); + if (!int_in) + break; + + USB_INFO + ( + "New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", + dev->getVid(), + dev->getPid(), + dev, + mouse_intf + ); + dev->setName("Mouse", mouse_intf); + host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init); + + int_in->attach(this, &USBHostMouse::rxHandler); + len_listen = int_in->getSize(); + if (len_listen > sizeof(report)) { + len_listen = sizeof(report); + } + + host->interruptRead(dev, int_in, report, len_listen, false); + + dev_connected = true; + return true; + } + } + } + + init(); + return false; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void USBHostMouse::rxHandler() +{ + int len_listen = int_in->getSize(); + + if (onUpdate) { + (*onUpdate) (report[0] & 0x07, report[1], report[2], report[3]); + } + + if (onButtonUpdate && (buttons != (report[0] & 0x07))) { + (*onButtonUpdate) (report[0] & 0x07); + } + + if (onXUpdate && (x != report[1])) { + (*onXUpdate) (report[1]); + } + + if (onYUpdate && (y != report[2])) { + (*onYUpdate) (report[2]); + } + + if (onZUpdate && (z != report[3])) { + (*onZUpdate) (report[3]); + } + + // update mouse state + buttons = report[0] & 0x07; + x = report[1]; + y = report[2]; + z = report[3]; + + if (dev) + host->interruptRead(dev, int_in, report, len_listen, false); +} + +/*virtual*/ +void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for mouse driver +} + +/*virtual*/ +bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((mouse_intf == -1) && (intf_class == HID_CLASS) && (intf_subclass == 0x01) && (intf_protocol == 0x02)) { + mouse_intf = intf_nb; + return true; + } + + return false; +} + +/*virtual*/ +bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == mouse_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + mouse_device_found = true; + return true; + } + } + + return false; +} +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostMouse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostHID/USBHostMouse.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,139 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTMOUSE_H +#define USBHOSTMOUSE_H + +#include "USBHostConf.h" + +#if USBHOST_MOUSE + +#include "USBHost.h" + +/** + * A class to communicate a USB mouse + */ +class USBHostMouse : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostMouse(); + + /** + * Try to connect a mouse device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a mouse is connected + * + * @returns true if a mouse is connected + */ + bool connected(); + + /** + * Attach a callback called when a mouse event is received + * + * @param ptr function pointer + */ + inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) { + if (ptr != NULL) { + onUpdate = ptr; + } + } + + /** + * Attach a callback called when the button state changes + * + * @param ptr function pointer + */ + inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) { + if (ptr != NULL) { + onButtonUpdate = ptr; + } + } + + /** + * Attach a callback called when the X axis value changes + * + * @param ptr function pointer + */ + inline void attachXEvent(void (*ptr)(int8_t x)) { + if (ptr != NULL) { + onXUpdate = ptr; + } + } + + /** + * Attach a callback called when the Y axis value changes + * + * @param ptr function pointer + */ + inline void attachYEvent(void (*ptr)(int8_t y)) { + if (ptr != NULL) { + onYUpdate = ptr; + } + } + + /** + * Attach a callback called when the Z axis value changes (scrolling) + * + * @param ptr function pointer + */ + inline void attachZEvent(void (*ptr)(int8_t z)) { + if (ptr != NULL) { + onZUpdate = ptr; + } + } + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * int_in; + uint8_t report[4]; + + bool dev_connected; + bool mouse_device_found; + int mouse_intf; + + uint8_t buttons; + int8_t x; + int8_t y; + int8_t z; + + void rxHandler(); + void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z); + void (*onButtonUpdate)(uint8_t buttons); + void (*onXUpdate)(int8_t x); + void (*onYUpdate)(int8_t y); + void (*onZUpdate)(int8_t z); + int report_id; + void init(); +}; + +#endif + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostMSD/USBHostMSD.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostMSD/USBHostMSD.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,356 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostMSD.h" + +#if USBHOST_MSD + +#include "dbg.h" + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +#define DEVICE_TO_HOST 0x80 +#define HOST_TO_DEVICE 0x00 + +#define GET_MAX_LUN (0xFE) +#define BO_MASS_STORAGE_RESET (0xFF) + +USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir) +{ + host = USBHost::getHostInst(); + init(); +} + +void USBHostMSD::init() { + dev_connected = false; + dev = NULL; + bulk_in = NULL; + bulk_out = NULL; + dev_connected = false; + blockSize = 0; + blockCount = 0; + msd_intf = -1; + msd_device_found = false; + disk_init = false; + dev_connected = false; + nb_ep = 0; +} + + +bool USBHostMSD::connected() +{ + return dev_connected; +} + +bool USBHostMSD::connect() +{ + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + USB_DBG("Trying to connect MSD device\r\n"); + + if(host->enumerate(dev, this)) + break; + + if (msd_device_found) { + bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN); + bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT); + + if (!bulk_in || !bulk_out) + continue; + + USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf); + dev->setName("MSD", msd_intf); + host->registerDriver(dev, msd_intf, this, &USBHostMSD::init); + + dev_connected = true; + return true; + } + } //if() + } //for() + init(); + return false; +} + +/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for MSD driver +} + +/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((msd_intf == -1) && + (intf_class == MSD_CLASS) && + (intf_subclass == 0x06) && + (intf_protocol == 0x50)) { + msd_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == msd_intf) { + if (type == BULK_ENDPOINT) { + nb_ep++; + if (nb_ep == 2) + msd_device_found = true; + return true; + } + } + return false; +} + + +int USBHostMSD::testUnitReady() { + USB_DBG("Test unit ready"); + return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0); +} + + +int USBHostMSD::readCapacity() { + USB_DBG("Read capacity"); + uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0}; + uint8_t result[8]; + int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8); + if (status == 0) { + blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]; + blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7]; + USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize); + } + return status; +} + + +int USBHostMSD::SCSIRequestSense() { + USB_DBG("Request sense"); + uint8_t cmd[6] = {0x03,0,0,0,18,0}; + uint8_t result[18]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); + return status; +} + + +int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) { + USB_DBG("Inquiry"); + uint8_t evpd = (page_code == 0) ? 0 : 1; + uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0}; + uint8_t result[36]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); + if (status == 0) { + char vid_pid[17]; + memcpy(vid_pid, &result[8], 8); + vid_pid[8] = 0; + USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid); + + memcpy(vid_pid, &result[16], 16); + vid_pid[16] = 0; + USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid); + + memcpy(vid_pid, &result[32], 4); + vid_pid[4] = 0; + USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid); + } + return status; +} + +int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) { + // if ep stalled: send clear feature + if (res == USB_TYPE_STALL_ERROR) { + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, ep->getAddress(), NULL, 0); + // set state to IDLE if clear feature successful + if (res == USB_TYPE_OK) { + ep->setState(USB_TYPE_IDLE); + } + } + + if (res != USB_TYPE_OK) + return -1; + + return 0; +} + + +int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) { + + int res = 0; + + cbw.Signature = CBW_SIGNATURE; + cbw.Tag = 0; + cbw.DataLength = transfer_len; + cbw.Flags = flags; + cbw.LUN = 0; + cbw.CBLength = cmd_len; + memset(cbw.CB,0,sizeof(cbw.CB)); + if (cmd) { + memcpy(cbw.CB,cmd,cmd_len); + } + + // send the cbw + USB_DBG("Send CBW"); + res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); + if (checkResult(res, bulk_out)) + return -1; + + // data stage if needed + if (data) { + USB_DBG("data stage"); + if (flags == HOST_TO_DEVICE) { + + res = host->bulkWrite(dev, bulk_out, data, transfer_len); + if (checkResult(res, bulk_out)) + return -1; + + } else if (flags == DEVICE_TO_HOST) { + + res = host->bulkRead(dev, bulk_in, data, transfer_len); + if (checkResult(res, bulk_in)) + return -1; + } + } + + // status stage + csw.Signature = 0; + USB_DBG("Read CSW"); + res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); + if (checkResult(res, bulk_in)) + return -1; + + if (csw.Signature != CSW_SIGNATURE) { + return -1; + } + + USB_DBG("recv csw: status: %d", csw.Status); + + // ModeSense? + if ((csw.Status == 1) && (cmd[0] != 0x03)) { + USB_DBG("request mode sense"); + return SCSIRequestSense(); + } + + // perform reset recovery + if ((csw.Status == 2) && (cmd[0] != 0x03)) { + + // send Bulk-Only Mass Storage Reset request + res = host->controlWrite( dev, + USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, + BO_MASS_STORAGE_RESET, + 0, msd_intf, NULL, 0); + + // unstall both endpoints + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_in->getAddress(), NULL, 0); + + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_out->getAddress(), NULL, 0); + + } + + return csw.Status; +} + + +int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) { + uint8_t cmd[10]; + memset(cmd,0,10); + cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; + + cmd[2] = (block >> 24) & 0xff; + cmd[3] = (block >> 16) & 0xff; + cmd[4] = (block >> 8) & 0xff; + cmd[5] = block & 0xff; + + cmd[7] = (nbBlock >> 8) & 0xff; + cmd[8] = nbBlock & 0xff; + + return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); +} + +int USBHostMSD::getMaxLun() { + uint8_t buf[1], res; + res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + 0xfe, 0, msd_intf, buf, 1); + USB_DBG("max lun: %d", buf[0]); + return res; +} + +int USBHostMSD::disk_initialize() { + USB_DBG("FILESYSTEM: init"); + /* U16 */int i, timeout = 10; + + getMaxLun(); + + for (i = 0; i < timeout; i++) { + wait_ms(100); //Thread::wait(100); + if (!testUnitReady()) + break; + } + + if (i == timeout) { + disk_init = false; + return -1; + } + + inquiry(0, 0); + disk_init = 1; + return readCapacity(); +} + +int USBHostMSD::disk_write(const uint8_t *buffer, uint32_t sector, uint32_t count) { + USB_DBG("FILESYSTEM: write sector: %lld, count: %d", sector, count); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, sector, count, HOST_TO_DEVICE); +} + +int USBHostMSD::disk_read(uint8_t * buffer, uint32_t sector, uint32_t count) { + USB_DBG("FILESYSTEM: read sector: %lld, count: %d", sector, count); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, sector, count, DEVICE_TO_HOST); +} + +uint32_t USBHostMSD::disk_sectors() { + USB_DBG("FILESYSTEM: sectors"); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return 0; + return blockCount; +} + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostMSD/USBHostMSD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostMSD/USBHostMSD.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,119 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTMSD_H +#define USBHOSTMSD_H + +#include "USBHostConf.h" + +#if USBHOST_MSD + +#include "USBHost.h" +#include "FATFileSystem.h" + +/** + * A class to communicate a USB flash disk + */ +class USBHostMSD : public IUSBEnumerator, public FATFileSystem { +public: + /** + * Constructor + * + * @param rootdir mount name + */ + USBHostMSD(const char * rootdir); + + /** + * Check if a MSD device is connected + * + * @return true if a MSD device is connected + */ + bool connected(); + + /** + * Try to connect to a MSD device + * + * @return true if connection was successful + */ + bool connect(); + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + + // From FATFileSystem + virtual int disk_initialize(); + virtual int disk_status() {return 0;} + virtual int disk_read(uint8_t * buffer, uint32_t sector, uint32_t count); + virtual int disk_write(const uint8_t * buffer, uint32_t sector, uint32_t count); + virtual int disk_sync() {return 0;} + virtual uint32_t disk_sectors(); + +private: + USBHost * host; + USBDeviceConnected * dev; + bool dev_connected; + USBEndpoint * bulk_in; + USBEndpoint * bulk_out; + uint8_t nb_ep; + + // Bulk-only CBW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; + } PACKED CBW; + + // Bulk-only CSW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; + } PACKED CSW; + + CBW cbw; + CSW csw; + + int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len); + int testUnitReady(); + int readCapacity(); + int inquiry(uint8_t lun, uint8_t page_code); + int SCSIRequestSense(); + int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction); + int checkResult(uint8_t res, USBEndpoint * ep); + int getMaxLun(); + + int blockSize; + uint64_t blockCount; + + int msd_intf; + bool msd_device_found; + bool disk_init; + + void init(); + +}; + +#endif + +#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostRSSI/USBHostRSSI.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostRSSI/USBHostRSSI.cpp Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,193 @@ +#include "USBHostRSSI.h" + +USBHostRSSI::USBHostRSSI() +{ + host = USBHost::getHostInst(); + init(); +} + +void USBHostRSSI::init() +{ + dev = NULL; + int_in = NULL; + onUpdate = NULL; + dev_connected = false; + bluetooth_device_found = false; + bluetooth_intf = -1; + seq = 0; + +} + +bool USBHostRSSI::connected() { + return dev_connected; +} + +bool USBHostRSSI::connect() { + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + if(host->enumerate(dev, this)) { + break; + } + if (bluetooth_device_found) { + int_in = dev->getEndpoint(bluetooth_intf, INTERRUPT_ENDPOINT, IN); + USB_DBG("int_in=%p", int_in); + if (!int_in) { + break; + } + USB_INFO("New Bluetooth device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, bluetooth_intf); + int_in->attach(this, &USBHostRSSI::rxHandler); + int rc = host->interruptRead(dev, int_in, int_buf, sizeof(int_buf), false); + USB_TEST_ASSERT(rc != USB_TYPE_ERROR); + rc = cmdSend(HCI_OP_RESET); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostRSSI::rxHandler() { + event(int_buf, int_in->getLengthTransferred()); + if (dev) { + host->interruptRead(dev, int_in, int_buf, sizeof(int_buf), false); + } +} + +/*virtual*/ void USBHostRSSI::setVidPid(uint16_t vid, uint16_t pid) +{ + USB_DBG("vid:%04x pid:%04x", vid, pid); + // we don't check VID/PID for mouse driver +} + +/*virtual*/ bool USBHostRSSI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol); + if (bluetooth_intf == -1 && intf_class == 0xe0) { + bluetooth_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostRSSI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir); + + if (intf_nb == bluetooth_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + bluetooth_device_found = true; + return true; + } + } + return false; +} + +void USBHostRSSI::event(uint8_t* data, int len) { + CTASSERT(sizeof(BD_ADDR) == 6); + CTASSERT(sizeof(inquiry_with_rssi_info) == 14); + inquiry_with_rssi_info* info; + int max_period_length = 25; + int min_period_length = 20; + int inquiry_length = 15; + USB_TYPE rc; + if (len > 0) { + USB_DBG_HEX(data, len); + hci_event* event = reinterpret_cast<hci_event*>(data); + switch(event->evt) { + case HCI_EV_CMD_COMPLETE: + switch(event->c.op) { + case HCI_OP_RESET: + wait_ms(500); + rc = cmdSend(HCI_OP_WRITE_INQUIRY_MODE, "B", 0x01); // with RSSI + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + } + break; + case HCI_OP_WRITE_INQUIRY_MODE: + rc = cmdSend(HCI_OP_PERIODIC_INQUIRY, "HHBBBBB", + max_period_length, min_period_length, 0x33, 0x8B, 0x9E, inquiry_length, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + break; + default: + break; + } + break; + case HCI_EV_INQUIRY_RESULT_WITH_RSSI: + //USB_DBG_HEX(buf, r); + info = reinterpret_cast<inquiry_with_rssi_info*>(event->c.data); + if (onUpdate) { + (*onUpdate)(info); + } + break; + default: + break; + } + } +} + +USB_TYPE USBHostRSSI::cmdSend(uint16_t op) +{ + return cmdSendSub(op, NULL, 0); +} + +USB_TYPE USBHostRSSI::cmdSend(uint16_t op, const char* fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + uint8_t buf[255]; + int pos = 0; + char* name; + int name_len; + uint16_t h; + BD_ADDR* bdaddr; + for(int i = 0; fmt[i]; i++) { + switch(fmt[i]) { + case 's': + name = va_arg(vl, char*); + name_len = strlen(name)+1; + memcpy(buf+pos, name, name_len); + pos += name_len; + break; + case 'B': + buf[pos++] = va_arg(vl, int); + break; + case 'H': + h = va_arg(vl, int); + buf[pos++] = h; + buf[pos++] = h>>8; + break; + case 'A': + bdaddr = va_arg(vl, BD_ADDR*); + memcpy(buf+pos, bdaddr, 6); + pos += 6; + break; + default: + USB_DBG("op=%04X fmt=%s i=%d", op, fmt, i); + break; + } + } + return cmdSendSub(op, buf, pos); +} + +USB_TYPE USBHostRSSI::cmdSendSub(uint16_t op, const uint8_t* data, int size) +{ + uint8_t* buf = new uint8_t[size+3]; + buf[0] = op; + buf[1] = op>>8; + buf[2] = size; + if (data) { + memcpy(buf+3, data, size); + } + USB_TYPE rc = host->controlWrite(dev, USB_REQUEST_TYPE_CLASS, 0, 0, 0, buf, size+3); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + delete[] buf; + return rc; +}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostRSSI/USBHostRSSI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost-STM32F4/USBHostRSSI/USBHostRSSI.h Tue Feb 19 21:32:56 2019 +0000 @@ -0,0 +1,145 @@ +// Simple USBHost Bluetooth RSSI for FRDM-KL46Z +#pragma once +#include "USBHost.h" +#include <stdarg.h> + +#define HCI_OP_INQUIRY 0x0401 +#define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_PERIODIC_INQUIRY 0x0403 +#define HCI_OP_EXIT_PERIODIC_INQUIRY 0x0404 +#define HCI_OP_REMOTE_NAME_REQ 0x0419 +#define HCI_OP_RESET 0x0c03 +#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a +#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24 +#define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 +#define HCI_OP_READ_EXTENDED_INQUIRY_RESPONSE 0x0c51 +#define HCI_OP_WRITE_EXTENDED_INQUIRY_RESPONSE 0x0c52 +#define HCI_OP_READ_BD_ADDR 0x1009 + +#define HCI_EV_INQUIRY_COMPLETE 0x01 +#define HCI_EV_INQUIRY_RESULT 0x02 +#define HCI_EV_REMOTE_NAME 0x07 +#define HCI_EV_CMD_COMPLETE 0x0e +#define HCI_EV_CMD_STATUS 0x0f +#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f + +#pragma pack(push,1) +struct BD_ADDR { + uint8_t addr[6]; + void set(char* s) { + char* p = s; + for(int i = 5; i >= 0; i--) { + addr[i] = strtol(p, &p, 16); + if (*p == ':') { + p++; + } + } + } + void str(char* buf, size_t size) { + snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); + } + void str_mask(char* buf, size_t size) { + snprintf(buf, size, "%02X:%02X:%02X:xx:xx:xx", addr[5], addr[4], addr[3]); + } + bool eq(BD_ADDR* a) { + return memcmp(addr, a->addr, 6) == 0; + } + bool eq_vendor(BD_ADDR* a) { + return memcmp(addr+3, a->addr+3, 3) == 0; + } +}; + +struct inquiry_info { + BD_ADDR bdaddr; + uint8_t page_scan_repetition_mode; + uint8_t reserved[2]; + uint8_t dev_class[3]; + uint16_t clock_offset; +}; + +struct inquiry_with_rssi_info { // offset + BD_ADDR bdaddr; // +0 + uint8_t page_scan_repetition_mode;// +6 + uint8_t reserved[1]; // +7 + uint8_t class_of_device[3]; // +8 + uint16_t clock_offset; // +11 + int8_t rssi; // +13 +}; // +14 + +struct extended_inquiry_info { + BD_ADDR bdaddr; + uint8_t page_scan_repetition_mode; + uint8_t reserved[1]; + uint8_t class_of_device[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t extended_inquiry_response[240]; +}; + +struct hci_event { + uint8_t evt; + uint8_t len; + uint8_t status; + union { + uint16_t op; + uint8_t data[2]; + } c; +}; +#pragma pack(pop) + +class USBHostRSSI : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostRSSI(); + + /** + * Try to connect a BT device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a mouse is connected + * + * @returns true if a BT is connected + */ + bool connected(); + + void attachEvent(void (*ptr)(inquiry_with_rssi_info* info)) { + if (ptr != NULL) { + onUpdate = ptr; + } + } + //Report* report; + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * int_in; + bool dev_connected; + bool bluetooth_device_found; + int bluetooth_intf; + + void rxHandler(); + void (*onUpdate)(inquiry_with_rssi_info* info); + uint8_t int_buf[64]; + int seq; + void event(uint8_t* data, int size); + USB_TYPE cmdSend(uint16_t op); + USB_TYPE cmdSend(uint16_t op, const char* fmt, ...); + USB_TYPE cmdSendSub(uint16_t op, const uint8_t* data, int size); + void init(); +}; +