I was workign on some other USBHost extensions and found I needed debug information that was being generated by a Teensy plugged into the USB host port that was output using Serial Emulation to be available. Likewise I wanted the ability to feed data back to that other Teensy. So I decided to create USBHost_t36 implemention to handle the USB types that include Serial Emulation USBSerialEmu class. The USBSerialEmu code was based on the USBSerial code as well as RAWHID. I found that there was a bug in the Receiving of data that was sent by the remote SEREMU output, I would miss the first character Fixed. USBSerial fixed same bug in reading first charactermain
/* USB EHCI Host for Teensy 3.6 | |||||
* Copyright 2017 Paul Stoffregen (paul@pjrc.com) | |||||
* | |||||
* 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. | |||||
*/ | |||||
#include <Arduino.h> | |||||
#include "USBHost_t36.h" // Read this header first for key info | |||||
//#define SEREMU_PRINT_DEBUG | |||||
void USBSerialEmu::init() | |||||
{ | |||||
USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||||
USBHIDParser::driver_ready_for_hid_collection(this); | |||||
} | |||||
hidclaim_t USBSerialEmu::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage) | |||||
{ | |||||
// only claim SerEMU devices currently: 16c0:0486 | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.printf("SerEMU Claim: %x:%x usage: %x\n", dev->idVendor, dev->idProduct, topusage); | |||||
#endif | |||||
if (dev->idVendor != 0x16c0) return CLAIM_NO; // NOT PJRC | |||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO; | |||||
if (usage_) return CLAIM_NO; // Only claim one | |||||
// make sure it is the SEREMU usage | |||||
if (topusage != 0xffc90004) return CLAIM_NO; // Not the SEREMU | |||||
mydevice = dev; | |||||
collections_claimed++; | |||||
usage_ = topusage; | |||||
driver_ = driver; // remember the driver. | |||||
rx_head_ = 0;// receive head | |||||
rx_tail_ = 0;// receive tail | |||||
tx_head_ = 0; | |||||
rx_pipe_size_ = driver->inSize(); | |||||
tx_pipe_size_ = driver->outSize(); | |||||
tx_out_data_pending_ = 0; | |||||
//if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE)) { | |||||
tx_buffer_[0] = 0; | |||||
tx_buffer_[1] = 0; | |||||
tx_buffer_[2] = 0; | |||||
tx_buffer_[3] = 0; | |||||
driver_->sendControlPacket( 0x21, 0x9, 0x300, driver_->interfaceNumber(), 4, tx_buffer_); | |||||
return CLAIM_INTERFACE; // We wa | |||||
} | |||||
void USBSerialEmu::disconnect_collection(Device_t *dev) | |||||
{ | |||||
if (--collections_claimed == 0) { | |||||
mydevice = NULL; | |||||
usage_ = 0; | |||||
} | |||||
} | |||||
bool USBSerialEmu::hid_process_in_data(const Transfer_t *transfer) | |||||
{ | |||||
uint16_t len = transfer->length; | |||||
const uint8_t *buffer = (const uint8_t *)transfer->buffer; | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.printf("USBSerialEmu::hid_process_in_data: %x %d: %x %x %x\n", usage_, len, buffer[0], buffer[1], buffer[2]); | |||||
#endif | |||||
const uint8_t *buffer_end = buffer + len -1; | |||||
while ((buffer_end > buffer) && (*buffer_end == 0))buffer_end--; | |||||
// lets trim off the trailing null characters. | |||||
// Now lets move the bytes onto our queue. | |||||
uint16_t tail = rx_tail_; | |||||
while (buffer <= buffer_end) { | |||||
uint16_t new_head = rx_head_ + 1; | |||||
if (new_head == RX_BUFFER_SIZE) new_head = 0; | |||||
if (new_head == tail) break; // we don't have room so bail out. | |||||
rx_buffer_[rx_head_] = *buffer++; | |||||
rx_head_ = new_head; // point off to the new next head. | |||||
} | |||||
return true; | |||||
} | |||||
bool USBSerialEmu::hid_process_out_data(const Transfer_t *transfer) | |||||
{ | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.printf("USBSerialEmu::hid_process_out_data: %x\n", usage_); | |||||
#endif | |||||
if (tx_out_data_pending_) { | |||||
tx_out_data_pending_--; | |||||
} | |||||
return true; | |||||
} | |||||
bool USBSerialEmu::sendPacket() | |||||
{ | |||||
USBHDBGSerial.printf("SEMU: SendPacket\n"); | |||||
if (!driver_) return false; | |||||
if (!driver_->sendPacket(tx_buffer_)) return false; | |||||
tx_out_data_pending_++; | |||||
tx_head_ = 0; | |||||
return true; | |||||
} | |||||
int USBSerialEmu::available(void) | |||||
{ | |||||
if (!driver_) return 0; | |||||
uint32_t head = rx_head_; | |||||
uint32_t tail = rx_tail_; | |||||
if (head >= tail) return head - tail; | |||||
return RX_BUFFER_SIZE + head - tail; | |||||
} | |||||
int USBSerialEmu::peek(void) | |||||
{ | |||||
if (!driver_) return -1; | |||||
if (rx_head_ == rx_tail_) return -1; | |||||
return rx_buffer_[rx_tail_]; | |||||
} | |||||
int USBSerialEmu::read(void) | |||||
{ | |||||
if (!driver_) return -1; | |||||
if (rx_head_ == rx_tail_) return -1; | |||||
int c = rx_buffer_[rx_tail_]; | |||||
if (++rx_tail_ >= RX_BUFFER_SIZE) rx_tail_ = 0; | |||||
return c; | |||||
} | |||||
int USBSerialEmu::availableForWrite() | |||||
{ | |||||
if (!driver_) return 0; | |||||
return tx_pipe_size_ - tx_head_ + (2-tx_out_data_pending_)*tx_pipe_size_; | |||||
} | |||||
size_t USBSerialEmu::write(uint8_t c) | |||||
{ | |||||
// Single buffer, as our HID device has double buffers. | |||||
if (c >= ' ') USBHDBGSerial.printf("SEMU: %c\n", c); | |||||
else USBHDBGSerial.printf("SEMU: 0x%x\n", c); | |||||
if (!driver_) return 0; | |||||
if (tx_head_ == tx_pipe_size_) { | |||||
while (!sendPacket()) yield(); // wait until the device above queues this packet | |||||
} | |||||
tx_buffer_[tx_head_++] = c; | |||||
// if this character filled it. then try to queue it again | |||||
if (tx_head_ == tx_pipe_size_) sendPacket(); | |||||
driver_->stopTimer(); | |||||
driver_->startTimer(write_timeout_); | |||||
return 1; | |||||
} | |||||
void USBSerialEmu::flush(void) | |||||
{ | |||||
if (!driver_) return; | |||||
USBHDBGSerial.printf("SEMU: flush\n"); | |||||
driver_->stopTimer(); // Stop longer timer. | |||||
driver_->startTimer(100); // Start a mimimal timeout | |||||
if (tx_head_) sendPacket(); | |||||
// And wait for HID to say they were all sent. | |||||
elapsedMillis em = 0; | |||||
while (tx_out_data_pending_ && (em < 10000)) yield(); // wait up to 10 seconds? | |||||
} | |||||
void USBSerialEmu::hid_timer_event(USBDriverTimer *whichTimer) | |||||
{ | |||||
USBHDBGSerial.printf("SEMU: Timer\n"); | |||||
if (!driver_) return; | |||||
driver_->stopTimer(); | |||||
if (tx_head_) { | |||||
memset(tx_buffer_ + tx_head_, 0, tx_pipe_size_ - tx_head_); // clear the rest of bytes in buffer. | |||||
sendPacket(); | |||||
} | |||||
} | |||||
void USBSerialEmu::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax) | |||||
{ | |||||
// These should not be called as we are claiming the whole interface and not | |||||
// allowing the parse to happen | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.printf("SerEMU::hid_input_begin %x %x %x %x\n", topusage, type, lgmin, lgmax); | |||||
#endif | |||||
//hid_input_begin_ = true; | |||||
} | |||||
void USBSerialEmu::hid_input_data(uint32_t usage, int32_t value) | |||||
{ | |||||
// These should not be called as we are claiming the whole interface and not | |||||
// allowing the parse to happen | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.printf("SerEMU: usage=%X, value=%d", usage, value); | |||||
if ((value >= ' ') && (value <='~')) USBHDBGSerial.printf("(%c)", value); | |||||
USBHDBGSerial.println(); | |||||
#endif | |||||
} | |||||
void USBSerialEmu::hid_input_end() | |||||
{ | |||||
// These should not be called as we are claiming the whole interface and not | |||||
// allowing the parse to happen | |||||
#ifdef SEREMU_PRINT_DEBUG | |||||
USBHDBGSerial.println("SerEMU::hid_input_end"); | |||||
#endif | |||||
// if (hid_input_begin_) { | |||||
// hid_input_begin_ = false; | |||||
// } | |||||
} |
// USBHost. | // USBHost. | ||||
class USBDriver; | class USBDriver; | ||||
class USBDriverTimer; | class USBDriverTimer; | ||||
class USBHIDInput; | |||||
/************************************************/ | /************************************************/ | ||||
/* Added Defines */ | /* Added Defines */ | ||||
public: | public: | ||||
USBDriverTimer() { } | USBDriverTimer() { } | ||||
USBDriverTimer(USBDriver *d) : driver(d) { } | USBDriverTimer(USBDriver *d) : driver(d) { } | ||||
USBDriverTimer(USBHIDInput *hd) : driver(nullptr), hidinput(hd) { } | |||||
void init(USBDriver *d) { driver = d; }; | void init(USBDriver *d) { driver = d; }; | ||||
void start(uint32_t microseconds); | void start(uint32_t microseconds); | ||||
void stop(); | void stop(); | ||||
uint32_t started_micros; // testing only | uint32_t started_micros; // testing only | ||||
private: | private: | ||||
USBDriver *driver; | USBDriver *driver; | ||||
USBHIDInput *hidinput; | |||||
uint32_t usec; | uint32_t usec; | ||||
USBDriverTimer *next; | USBDriverTimer *next; | ||||
USBDriverTimer *prev; | USBDriverTimer *prev; | ||||
const uint8_t *serialNumber() | const uint8_t *serialNumber() | ||||
{ return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | { return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | ||||
private: | private: | ||||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage); | virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage); | ||||
virtual bool hid_process_in_data(const Transfer_t *transfer) {return false;} | virtual bool hid_process_in_data(const Transfer_t *transfer) {return false;} | ||||
virtual void hid_input_data(uint32_t usage, int32_t value); | virtual void hid_input_data(uint32_t usage, int32_t value); | ||||
virtual void hid_input_end(); | virtual void hid_input_end(); | ||||
virtual void disconnect_collection(Device_t *dev); | virtual void disconnect_collection(Device_t *dev); | ||||
virtual void hid_timer_event(USBDriverTimer *whichTimer) { } | |||||
void add_to_list(); | void add_to_list(); | ||||
USBHIDInput *next = NULL; | USBHIDInput *next = NULL; | ||||
friend class USBHIDParser; | friend class USBHIDParser; | ||||
class USBHIDParser : public USBDriver { | class USBHIDParser : public USBDriver { | ||||
public: | public: | ||||
USBHIDParser(USBHost &host) { init(); } | |||||
USBHIDParser(USBHost &host) : hidTimer(this) { init(); } | |||||
static void driver_ready_for_hid_collection(USBHIDInput *driver); | static void driver_ready_for_hid_collection(USBHIDInput *driver); | ||||
bool sendPacket(const uint8_t *buffer, int cb=-1); | bool sendPacket(const uint8_t *buffer, int cb=-1); | ||||
void setTXBuffers(uint8_t *buffer1, uint8_t *buffer2, uint8_t cb); | void setTXBuffers(uint8_t *buffer1, uint8_t *buffer2, uint8_t cb); | ||||
bool sendControlPacket(uint32_t bmRequestType, uint32_t bRequest, | bool sendControlPacket(uint32_t bmRequestType, uint32_t bRequest, | ||||
uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf); | uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf); | ||||
// Atempt for RAWhid and SEREMU to take over processing of data | |||||
// | |||||
uint16_t inSize(void) {return in_size;} | |||||
uint16_t outSize(void) {return out_size;} | |||||
void startTimer(uint32_t microseconds) {hidTimer.start(microseconds);} | |||||
void stopTimer() {hidTimer.stop();} | |||||
uint8_t interfaceNumber() { return bInterfaceNumber;} | |||||
protected: | protected: | ||||
enum { TOPUSAGE_LIST_LEN = 4 }; | enum { TOPUSAGE_LIST_LEN = 4 }; | ||||
enum { USAGE_LIST_LEN = 24 }; | enum { USAGE_LIST_LEN = 24 }; | ||||
virtual void disconnect(); | virtual void disconnect(); | ||||
static void in_callback(const Transfer_t *transfer); | static void in_callback(const Transfer_t *transfer); | ||||
static void out_callback(const Transfer_t *transfer); | static void out_callback(const Transfer_t *transfer); | ||||
virtual void timer_event(USBDriverTimer *whichTimer); | |||||
void in_data(const Transfer_t *transfer); | void in_data(const Transfer_t *transfer); | ||||
void out_data(const Transfer_t *transfer); | void out_data(const Transfer_t *transfer); | ||||
bool check_if_using_report_id(); | bool check_if_using_report_id(); | ||||
void parse(uint16_t type_and_report_id, const uint8_t *data, uint32_t len); | void parse(uint16_t type_and_report_id, const uint8_t *data, uint32_t len); | ||||
void init(); | void init(); | ||||
// Atempt for RAWhid to take over processing of data | |||||
// | |||||
uint16_t inSize(void) {return in_size;} | |||||
uint16_t outSize(void) {return out_size;} | |||||
uint8_t activeSendMask(void) {return txstate;} | uint8_t activeSendMask(void) {return txstate;} | ||||
uint8_t *tx1 = nullptr; | uint8_t *tx1 = nullptr; | ||||
uint8_t *tx2 = nullptr; | uint8_t *tx2 = nullptr; | ||||
bool hid_driver_claimed_control_ = false; | bool hid_driver_claimed_control_ = false; | ||||
USBDriverTimer hidTimer; | |||||
uint8_t bInterfaceNumber = 0; | |||||
}; | }; | ||||
//-------------------------------------------------------------------------- | //-------------------------------------------------------------------------- | ||||
//-------------------------------------------------------------------------- | //-------------------------------------------------------------------------- | ||||
class USBSerialEmu : public USBHIDInput, public Stream { | |||||
public: | |||||
USBSerialEmu(USBHost &host) { init(); } | |||||
uint32_t usage(void) {return usage_;} | |||||
// Stream stuff. | |||||
uint32_t writeTimeout() {return write_timeout_;} | |||||
void writeTimeOut(uint32_t write_timeout) {write_timeout_ = write_timeout;} // Will not impact current ones. | |||||
virtual int available(void); | |||||
virtual int peek(void); | |||||
virtual int read(void); | |||||
virtual int availableForWrite(); | |||||
virtual size_t write(uint8_t c); | |||||
virtual void flush(void); | |||||
using Print::write; | |||||
protected: | |||||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage); | |||||
virtual bool hid_process_in_data(const Transfer_t *transfer); | |||||
virtual bool hid_process_out_data(const Transfer_t *transfer); | |||||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | |||||
virtual void hid_input_data(uint32_t usage, int32_t value); | |||||
virtual void hid_input_end(); | |||||
virtual void disconnect_collection(Device_t *dev); | |||||
virtual void hid_timer_event(USBDriverTimer *whichTimer); | |||||
bool sendPacket(); | |||||
private: | |||||
void init(); | |||||
USBHIDParser *driver_; | |||||
enum { MAX_PACKET_SIZE = 64 }; | |||||
bool (*receiveCB)(uint32_t usage, const uint8_t *data, uint32_t len) = nullptr; | |||||
uint8_t collections_claimed = 0; | |||||
uint32_t usage_ = 0; | |||||
// We have max of 512 byte packets coming in. How about enough room for 3+3 | |||||
enum { RX_BUFFER_SIZE=1024, TX_BUFFER_SIZE = 512 }; | |||||
enum { DEFAULT_WRITE_TIMEOUT = 3500}; | |||||
uint8_t rx_buffer_[RX_BUFFER_SIZE]; | |||||
uint8_t tx_buffer_[TX_BUFFER_SIZE]; | |||||
volatile uint8_t tx_out_data_pending_ = 0; | |||||
volatile uint16_t rx_head_;// receive head | |||||
volatile uint16_t rx_tail_;// receive tail | |||||
volatile uint16_t tx_head_; | |||||
uint16_t rx_pipe_size_;// size of receive circular buffer | |||||
uint16_t tx_pipe_size_;// size of transmit circular buffer | |||||
uint32_t write_timeout_ = DEFAULT_WRITE_TIMEOUT; | |||||
// See if we can contribute transfers | |||||
Transfer_t mytransfers[2] __attribute__ ((aligned(32))); | |||||
}; | |||||
//-------------------------------------------------------------------------- | |||||
class BluetoothController: public USBDriver { | class BluetoothController: public USBDriver { | ||||
public: | public: | ||||
static const uint8_t MAX_CONNECTIONS = 4; | static const uint8_t MAX_CONNECTIONS = 4; | ||||
bool deviceAvailable = false; | bool deviceAvailable = false; | ||||
}; | }; | ||||
#endif | #endif |
uint32_t numendpoint = descriptors[4]; | uint32_t numendpoint = descriptors[4]; | ||||
if (numendpoint < 1 || numendpoint > 2) return false; | if (numendpoint < 1 || numendpoint > 2) return false; | ||||
if (descriptors[5] != 3) return false; // bInterfaceClass, 3 = HID | if (descriptors[5] != 3) return false; // bInterfaceClass, 3 = HID | ||||
println(" bInterfaceNumber = ", descriptors[2]); | |||||
println(" bInterfaceClass = ", descriptors[5]); | println(" bInterfaceClass = ", descriptors[5]); | ||||
println(" bInterfaceSubClass = ", descriptors[6]); | println(" bInterfaceSubClass = ", descriptors[6]); | ||||
println(" bInterfaceProtocol = ", descriptors[7]); | println(" bInterfaceProtocol = ", descriptors[7]); | ||||
topusage_drivers[i] = NULL; | topusage_drivers[i] = NULL; | ||||
} | } | ||||
// request the HID report descriptor | // request the HID report descriptor | ||||
bInterfaceNumber = descriptors[2]; // save away the interface number; | |||||
mk_setup(setup, 0x81, 6, 0x2200, descriptors[2], descsize); // get report desc | mk_setup(setup, 0x81, 6, 0x2200, descriptors[2], descsize); // get report desc | ||||
queue_Control_Transfer(dev, &setup, descriptor, this); | queue_Control_Transfer(dev, &setup, descriptor, this); | ||||
return true; | return true; | ||||
} | } | ||||
USBHDBGSerial.printf("\n"); */ | USBHDBGSerial.printf("\n"); */ | ||||
/* | |||||
print("HID: "); | print("HID: "); | ||||
print(use_report_id); | print(use_report_id); | ||||
print(" - "); | print(" - "); | ||||
print_hexbytes(transfer->buffer, transfer->length); | print_hexbytes(transfer->buffer, transfer->length); | ||||
*/ | |||||
const uint8_t *buf = (const uint8_t *)transfer->buffer; | const uint8_t *buf = (const uint8_t *)transfer->buffer; | ||||
uint32_t len = transfer->length; | uint32_t len = transfer->length; | ||||
} | } | ||||
} | } | ||||
void USBHIDParser::timer_event(USBDriverTimer *whichTimer) | |||||
{ | |||||
if (topusage_drivers[0]) { | |||||
topusage_drivers[0]->hid_timer_event(whichTimer); | |||||
} | |||||
} | |||||
bool USBHIDParser::sendPacket(const uint8_t *buffer, int cb) { | bool USBHIDParser::sendPacket(const uint8_t *buffer, int cb) { | ||||
if (!out_size || !out_pipe) return false; | if (!out_size || !out_pipe) return false; | ||||
if (!tx1) { | if (!tx1) { |
MIDIDevice_BigBuffer KEYWORD1 | MIDIDevice_BigBuffer KEYWORD1 | ||||
USBSerial KEYWORD1 | USBSerial KEYWORD1 | ||||
USBSerial_BigBuffer KEYWORD1 | USBSerial_BigBuffer KEYWORD1 | ||||
USBSerialEmu KEYWORD1 | |||||
USBSerialBase KEYWORD1 | USBSerialBase KEYWORD1 | ||||
AntPlus KEYWORD1 | AntPlus KEYWORD1 | ||||
JoystickController KEYWORD1 | JoystickController KEYWORD1 |
version=0.1 | version=0.1 | ||||
author=Paul Stoffregen | author=Paul Stoffregen | ||||
maintainer=Paul Stoffregen | maintainer=Paul Stoffregen | ||||
sentence=Connect USB devices to the USB Host of Teensy 3.6. | |||||
sentence=Connect USB devices to the USB Host of Teensy 3.6 and Teensy 4.x | |||||
paragraph= | paragraph= | ||||
category=Communication | category=Communication | ||||
url=https://github.com/PaulStoffregen/USBHost_t36 | url=https://github.com/PaulStoffregen/USBHost_t36 | ||||
architectures=* | architectures=* | ||||
includes=USBHost_t36 |
USBHDBGSerial.printf("Rawhid Claim: %x:%x usage: %x\n", dev->idVendor, dev->idProduct, topusage); | USBHDBGSerial.printf("Rawhid Claim: %x:%x usage: %x\n", dev->idVendor, dev->idProduct, topusage); | ||||
#endif | #endif | ||||
if ((dev->idVendor != 0x16c0 || (dev->idProduct) != 0x486)) return CLAIM_NO; | |||||
if (dev->idVendor != 0x16c0) return CLAIM_NO; // NOT PJRC | |||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO; | if (mydevice != NULL && dev != mydevice) return CLAIM_NO; | ||||
if (usage_) return CLAIM_NO; // Only claim one | if (usage_) return CLAIM_NO; // Only claim one | ||||
if (fixed_usage_ && (fixed_usage_ != topusage)) return CLAIM_NO; // See if we want specific one and if so is it this one | |||||
if (fixed_usage_ ) { | |||||
if (fixed_usage_ != topusage) return CLAIM_NO; // See if we want specific one and if so is it this one | |||||
} else if (dev->idProduct != 0x486) return CLAIM_NO; // otherwise mainly used for RAWHID Serial type. | |||||
mydevice = dev; | mydevice = dev; | ||||
collections_claimed++; | collections_claimed++; | ||||
usage_ = topusage; | usage_ = topusage; |
int USBSerialBase::peek(void) | int USBSerialBase::peek(void) | ||||
{ | { | ||||
if (!device) return -1; | if (!device) return -1; | ||||
uint32_t head = rxhead; | |||||
uint32_t tail = rxtail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= rxsize) tail = 0; | |||||
return rxbuf[tail]; | |||||
if (rxhead == rxtail) return -1; | |||||
return rxbuf[rxtail]; | |||||
} | } | ||||
int USBSerialBase::read(void) | int USBSerialBase::read(void) | ||||
{ | { | ||||
if (!device) return -1; | if (!device) return -1; | ||||
uint32_t head = rxhead; | |||||
uint32_t tail = rxtail; | |||||
if (head == tail) return -1; | |||||
if (++tail >= rxsize) tail = 0; | |||||
int c = rxbuf[tail]; | |||||
rxtail = tail; | |||||
if (rxhead == rxtail) return -1; | |||||
int c = rxbuf[rxtail]; | |||||
if (++rxtail >= rxsize) rxtail = 0; | |||||
if ((rxstate & 0x03) != 0x03) { | if ((rxstate & 0x03) != 0x03) { | ||||
NVIC_DISABLE_IRQ(IRQ_USBHS); | NVIC_DISABLE_IRQ(IRQ_USBHS); | ||||
rx_queue_packets(head, tail); | |||||
rx_queue_packets(rxhead, rxtail); | |||||
NVIC_ENABLE_IRQ(IRQ_USBHS); | NVIC_ENABLE_IRQ(IRQ_USBHS); | ||||
} | } | ||||
return c; | return c; |