Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768
Dependents: F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld
Fork of KL46Z-USBHost by
簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
Platforms
- Nucleo F446RE
- Nucleo F411RE
- Nucleo F401RE
- FRDM-K64F
- FRDM-KL46Z
- FRDM-KL25Z
- LPC4088
- LPC1768
Nucleo F446RE/F411RE/F401REのUSB接続方法
ST morpho | USB |
---|---|
U5V (CN10-8) | VBUS (1 RED) |
PA11 (CN10-14) | DM (2 WHITE) |
PA12 (CN10-12) | DP (3 GREEN) |
GND (CN10-20) | GND (4 BLACK) |
Examples
Import programF446RE-USBHostMouse_HelloWorld
USBHostMouse Hello World for ST-Nucleo-F446RE
Import programF401RE-USBHostMSD_HelloWorld
Simple USBHost MSD(USB flash drive) for Nucleo F401RE/FRDM-KL46Z test program
Import programF401RE-USBHostC270_example
Simple USBHost WebCam test program
Import programK64F_USBHostC270_example
Simple USBHost C270 example
Import programF401RE-BTstack_example
BTstack for Nucleo F401RE/FRDM-KL46Z example program
Import programUSBHostRSSI_example
Bluetooth device discovery example program.
Import programKL46Z-USBHostGPS_HelloWorld
Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program
Revision 13:8774c07f12a5, committed 2014-06-10
- Comitter:
- va009039
- Date:
- Tue Jun 10 13:38:41 2014 +0900
- Parent:
- 12:b91fdea8c0a7
- Child:
- 14:b167f2b97cb7
- Commit message:
- add USBHostC270
Changed in this revision
--- a/USBHost/USBHALHost2_F401RE.cpp Mon Jun 09 09:01:10 2014 +0000 +++ b/USBHost/USBHALHost2_F401RE.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -199,6 +199,12 @@ USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); } + else if(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC) + { + USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM; + hhcd->hc[chnum].urb_state = URB_DONE; + HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state); + } hhcd->hc[chnum].toggle_in ^= 1; }
--- a/USBHost/USBHALHost_F401RE.cpp Mon Jun 09 09:01:10 2014 +0000 +++ b/USBHost/USBHALHost_F401RE.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -409,24 +409,17 @@ } int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { - USBDeviceConnected* dev = ep->getDevice(); - HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_ISO_IN, - ep->getAddress(), - dev->getAddress(), - HCD_SPEED_FULL, - EP_TYPE_ISOC, ep->getSize()); - - token_done = false; + static bool init = false; + if (!init) { + init = true; + USBDeviceConnected* dev = ep->getDevice(); + HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_ISO_IN, + ep->getAddress(), dev->getAddress(), + HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize()); + } HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_ISO_IN, DIR_IN, EP_TYPE_ISOC, 1, data, size, 0); - while(!token_done); - - switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_ISO_IN)) { - case URB_DONE: + while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_ISO_IN) == URB_IDLE); return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_ISO_IN); - - default: - return -1; - } } #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/BaseUvc.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,55 @@ +// 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) { + 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; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/BaseUvc.h Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,51 @@ +// BaseUvc.h +//#include "USBIsochronous.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; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/CamInfo.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,188 @@ +// 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), \ + } + +#define C210_PID 0x819 +#define C210_INFO(SIZE) {C270_VID, C210_PID, _##SIZE, 0, \ + "C270", \ + C270_MJPEG, \ + C270_##SIZE, \ + _5FPS, \ + C270_EN, \ + 192, \ + C270_IF_ALT(192), \ + } + +// 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), \ + } + +//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), \ + } + +//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), \ + } + +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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/USBHostCam.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,191 @@ +// 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); + 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; +} + +#if 0 +void USBHostCam::setup() { + caminfo = CamInfoList; + bool found = false; + while(caminfo->vid != 0) { + if (caminfo->vid == host->getDevice(0)->getVid() && + caminfo->pid == host->getDevice(0)->getPid() && + caminfo->size == _caminfo_size && caminfo->option == _caminfo_option) { + found = true; + break; + } + caminfo++; + } + if (!found) { + CAM_INFO("caminfo not found."); + exit(1); + } + CAM_INFO("Found: %s", caminfo->name); + + ep_iso_in.setAddress(caminfo->en); + ep_iso_in.setSize(caminfo->mps); + 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"); + } +} +#endif + + +/*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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/USBHostCam.h Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,98 @@ +// 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; +}; + +/** + * 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(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/decodeMJPEG.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostC270/decodeMJPEG.h Tue Jun 10 13:38:41 2014 +0900 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/USBHostGPS.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -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; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/USBHostGPS.h Tue Jun 10 13:38:41 2014 +0900 @@ -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(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/decodeNMEA.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -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; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/decodeNMEA.h Tue Jun 10 13:38:41 2014 +0900 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostKeyboard.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,184 @@ +/* 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 + +static uint8_t keymap[4][0x39] = { + { 0, 0, 0, 0, 'a', 'b' /*0x05*/, + 'c', 'd', 'e', 'f', 'g' /*0x0a*/, + 'h', 'i', 'j', 'k', 'l'/*0x0f*/, + 'm', 'n', 'o', 'p', 'q'/*0x14*/, + 'r', 's', 't', 'u', 'v'/*0x19*/, + 'w', 'x', 'y', 'z', '1'/*0x1E*/, + '2', '3', '4', '5', '6'/*0x23*/, + '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/ + 0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/ + '=', '[', ']', '\\', '#', /*0x32*/ + ';', '\'', 0, ',', '.', /*0x37*/ + '/'}, + + /* CTRL MODIFIER */ + { 0, 0, 0, 0, 0, 0 /*0x05*/, + 0, 0, 0, 0, 0 /*0x0a*/, + 0, 0, 0, 0, 0/*0x0f*/, + 0, 0, 0, 0, 0/*0x14*/, + 0, 0, 0, 0, 0/*0x19*/, + 0, 0, 0, 0, 0/*0x1E*/, + 0, 0, 0, 0, 0/*0x23*/, + 0, 0, 0, 0, 0 /*enter*/, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + 0, 0, 0, 0, 0, /*0x32*/ + 0, 0, 0, 0, 0, /*0x37*/ + 0}, + + /* SHIFT MODIFIER */ + { 0, 0, 0, 0, 'A', 'B' /*0x05*/, + 'C', 'D', 'E', 'F', 'G' /*0x0a*/, + 'H', 'I', 'J', 'K', 'L'/*0x0f*/, + 'M', 'N', 'O', 'P', 'Q'/*0x14*/, + 'R', 'S', 'T', 'U', 'V'/*0x19*/, + 'W', 'X', 'Y', 'Z', '!'/*0x1E*/, + '@', '#', '$', '%', '^'/*0x23*/, + '&', '*', '(', ')', 0, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + '+', '{', '}', '|', '~', /*0x32*/ + ':', '"', 0, '<', '>', /*0x37*/ + '?'}, + + /* ALT MODIFIER */ + { 0, 0, 0, 0, 0, 0 /*0x05*/, + 0, 0, 0, 0, 0 /*0x0a*/, + 0, 0, 0, 0, 0/*0x0f*/, + 0, 0, 0, 0, 0/*0x14*/, + 0, 0, 0, 0, 0/*0x19*/, + 0, 0, 0, 0, 0/*0x1E*/, + 0, 0, 0, 0, 0/*0x23*/, + 0, 0, 0, 0, 0 /*enter*/, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + 0, 0, 0, 0, 0, /*0x32*/ + 0, 0, 0, 0, 0, /*0x37*/ + 0} + +}; + + +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostKeyboard.h Tue Jun 10 13:38:41 2014 +0900 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,144 @@ +/* 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 + +USBHostMouse::USBHostMouse() { + host = USBHost::getHostInst(); + init(); +} + +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; +} + +bool USBHostMouse::connected() { + return dev_connected; +} + +bool USBHostMouse::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 (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); + host->interruptRead(dev, int_in, report, int_in->getSize(), false); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.h Tue Jun 10 13:38:41 2014 +0900 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostRSSI/USBHostRSSI.cpp Tue Jun 10 13:38:41 2014 +0900 @@ -0,0 +1,191 @@ +#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); + 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostRSSI/USBHostRSSI.h Tue Jun 10 13:38:41 2014 +0900 @@ -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[]; + } 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(); +}; +