1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-24 01:52:23 -05:00

Merge pull request #13 from KurtE/XBOX1-Keyboard

Xbox1 keyboard
This commit is contained in:
Paul Stoffregen 2017-12-13 03:46:51 -08:00 committed by GitHub
commit 5cd2d8c799
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1372 additions and 391 deletions

View File

@ -56,7 +56,7 @@
// your best effort to read chapter 4 before asking USB questions! // your best effort to read chapter 4 before asking USB questions!
//#define USBHOST_PRINT_DEBUG #define USBHOST_PRINT_DEBUG
/************************************************/ /************************************************/
/* Data Types */ /* Data Types */
@ -80,6 +80,7 @@ class USBHost;
typedef struct Device_struct Device_t; typedef struct Device_struct Device_t;
typedef struct Pipe_struct Pipe_t; typedef struct Pipe_struct Pipe_t;
typedef struct Transfer_struct Transfer_t; typedef struct Transfer_struct Transfer_t;
typedef enum { CLAIM_NO=0, CLAIM_REPORT, CLAIM_INTERFACE} hidclaim_t;
// All USB device drivers inherit use these classes. // All USB device drivers inherit use these classes.
// Drivers build user-visible functionality on top // Drivers build user-visible functionality on top
@ -91,6 +92,7 @@ class USBDriverTimer;
/************************************************/ /************************************************/
/* Added Defines */ /* Added Defines */
/************************************************/ /************************************************/
// Keyboard special Keys
#define KEYD_UP 0xDA #define KEYD_UP 0xDA
#define KEYD_DOWN 0xD9 #define KEYD_DOWN 0xD9
#define KEYD_LEFT 0xD8 #define KEYD_LEFT 0xD8
@ -114,6 +116,22 @@ class USBDriverTimer;
#define KEYD_F11 0xCC #define KEYD_F11 0xCC
#define KEYD_F12 0xCD #define KEYD_F12 0xCD
// USBSerial formats - Lets encode format into bits
// Bits: 0-4 - Number of data bits
// Bits: 5-7 - Parity (0=none, 1=odd, 2 = even)
// bits: 8-9 - Stop bits. 0=1, 1=2
#define USBHOST_SERIAL_7E1 0x047
#define USBHOST_SERIAL_7O1 0x027
#define USBHOST_SERIAL_8N1 0x08
#define USBHOST_SERIAL_8N2 0x108
#define USBHOST_SERIAL_8E1 0x048
#define USBHOST_SERIAL_8O1 0x028
/************************************************/ /************************************************/
/* Data Structure Definitions */ /* Data Structure Definitions */
/************************************************/ /************************************************/
@ -252,11 +270,12 @@ protected:
static void disconnect_Device(Device_t *dev); static void disconnect_Device(Device_t *dev);
static void enumeration(const Transfer_t *transfer); static void enumeration(const Transfer_t *transfer);
static void driver_ready_for_device(USBDriver *driver); static void driver_ready_for_device(USBDriver *driver);
static volatile bool enumeration_busy;
public: // Maybe others may want/need to contribute memory example HID devices may want to add transfers.
static void contribute_Devices(Device_t *devices, uint32_t num); static void contribute_Devices(Device_t *devices, uint32_t num);
static void contribute_Pipes(Pipe_t *pipes, uint32_t num); static void contribute_Pipes(Pipe_t *pipes, uint32_t num);
static void contribute_Transfers(Transfer_t *transfers, uint32_t num); static void contribute_Transfers(Transfer_t *transfers, uint32_t num);
static void contribute_String_Buffers(strbuf_t *strbuf, uint32_t num); static void contribute_String_Buffers(strbuf_t *strbuf, uint32_t num);
static volatile bool enumeration_busy;
private: private:
static void isr(); static void isr();
static void convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer); static void convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer);
@ -452,6 +471,8 @@ private:
// Device drivers may inherit from this base class, if they wish to receive // Device drivers may inherit from this base class, if they wish to receive
// HID input data fully decoded by the USBHIDParser driver // HID input data fully decoded by the USBHIDParser driver
class USBHIDParser;
class USBHIDInput { class USBHIDInput {
public: public:
operator bool() { return (mydevice != nullptr); } operator bool() { return (mydevice != nullptr); }
@ -465,7 +486,9 @@ public:
{ 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 bool claim_collection(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_out_data(const Transfer_t *transfer) {return false;}
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); 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_data(uint32_t usage, int32_t value);
virtual void hid_input_end(); virtual void hid_input_end();
@ -559,10 +582,12 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
class USBHIDParser : public USBDriver { class USBHIDParser : public USBDriver {
public: public:
USBHIDParser(USBHost &host) { init(); } USBHIDParser(USBHost &host) { 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);
protected: protected:
enum { TOPUSAGE_LIST_LEN = 4 }; enum { TOPUSAGE_LIST_LEN = 4 };
enum { USAGE_LIST_LEN = 24 }; enum { USAGE_LIST_LEN = 24 };
@ -578,6 +603,14 @@ protected:
USBHIDInput * find_driver(uint32_t topusage); USBHIDInput * find_driver(uint32_t topusage);
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;}
private: private:
Pipe_t *in_pipe; Pipe_t *in_pipe;
Pipe_t *out_pipe; Pipe_t *out_pipe;
@ -594,11 +627,15 @@ private:
Pipe_t mypipes[3] __attribute__ ((aligned(32))); Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); Transfer_t mytransfers[4] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1]; strbuf_t mystring_bufs[1];
uint8_t txstate = 0;
uint8_t *tx1 = nullptr;
uint8_t *tx2 = nullptr;
bool hid_driver_claimed_control_ = false;
}; };
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
class KeyboardController : public USBDriver /* , public USBHIDInput */ { class KeyboardController : public USBDriver , public USBHIDInput {
public: public:
typedef union { typedef union {
struct { struct {
@ -614,8 +651,10 @@ typedef union {
public: public:
KeyboardController(USBHost &host) { init(); } KeyboardController(USBHost &host) { init(); }
KeyboardController(USBHost *host) { init(); } KeyboardController(USBHost *host) { init(); }
int available();
int read(); // Some methods are in both public classes so we need to figure out which one to use
operator bool() { return (device != nullptr); }
// Main boot keyboard functions.
uint16_t getKey() { return keyCode; } uint16_t getKey() { return keyCode; }
uint8_t getModifiers() { return modifiers; } uint8_t getModifiers() { return modifiers; }
uint8_t getOemKey() { return keyOEM; } uint8_t getOemKey() { return keyOEM; }
@ -630,6 +669,13 @@ public:
void numLock(bool f); void numLock(bool f);
void capsLock(bool f); void capsLock(bool f);
void scrollLock(bool f); void scrollLock(bool f);
// Added for extras information.
void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; }
void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; }
enum {MAX_KEYS_DOWN=4};
protected: protected:
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
virtual void control(const Transfer_t *transfer); virtual void control(const Transfer_t *transfer);
@ -637,6 +683,14 @@ protected:
static void callback(const Transfer_t *transfer); static void callback(const Transfer_t *transfer);
void new_data(const Transfer_t *transfer); void new_data(const Transfer_t *transfer);
void init(); void init();
protected: // HID functions for extra keyboard data.
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
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);
private: private:
void update(); void update();
uint16_t convert_to_unicode(uint32_t mod, uint32_t key); uint16_t convert_to_unicode(uint32_t mod, uint32_t key);
@ -652,43 +706,22 @@ private:
uint8_t keyOEM; uint8_t keyOEM;
uint8_t prev_report[8]; uint8_t prev_report[8];
KBDLeds_t leds_ = {0}; KBDLeds_t leds_ = {0};
bool update_leds_ = false;
bool processing_new_data_ = false;
Pipe_t mypipes[2] __attribute__ ((aligned(32))); Pipe_t mypipes[2] __attribute__ ((aligned(32)));
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); Transfer_t mytransfers[4] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1]; strbuf_t mystring_bufs[1];
};
//-------------------------------------------------------------------------- // Added to process secondary HID data.
void (*extrasKeyPressedFunction)(uint32_t top, uint16_t code);
class KeyboardHIDExtrasController : public USBHIDInput { void (*extrasKeyReleasedFunction)(uint32_t top, uint16_t code);
public:
KeyboardHIDExtrasController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); }
void clear() { event_ = false;}
bool available() { return event_; }
void attachPress(void (*f)(uint32_t top, uint16_t code)) { keyPressedFunction = f; }
void attachRelease(void (*f)(uint32_t top, uint16_t code)) { keyReleasedFunction = f; }
enum {MAX_KEYS_DOWN=4};
// uint32_t buttons() { return buttons_; }
protected:
virtual bool claim_collection(Device_t *dev, uint32_t topusage);
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);
private:
void (*keyPressedFunction)(uint32_t top, uint16_t code);
void (*keyReleasedFunction)(uint32_t top, uint16_t code);
uint32_t topusage_ = 0; // What top report am I processing? uint32_t topusage_ = 0; // What top report am I processing?
uint8_t collections_claimed_ = 0; uint8_t collections_claimed_ = 0;
volatile bool event_ = false;
volatile bool hid_input_begin_ = false; volatile bool hid_input_begin_ = false;
volatile bool hid_input_data_ = false; // did we receive any valid data with report? volatile bool hid_input_data_ = false; // did we receive any valid data with report?
uint8_t count_keys_down_ = 0; uint8_t count_keys_down_ = 0;
uint16_t keys_down[MAX_KEYS_DOWN]; uint16_t keys_down[MAX_KEYS_DOWN];
}; };
//--------------------------------------------------------------------------
class MouseController : public USBHIDInput { class MouseController : public USBHIDInput {
public: public:
@ -701,7 +734,7 @@ public:
int getWheel() { return wheel; } int getWheel() { return wheel; }
int getWheelH() { return wheelH; } int getWheelH() { return wheelH; }
protected: protected:
virtual bool claim_collection(Device_t *dev, uint32_t topusage); virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); 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_data(uint32_t usage, int32_t value);
virtual void hid_input_end(); virtual void hid_input_end();
@ -719,27 +752,76 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
class JoystickController : public USBHIDInput { class JoystickController : public USBDriver, public USBHIDInput {
public: public:
JoystickController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); } JoystickController(USBHost &host) { init(); }
uint16_t idVendor();
uint16_t idProduct();
const uint8_t *manufacturer();
const uint8_t *product();
const uint8_t *serialNumber();
operator bool() { return ((device != nullptr) || (mydevice != nullptr)); } // override as in both USBDriver and in USBHIDInput
bool available() { return joystickEvent; } bool available() { return joystickEvent; }
void joystickDataClear(); void joystickDataClear();
uint32_t getButtons() { return buttons; } uint32_t getButtons() { return buttons; }
int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; } int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; }
uint32_t axisMask() {return axis_mask_;}
enum { AXIS_COUNT = 10 };
protected: protected:
virtual bool claim_collection(Device_t *dev, uint32_t topusage); // From USBDriver
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
virtual void control(const Transfer_t *transfer);
virtual void disconnect();
// From USBHIDInput
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); 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_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);
private: private:
uint8_t collections_claimed = 0;
// Class specific
void init();
bool anychange = false; bool anychange = false;
volatile bool joystickEvent = false; volatile bool joystickEvent = false;
uint32_t buttons = 0; uint32_t buttons = 0;
int16_t axis[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int axis[AXIS_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t axis_mask_ = 0; // which axis have valid data
// Used by HID code
uint8_t collections_claimed = 0;
// Used by USBDriver code
static void rx_callback(const Transfer_t *transfer);
static void tx_callback(const Transfer_t *transfer);
void rx_data(const Transfer_t *transfer);
void tx_data(const Transfer_t *transfer);
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1];
uint16_t rx_size_ = 0;
uint16_t tx_size_ = 0;
Pipe_t *rxpipe_;
Pipe_t *txpipe_;
uint8_t rxbuf_[64]; // receive circular buffer
// Mapping table to say which devices we handle
typedef struct {
uint16_t idVendor;
uint16_t idProduct;
} product_vendor_mapping_t;
static product_vendor_mapping_t pid_vid_mapping[];
}; };
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
class MIDIDevice : public USBDriver { class MIDIDevice : public USBDriver {
@ -889,17 +971,23 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
class USBSerial: public USBDriver, public Stream { class USBSerial: public USBDriver, public Stream {
public: public:
// FIXME: need different USBSerial, with bigger buffers for 480 Mbit & faster speed // FIXME: need different USBSerial, with bigger buffers for 480 Mbit & faster speed
enum { BUFFER_SIZE = 648 }; // must hold at least 6 max size packets, plus 2 extra bytes enum { BUFFER_SIZE = 648 }; // must hold at least 6 max size packets, plus 2 extra bytes
enum { DEFAULT_WRITE_TIMEOUT = 3500};
USBSerial(USBHost &host) : txtimer(this) { init(); } USBSerial(USBHost &host) : txtimer(this) { init(); }
void begin(uint32_t baud, uint32_t format=0); void begin(uint32_t baud, uint32_t format=USBHOST_SERIAL_8N1);
void end(void); void end(void);
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 available(void);
virtual int peek(void); virtual int peek(void);
virtual int read(void); virtual int read(void);
virtual int availableForWrite(); virtual int availableForWrite();
virtual size_t write(uint8_t c); virtual size_t write(uint8_t c);
virtual void flush(void);
using Print::write; using Print::write;
protected: protected:
@ -916,6 +1004,7 @@ private:
void init(); void init();
static bool check_rxtx_ep(uint32_t &rxep, uint32_t &txep); static bool check_rxtx_ep(uint32_t &rxep, uint32_t &txep);
bool init_buffers(uint32_t rsize, uint32_t tsize); bool init_buffers(uint32_t rsize, uint32_t tsize);
void ch341_setBaud(uint8_t byte_index);
private: private:
Pipe_t mypipes[3] __attribute__ ((aligned(32))); Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[7] __attribute__ ((aligned(32))); Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
@ -923,8 +1012,10 @@ private:
USBDriverTimer txtimer; USBDriverTimer txtimer;
uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; uint32_t bigbuffer[(BUFFER_SIZE+3)/4];
setup_t setup; setup_t setup;
uint8_t setupdata[8]; uint8_t setupdata[16]; //
uint32_t baudrate; uint32_t baudrate;
uint32_t format_;
uint32_t write_timeout_ = DEFAULT_WRITE_TIMEOUT;
Pipe_t *rxpipe; Pipe_t *rxpipe;
Pipe_t *txpipe; Pipe_t *txpipe;
uint8_t *rx1; // location for first incoming packet uint8_t *rx1; // location for first incoming packet
@ -947,7 +1038,16 @@ private:
uint8_t pl2303_v2; uint8_t pl2303_v2;
uint8_t interface; uint8_t interface;
bool control_queued; bool control_queued;
enum { CDCACM, FTDI, PL2303, CH341 } sertype; typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t;
sertype_t sertype;
typedef struct {
uint16_t idVendor;
uint16_t idProduct;
sertype_t sertype;
} product_vendor_mapping_t;
static product_vendor_mapping_t pid_vid_mapping[];
}; };
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@ -1171,5 +1271,35 @@ private:
uint16_t wheelCircumference; // default is WHEEL_CIRCUMFERENCE (2122cm) uint16_t wheelCircumference; // default is WHEEL_CIRCUMFERENCE (2122cm)
}; };
//--------------------------------------------------------------------------
class RawHIDController : public USBHIDInput {
public:
RawHIDController(USBHost &host, uint32_t usage = 0) : fixed_usage_(usage) { init(); }
uint32_t usage(void) {return usage_;}
void attachReceive(bool (*f)(uint32_t usage, const uint8_t *data, uint32_t len)) {receiveCB = f;}
bool sendPacket(const uint8_t *buffer);
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);
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;
//volatile bool hid_input_begin_ = false;
uint32_t fixed_usage_;
uint32_t usage_ = 0;
// See if we can contribute transfers
Transfer_t mytransfers[2] __attribute__ ((aligned(32)));
};
#endif #endif

View File

@ -1252,12 +1252,28 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
// TODO: does this write interfere UPI & UAI (bits 18 & 19) ?? // TODO: does this write interfere UPI & UAI (bits 18 & 19) ??
} }
// find & free all the transfers which completed // find & free all the transfers which completed
println(" Free transfers");
Transfer_t *t = async_followup_first; Transfer_t *t = async_followup_first;
while (t) { while (t) {
print(" * ", (uint32_t)t);
Transfer_t *next = t->next_followup; Transfer_t *next = t->next_followup;
if (t->pipe == pipe) { if (t->pipe == pipe) {
print(" * remove");
remove_from_async_followup_list(t); remove_from_async_followup_list(t);
free_Transfer(t);
// Only free if not in QH list
Transfer_t *tr = (Transfer_t *)(pipe->qh.next);
while (((uint32_t)tr & 0xFFFFFFE0) && (tr != t)){
tr = (Transfer_t *)(tr->qtd.next);
}
if (tr == t) {
println(" * defer free until QH");
} else {
println(" * free");
free_Transfer(t); // The later code should actually free it...
}
} else {
println("");
} }
t = next; t = next;
} }
@ -1286,12 +1302,28 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
// TODO: subtract bandwidth from uframe_bandwidth array // TODO: subtract bandwidth from uframe_bandwidth array
// find & free all the transfers which completed // find & free all the transfers which completed
println(" Free transfers");
Transfer_t *t = periodic_followup_first; Transfer_t *t = periodic_followup_first;
while (t) { while (t) {
print(" * ", (uint32_t)t);
Transfer_t *next = t->next_followup; Transfer_t *next = t->next_followup;
if (t->pipe == pipe) { if (t->pipe == pipe) {
print(" * remove");
remove_from_periodic_followup_list(t); remove_from_periodic_followup_list(t);
free_Transfer(t);
// Only free if not in QH list
Transfer_t *tr = (Transfer_t *)(pipe->qh.next);
while (((uint32_t)tr & 0xFFFFFFE0) && (tr != t)){
tr = (Transfer_t *)(tr->qtd.next);
}
if (tr == t) {
println(" * defer free until QH");
} else {
println(" * free");
free_Transfer(t); // The later code should actually free it...
}
} else {
println("");
} }
t = next; t = next;
} }
@ -1300,14 +1332,17 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
// TODO: do we need to look at pipe->qh.current ?? // TODO: do we need to look at pipe->qh.current ??
// //
// free all the transfers still attached to the QH // free all the transfers still attached to the QH
println(" Free transfers attached to QH");
Transfer_t *tr = (Transfer_t *)(pipe->qh.next); Transfer_t *tr = (Transfer_t *)(pipe->qh.next);
while ((uint32_t)tr & 0xFFFFFFE0) { while ((uint32_t)tr & 0xFFFFFFE0) {
println(" * ", (uint32_t)tr);
Transfer_t *next = (Transfer_t *)(tr->qtd.next); Transfer_t *next = (Transfer_t *)(tr->qtd.next);
free_Transfer(tr); free_Transfer(tr);
tr = next; tr = next;
} }
// hopefully we found everything... // hopefully we found everything...
free_Pipe(pipe); free_Pipe(pipe);
println("* Delete Pipe completed");
} }

View File

@ -7,11 +7,9 @@
USBHost myusb; USBHost myusb;
USBHub hub1(myusb); USBHub hub1(myusb);
USBHub hub2(myusb); USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);
KeyboardController keyboard1(myusb); KeyboardController keyboard1(myusb);
KeyboardController keyboard2(myusb); KeyboardController keyboard2(myusb);
KeyboardHIDExtrasController hidextras(myusb); //KeyboardHIDExtrasController hidextras(myusb);
USBHIDParser hid1(myusb); USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb); USBHIDParser hid2(myusb);
USBHIDParser hid3(myusb); USBHIDParser hid3(myusb);
@ -19,16 +17,18 @@ USBHIDParser hid4(myusb);
USBHIDParser hid5(myusb); USBHIDParser hid5(myusb);
MouseController mouse1(myusb); MouseController mouse1(myusb);
JoystickController joystick1(myusb); JoystickController joystick1(myusb);
RawHIDController rawhid1(myusb);
RawHIDController rawhid2(myusb, 0xffc90004);
USBDriver *drivers[] = {&hub1, &hub2, &hub3, &hub4, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; USBDriver *drivers[] = {&hub1, &hub2,&keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "Hub3", "Hub4" "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"};
bool driver_active[CNT_DEVICES] = {false, false, false, false}; bool driver_active[CNT_DEVICES] = {false, false, false, false};
// Lets also look at HID Input devices // Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&mouse1, &joystick1}; USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) #define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1"}; const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"};
bool hid_driver_active[CNT_DEVICES] = {false, false}; bool hid_driver_active[CNT_DEVICES] = {false, false};
@ -40,8 +40,13 @@ void setup()
myusb.begin(); myusb.begin();
keyboard1.attachPress(OnPress); keyboard1.attachPress(OnPress);
keyboard2.attachPress(OnPress); keyboard2.attachPress(OnPress);
hidextras.attachPress(OnHIDExtrasPress); keyboard1.attachExtrasPress(OnHIDExtrasPress);
hidextras.attachRelease(OnHIDExtrasRelease); keyboard1.attachExtrasRelease(OnHIDExtrasRelease);
keyboard2.attachExtrasPress(OnHIDExtrasPress);
keyboard2.attachExtrasRelease(OnHIDExtrasRelease);
rawhid1.attachReceive(OnReceiveHidData);
rawhid2.attachReceive(OnReceiveHidData);
} }
@ -104,25 +109,31 @@ void loop()
mouse1.mouseDataClear(); mouse1.mouseDataClear();
} }
if (joystick1.available()) { if (joystick1.available()) {
uint32_t axis_mask = joystick1.axisMask();
Serial.print("Joystick: buttons = "); Serial.print("Joystick: buttons = ");
Serial.print(joystick1.getButtons(), HEX); Serial.print(joystick1.getButtons(), HEX);
Serial.print(", X = "); for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
Serial.print(joystick1.getAxis(0)); if (axis_mask & 1) {
Serial.print(", Y = "); Serial.printf(" %d:%d", i, joystick1.getAxis(i));
Serial.print(joystick1.getAxis(1)); }
Serial.print(", Z = "); }
Serial.print(joystick1.getAxis(2));
Serial.print(", Rz = ");
Serial.print(joystick1.getAxis(5));
Serial.print(", Rx = ");
Serial.print(joystick1.getAxis(3));
Serial.print(", Ry = ");
Serial.print(joystick1.getAxis(4));
Serial.print(", Hat = ");
Serial.print(joystick1.getAxis(9));
Serial.println(); Serial.println();
joystick1.joystickDataClear(); joystick1.joystickDataClear();
} }
// See if we have some RAW data
if (rawhid1) {
int ch;
uint8_t buffer[64];
uint8_t count_chars = 0;
memset(buffer, 0, sizeof(buffer));
if (Serial.available()) {
while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) {
buffer[count_chars++] = ch;
}
rawhid1.sendPacket(buffer);
}
}
} }
@ -421,3 +432,38 @@ void OnHIDExtrasRelease(uint32_t top, uint16_t key)
Serial.print(") key release:"); Serial.print(") key release:");
Serial.println(key, HEX); Serial.println(key, HEX);
} }
bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) {
// Called for maybe both HIDS for rawhid basic test. One is for the Teensy
// to output to Serial. while still having Raw Hid...
if (usage == 0xffc90004) {
// Lets trim off trailing null characters.
while ((len > 0) && (data[len-1] == 0)) {
len--;
}
if (len) {
Serial.print("RawHid Serial: ");
Serial.write(data, len);
}
} else {
Serial.print("RawHID data: ");
Serial.println(usage, HEX);
while (len) {
uint8_t cb = (len > 16)? 16 : len;
const uint8_t *p = data;
uint8_t i;
for (i = 0; i < cb; i++) {
Serial.printf("%02x ", *p++);
}
Serial.print(": ");
for (i = 0; i < cb; i++) {
Serial.write(((*data >= ' ')&&(*data <= '~'))? *data : '.');
data++;
}
len -= cb;
Serial.println();
}
}
return true;
}

0
examples/Mouse/defs.h Normal file
View File

View File

@ -4,6 +4,8 @@
#include "USBHost_t36.h" #include "USBHost_t36.h"
#define USBBAUD 115200 #define USBBAUD 115200
uint32_t baud = USBBAUD;
uint32_t format = USBHOST_SERIAL_8N1;
USBHost myusb; USBHost myusb;
USBHub hub1(myusb); USBHub hub1(myusb);
USBHub hub2(myusb); USBHub hub2(myusb);
@ -60,23 +62,8 @@ void loop()
// If this is a new Serial device. // If this is a new Serial device.
if (drivers[i] == &userial) { if (drivers[i] == &userial) {
// Lets try first outputting something to our USerial to see if it will go out... // Lets try first outputting something to our USerial to see if it will go out...
userial.begin(USBBAUD); userial.begin(baud);
// delay(5);
// userial.println("ver");
#if 0
userial.println("abcdefghijklmnopqrstuvwxyz");
userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ");
userial.flush(); // force it out now.
userial.println("0123456789");
userial.flush();
delay(2);
userial.println("abcdefghijklmnopqrstuvwxyz");
userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ");
delay(2);
userial.println("!@#$%^&*()");
userial.flush();
#endif
} }
} }
} }
@ -89,8 +76,55 @@ void loop()
if (ch == '$') { if (ch == '$') {
BioloidTest(); BioloidTest();
while (Serial.read() != -1); while (Serial.read() != -1);
} else if (ch == '#') {
// Lets see if we have a baud rate specified here...
uint32_t new_baud = 0;
for(;;) {
ch = Serial.read();
if ((ch < '0') || (ch > '9'))
break;
new_baud = new_baud*10 + ch - '0';
}
// See if the user is specifying a format: 8n1, 7e1, 7e2, 8n2
// Note this is Quick and very dirty code...
//
if (ch == ',') {
char command_line[10];
ch = Serial.read();
while (ch == ' ') Serial.read(); // ignore any spaces.
uint8_t cb = 0;
while ((ch > ' ') && (cb < sizeof(command_line))) {
command_line[cb++] = ch;
ch = Serial.read();
}
command_line[cb] = '\0';
if (CompareStrings(command_line, "8N1")) format = USBHOST_SERIAL_8N1;
else if (CompareStrings(command_line, "8N2")) format = USBHOST_SERIAL_8N2;
else if (CompareStrings(command_line, "7E1")) format = USBHOST_SERIAL_7E1;
else if (CompareStrings(command_line, "7O1")) format = USBHOST_SERIAL_7O1;
}
Serial.println("\n*** Set new Baud command ***\n do userial.end()");
digitalWriteFast(2, HIGH);
userial.end(); // Do the end statement;
digitalWriteFast(2, LOW);
if (new_baud) {
baud = new_baud;
Serial.print(" New Baud: ");
Serial.println(baud);
Serial.print(" Format: ");
Serial.println(format, HEX);
digitalWriteFast(3, HIGH);
userial.begin(baud, format);
digitalWriteFast(3, LOW);
Serial.println(" Completed ");
} else {
Serial.println(" New Baud 0 - leave disabled");
}
while (Serial.read() != -1);
} else {
userial.write(ch);
} }
else userial.write(ch);
} }
} }
@ -106,14 +140,25 @@ void loop()
} }
} }
bool CompareStrings(const char *sz1, const char *sz2) {
while (*sz2 != 0) {
if (toupper(*sz1) != toupper(*sz2))
return false;
sz1++;
sz2++;
}
return true; // end of string so show as match
}
//#define ID_MASTER 200 //#define ID_MASTER 200
#define ID_MASTER 0xfd #define ID_MASTER 0xfd
// Extract stuff from Bioloid library.. // Extract stuff from Bioloid library..
#define AX12_BUFFER_SIZE 128 #define AX12_BUFFER_SIZE 128
#define COUNTER_TIMEOUT 12000 #define COUNTER_TIMEOUT 12000
/** Instruction Set **/ /** Instruction Set **/ #define AX_PING 1
#define AX_PING 1
#define AX_READ_DATA 2 #define AX_READ_DATA 2
#define AX_WRITE_DATA 3 #define AX_WRITE_DATA 3
#define AX_REG_WRITE 4 #define AX_REG_WRITE 4
@ -244,7 +289,7 @@ int ax12ReadPacket(int length) {
while ((ch = userial.read()) == -1) { while ((ch = userial.read()) == -1) {
if ((millis() - ulStart) > 10) { if ((millis() - ulStart) > 10) {
//if (!--ulCounter) { //if (!--ulCounter) {
// Serial.println("Timeout"); Serial.println("Timeout");
return 0; // Timeout return 0; // Timeout
} }
} }

View File

67
hid.cpp
View File

@ -128,21 +128,19 @@ bool USBHIDParser::claim(Device_t *dev, int type, const uint8_t *descriptors, ui
if (((endpoint1 & 0xF0) == 0x80) && ((endpoint2 & 0xF0) == 0)) { if (((endpoint1 & 0xF0) == 0x80) && ((endpoint2 & 0xF0) == 0)) {
// first endpoint is IN, second endpoint is OUT // first endpoint is IN, second endpoint is OUT
in_pipe = new_Pipe(dev, 3, endpoint1 & 0x0F, 1, size1, interval1); in_pipe = new_Pipe(dev, 3, endpoint1 & 0x0F, 1, size1, interval1);
//out_pipe = new_Pipe(dev, 3, endpoint2, 0, size2, interval2); out_pipe = new_Pipe(dev, 3, endpoint2, 0, size2, interval2);
out_pipe = NULL; // TODO; fixme
in_size = size1; in_size = size1;
out_size = size2; out_size = size2;
} else if (((endpoint1 & 0xF0) == 0) && ((endpoint2 & 0xF0) == 0x80)) { } else if (((endpoint1 & 0xF0) == 0) && ((endpoint2 & 0xF0) == 0x80)) {
// first endpoint is OUT, second endpoint is IN // first endpoint is OUT, second endpoint is IN
in_pipe = new_Pipe(dev, 3, endpoint2 & 0x0F, 1, size2, interval2); in_pipe = new_Pipe(dev, 3, endpoint2 & 0x0F, 1, size2, interval2);
//out_pipe = new_Pipe(dev, 3, endpoint1, 0, size1, interval1); out_pipe = new_Pipe(dev, 3, endpoint1, 0, size1, interval1);
out_pipe = NULL; // TODO; fixme
in_size = size2; in_size = size2;
out_size = size1; out_size = size1;
} else { } else {
return false; return false;
} }
//out_pipe->callback_function = out_callback; out_pipe->callback_function = out_callback;
} }
in_pipe->callback_function = in_callback; in_pipe->callback_function = in_callback;
for (uint32_t i=0; i < TOPUSAGE_LIST_LEN; i++) { for (uint32_t i=0; i < TOPUSAGE_LIST_LEN; i++) {
@ -185,6 +183,7 @@ void USBHIDParser::in_callback(const Transfer_t *transfer)
void USBHIDParser::out_callback(const Transfer_t *transfer) void USBHIDParser::out_callback(const Transfer_t *transfer)
{ {
//println("USBHIDParser:: out_callback (static)");
if (transfer->driver) { if (transfer->driver) {
((USBHIDParser*)(transfer->driver))->out_data(transfer); ((USBHIDParser*)(transfer->driver))->out_data(transfer);
} }
@ -215,14 +214,22 @@ void USBHIDParser::in_data(const Transfer_t *transfer)
Serial.println(); */ Serial.println(); */
print("HID: "); print("HID: ");
print(use_report_id);
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;
if (use_report_id == false) {
parse(0x0100, buf, len); // See if the first top report wishes to bypass the
} else { // parse...
if (len > 1) { if (!(topusage_drivers[0] && topusage_drivers[0]->hid_process_in_data(transfer))) {
parse(0x0100 | buf[0], buf + 1, len - 1);
if (use_report_id == false) {
parse(0x0100, buf, len);
} else {
if (len > 1) {
parse(0x0100 | buf[0], buf + 1, len - 1);
}
} }
} }
queue_Data_Transfer(in_pipe, report, in_size, this); queue_Data_Transfer(in_pipe, report, in_size, this);
@ -231,8 +238,44 @@ void USBHIDParser::in_data(const Transfer_t *transfer)
void USBHIDParser::out_data(const Transfer_t *transfer) void USBHIDParser::out_data(const Transfer_t *transfer)
{ {
println("USBHIDParser:out_data called (instance)");
// A packet completed. lets mark it as done and call back
// to top reports handler. We unmark our checkmark to
// handle case where they may want to queue up another one.
if (transfer->buffer == tx1) txstate &= ~1;
if (transfer->buffer == tx2) txstate &= ~2;
if (topusage_drivers[0]) {
topusage_drivers[0]->hid_process_out_data(transfer);
}
} }
bool USBHIDParser::sendPacket(const uint8_t *buffer) {
if (!out_size || !out_pipe) return false;
if (!tx1) {
// Was not init before, for now lets put it at end of descriptor
// TODO: should verify that either don't exceed overlap descsize
// Or that we have taken over this device
tx1 = &descriptor[sizeof(descriptor) - out_size];
tx2 = tx1 - out_size;
}
if ((txstate & 3) == 3) return false; // both transmit buffers are full
uint8_t *p = tx1;
if ((txstate & 1) == 0) {
txstate |= 1;
} else {
txstate |= 2;
p = tx2;
}
// copy the users data into our out going buffer
memcpy(p, buffer, out_size);
println("USBHIDParser Send packet");
print_hexbytes(buffer, out_size);
queue_Data_Transfer(out_pipe, p, out_size, this);
println(" Queue_data transfer returned");
return true;
}
// This no-inputs parse is meant to be used when we first get the // This no-inputs parse is meant to be used when we first get the
// HID report descriptor. It finds all the top level collections // HID report descriptor. It finds all the top level collections
// and allows drivers to claim them. This is always where we // and allows drivers to claim them. This is always where we
@ -333,9 +376,11 @@ USBHIDInput * USBHIDParser::find_driver(uint32_t topusage)
{ {
println("find_driver"); println("find_driver");
USBHIDInput *driver = available_hid_drivers_list; USBHIDInput *driver = available_hid_drivers_list;
hidclaim_t claim_type;
while (driver) { while (driver) {
println(" driver ", (uint32_t)driver, HEX); println(" driver ", (uint32_t)driver, HEX);
if (driver->claim_collection(device, topusage)) { if ((claim_type = driver->claim_collection(this, device, topusage)) != CLAIM_NO) {
if (claim_type == CLAIM_INTERFACE) hid_driver_claimed_control_ = true;
return driver; return driver;
} }
driver = driver->next; driver = driver->next;

View File

@ -24,24 +24,80 @@
#include <Arduino.h> #include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info #include "USBHost_t36.h" // Read this header first for key info
#define print USBHost::print_
#define println USBHost::println_
void JoystickController::init()
{
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
driver_ready_for_device(this);
USBHIDParser::driver_ready_for_hid_collection(this);
}
//*****************************************************************************
// Some simple query functions depend on which interface we are using...
//*****************************************************************************
uint16_t JoystickController::idVendor()
{
if (device != nullptr) return device->idVendor;
if (mydevice != nullptr) return mydevice->idVendor;
return 0;
}
uint16_t JoystickController::idProduct()
{
if (device != nullptr) return device->idProduct;
if (mydevice != nullptr) return mydevice->idProduct;
return 0;
}
const uint8_t *JoystickController::manufacturer()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
return nullptr;
}
const uint8_t *JoystickController::product()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
return nullptr;
}
const uint8_t *JoystickController::serialNumber()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
return nullptr;
}
bool JoystickController::claim_collection(Device_t *dev, uint32_t topusage)
//*****************************************************************************
// Support for Joysticks that USe HID data.
//*****************************************************************************
hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{ {
// only claim Desktop/Joystick and Desktop/Gamepad // only claim Desktop/Joystick and Desktop/Gamepad
if (topusage != 0x10004 && topusage != 0x10005) return false; if (topusage != 0x10004 && topusage != 0x10005) return CLAIM_NO;
// only claim from one physical device // only claim from one physical device
if (mydevice != NULL && dev != mydevice) return false; if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
mydevice = dev; mydevice = dev;
collections_claimed++; collections_claimed++;
anychange = true; // always report values on first read anychange = true; // always report values on first read
return true; return CLAIM_REPORT;
} }
void JoystickController::disconnect_collection(Device_t *dev) void JoystickController::disconnect_collection(Device_t *dev)
{ {
if (--collections_claimed == 0) { if (--collections_claimed == 0) {
mydevice = NULL; mydevice = NULL;
axis_mask_ = 0;
} }
} }
@ -70,8 +126,9 @@ void JoystickController::hid_input_data(uint32_t usage, int32_t value)
} }
} else if (usage_page == 1 && usage >= 0x30 && usage <= 0x39) { } else if (usage_page == 1 && usage >= 0x30 && usage <= 0x39) {
// TODO: need scaling of value to consistent API, 16 bit signed? // TODO: need scaling of value to consistent API, 16 bit signed?
// TODO: many joysticks repeat slider usage. Detect & map to axes? // TODO: many joysticks repeat slider usage. Detect & map to axis?
uint32_t i = usage - 0x30; uint32_t i = usage - 0x30;
axis_mask_ |= (1 << i); // Keep record of which axis we have data on.
if (axis[i] != value) { if (axis[i] != value) {
axis[i] = value; axis[i] = value;
anychange = true; anychange = true;
@ -92,4 +149,167 @@ void JoystickController::joystickDataClear() {
anychange = false; anychange = false;
} }
//*****************************************************************************
// Support for Joysticks that are class specific and do not use HID
// Example: XBox One controller.
//*****************************************************************************
// Note: currently just XBOX one.
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
{ 0x045e, 0x02ea },{ 0x045e, 0x02dd } };
static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
println("JoystickController claim this=", (uint32_t)this, HEX);
// only claim at device level
if (type != 0) return false;
print_hexbytes(descriptors, len);
uint8_t i = 0;
for (; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) {
if ((dev->idVendor == pid_vid_mapping[i].idVendor) && (dev->idProduct == pid_vid_mapping[i].idProduct)) {
break;
}
}
if (i == (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0]))) return false; // Not in our list
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 *6 7 8 9 20 1 2 3 4 5 6 7 8 9 30 1...
// 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00
// Lets do some verifications to make sure.
if (len < 9+7+7) return false;
uint32_t count_end_points = descriptors[4];
if (count_end_points < 2) return false;
if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID
uint32_t rxep = 0;
uint32_t txep = 0;
rx_size_ = 0;
tx_size_ = 0;
uint32_t descriptor_index = 9;
while (count_end_points-- && ((rxep == 0) || txep == 0)) {
if (descriptors[descriptor_index] != 7) return false; // length 7
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
if ((descriptors[descriptor_index+3] == 3) // Type 3...
&& (descriptors[descriptor_index+4] <= 64)
&& (descriptors[descriptor_index+5] == 0)) {
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) {
rxep = descriptors[descriptor_index+2];
rx_size_ = descriptors[descriptor_index+4];
} else {
txep = descriptors[descriptor_index+2];
tx_size_ = descriptors[descriptor_index+4];
}
}
descriptor_index += 7; // setup to look at next one...
}
if ((rxep == 0) || (txep == 0)) return false; // did not find two end points.
print("JoystickController, rxep=", rxep & 15);
print("(", rx_size_);
print("), txep=", txep);
print("(", tx_size_);
println(")");
rxpipe_ = new_Pipe(dev, 2, rxep & 15, 1, rx_size_);
if (!rxpipe_) return false;
txpipe_ = new_Pipe(dev, 2, txep, 0, tx_size_);
if (!txpipe_) {
//free_Pipe(rxpipe_);
return false;
}
rxpipe_->callback_function = rx_callback;
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
txpipe_->callback_function = tx_callback;
queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this);
memset(axis, 0, sizeof(axis)); // clear out any data.
return true;
}
void JoystickController::control(const Transfer_t *transfer)
{
}
/************************************************************/
// Interrupt-based Data Movement
/************************************************************/
void JoystickController::rx_callback(const Transfer_t *transfer)
{
if (!transfer->driver) return;
((JoystickController *)(transfer->driver))->rx_data(transfer);
}
void JoystickController::tx_callback(const Transfer_t *transfer)
{
if (!transfer->driver) return;
((JoystickController *)(transfer->driver))->tx_data(transfer);
}
/************************************************************/
// Interrupt-based Data Movement
// XBox one input data when type == 0x20
// Information came from several places on the web including:
// https://github.com/quantus/xbox-one-controller-protocol
/************************************************************/
typedef struct {
uint8_t type;
uint8_t const_0;
uint16_t id;
// From online references button order:
// sync, dummy, start, back, a, b, x, y
// dpad up, down left, right
// lb, rb, left stick, right stick
// Axis:
// lt, rt, lx, xy, rx, ry
//
uint16_t buttons;
int16_t axis[6];
} xbox1data20_t;
static const uint8_t xbox_axis_order_mapping[] = {4, 5, 0, 1, 2, 3};
void JoystickController::rx_data(const Transfer_t *transfer)
{
// print("JoystickController::rx_data: ");
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
axis_mask_ = 0x3f;
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer;
if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) {
// We have a data transfer. Lets see what is new...
if (xb1d->buttons != buttons) {
buttons = xb1d->buttons;
anychange = true;
}
for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) {
// The first two values were unsigned.
int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i];
if (axis_value != axis[xbox_axis_order_mapping[i]]) {
axis[xbox_axis_order_mapping[i]] = axis_value;
anychange = true;
}
}
joystickEvent = true;
}
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
}
void JoystickController::tx_data(const Transfer_t *transfer)
{
}
void JoystickController::disconnect()
{
axis_mask_ = 0;
// TODO: free resources
}

View File

@ -98,6 +98,7 @@ void KeyboardController::init()
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
driver_ready_for_device(this); driver_ready_for_device(this);
USBHIDParser::driver_ready_for_hid_collection(this);
} }
bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
@ -179,7 +180,6 @@ static bool contains(uint8_t b, const uint8_t *data)
void KeyboardController::new_data(const Transfer_t *transfer) void KeyboardController::new_data(const Transfer_t *transfer)
{ {
processing_new_data_ = true;
println("KeyboardController Callback (member)"); println("KeyboardController Callback (member)");
print(" KB Data: "); print(" KB Data: ");
print_hexbytes(transfer->buffer, 8); print_hexbytes(transfer->buffer, 8);
@ -197,12 +197,6 @@ void KeyboardController::new_data(const Transfer_t *transfer)
} }
memcpy(prev_report, report, 8); memcpy(prev_report, report, 8);
queue_Data_Transfer(datapipe, report, 8, this); queue_Data_Transfer(datapipe, report, 8, this);
processing_new_data_ = false;
// See if we have any outstanding leds to update
if (update_leds_) {
updateLEDS();
}
} }
@ -328,31 +322,107 @@ void KeyboardController::LEDS(uint8_t leds) {
} }
void KeyboardController::updateLEDS() { void KeyboardController::updateLEDS() {
println("KBD: Update LEDS", leds_.byte, HEX);
if (processing_new_data_) {
println(" Update defered");
update_leds_ = true;
return; // defer until later
}
// Now lets tell keyboard new state. // Now lets tell keyboard new state.
static uint8_t keyboard_keys_report[1] = {0}; mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds
setup_t keys_setup; queue_Control_Transfer(device, &setup, &leds_.byte, this);
keyboard_keys_report[0] = leds_.byte;
queue_Data_Transfer(datapipe, report, 8, this);
mk_setup(keys_setup, 0x21, 9, 0x200, 0, sizeof(keyboard_keys_report)); // hopefully this sets leds
queue_Control_Transfer(device, &keys_setup, keyboard_keys_report, this);
update_leds_ = false;
} }
//=============================================================================
// Keyboard Extras - Combined from other object
//=============================================================================
#define TOPUSAGE_SYS_CONTROL 0x10080
#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001
hidclaim_t KeyboardController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
// Lets try to claim a few specific Keyboard related collection/reports
//Serial.printf("KBH Claim %x\n", topusage);
if ((topusage != TOPUSAGE_SYS_CONTROL)
&& (topusage != TOPUSAGE_CONSUMER_CONTROL)
) return CLAIM_NO;
// only claim from one physical device
//Serial.println("KeyboardController claim collection");
// Lets only claim if this is the same device as claimed Keyboard...
if (dev != device) return CLAIM_NO;
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
mydevice = dev;
collections_claimed_++;
return CLAIM_REPORT;
}
void KeyboardController::disconnect_collection(Device_t *dev)
{
if (--collections_claimed_ == 0) {
mydevice = NULL;
}
}
void KeyboardController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
{
//Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax);
topusage_ = topusage; // remember which report we are processing.
hid_input_begin_ = true;
hid_input_data_ = false;
}
void KeyboardController::hid_input_data(uint32_t usage, int32_t value)
{
// Hack ignore 0xff00 high words as these are user values...
if ((usage & 0xffff0000) == 0xff000000) return;
//Serial.printf("KeyboardController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);
// See if the value is in our keys_down list
usage &= 0xffff; // only keep the actual key
if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items.
// Remember if we have received any logical key up events. Some keyboard appear to send them
// others do no...
hid_input_data_ = true;
uint8_t key_index;
for (key_index = 0; key_index < count_keys_down_; key_index++) {
if (keys_down[key_index] == usage) {
if (value) return; // still down
if (extrasKeyReleasedFunction) {
extrasKeyReleasedFunction(topusage_, usage);
}
// Remove from list
count_keys_down_--;
for (;key_index < count_keys_down_; key_index++) {
keys_down[key_index] = keys_down[key_index+1];
}
return;
}
}
// Was not in list
if (!value) return; // still 0
if (extrasKeyPressedFunction) {
extrasKeyPressedFunction(topusage_, usage);
}
if (count_keys_down_ < MAX_KEYS_DOWN) {
keys_down[count_keys_down_++] = usage;
}
}
void KeyboardController::hid_input_end()
{
//Serial.println("KPC:hid_input_end");
if (hid_input_begin_) {
// See if we received any data from parser if not, assume all keys released...
if (!hid_input_data_ ) {
if (extrasKeyReleasedFunction) {
while (count_keys_down_) {
count_keys_down_--;
extrasKeyReleasedFunction(topusage_, keys_down[count_keys_down_]);
}
}
count_keys_down_ = 0;
}
hid_input_begin_ = false;
}
}

View File

@ -1,123 +0,0 @@
/* USB keyboard power 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 TOPUSAGE_SYS_CONTROL 0x10080
#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001
bool KeyboardHIDExtrasController::claim_collection(Device_t *dev, uint32_t topusage)
{
// Lets try to claim a few specific Keyboard related collection/reports
//Serial.printf("KBH Claim %x\n", topusage);
if ((topusage != TOPUSAGE_SYS_CONTROL)
&& (topusage != TOPUSAGE_CONSUMER_CONTROL)
) return false;
// only claim from one physical device
//Serial.println("KeyboardHIDExtrasController claim collection");
if (mydevice != NULL && dev != mydevice) return false;
mydevice = dev;
collections_claimed_++;
return true;
}
void KeyboardHIDExtrasController::disconnect_collection(Device_t *dev)
{
if (--collections_claimed_ == 0) {
mydevice = NULL;
}
}
void KeyboardHIDExtrasController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
{
//Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax);
topusage_ = topusage; // remember which report we are processing.
hid_input_begin_ = true;
hid_input_data_ = false;
}
void KeyboardHIDExtrasController::hid_input_data(uint32_t usage, int32_t value)
{
// Hack ignore 0xff00 high words as these are user values...
if ((usage & 0xffff0000) == 0xff000000) return;
//Serial.printf("KeyboardHIDExtrasController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);
// See if the value is in our keys_down list
usage &= 0xffff; // only keep the actual key
if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items.
// Remember if we have received any logical key up events. Some keyboard appear to send them
// others do no...
hid_input_data_ = true;
uint8_t key_index;
for (key_index = 0; key_index < count_keys_down_; key_index++) {
if (keys_down[key_index] == usage) {
if (value) return; // still down
if (keyReleasedFunction) {
keyReleasedFunction(topusage_, usage);
}
// Remove from list
count_keys_down_--;
for (;key_index < count_keys_down_; key_index++) {
keys_down[key_index] = keys_down[key_index+1];
}
return;
}
}
// Was not in list
if (!value) return; // still 0
if (keyPressedFunction) {
keyPressedFunction(topusage_, usage);
}
if (count_keys_down_ < MAX_KEYS_DOWN) {
keys_down[count_keys_down_++] = usage;
}
}
void KeyboardHIDExtrasController::hid_input_end()
{
//Serial.println("KPC:hid_input_end");
if (hid_input_begin_) {
// See if we received any data from parser if not, assume all keys released...
if (!hid_input_data_ ) {
if (keyPressedFunction) {
while (count_keys_down_) {
count_keys_down_--;
keyReleasedFunction(topusage_, keys_down[count_keys_down_]);
}
}
count_keys_down_ = 0;
}
event_ = true;
hid_input_begin_ = false;
}
}

View File

@ -8,7 +8,7 @@ MIDIDevice KEYWORD1
USBSerial KEYWORD1 USBSerial KEYWORD1
AntPlus KEYWORD1 AntPlus KEYWORD1
JoystickController KEYWORD1 JoystickController KEYWORD1
KeyboardHIDExtrasController KEYWORD1 RawHIDController KEYWORD1
# Common Functions # Common Functions
Task KEYWORD2 Task KEYWORD2
@ -24,11 +24,13 @@ getModifiers KEYWORD2
getOemKey KEYWORD2 getOemKey KEYWORD2
attachPress KEYWORD2 attachPress KEYWORD2
attachRelease KEYWORD2 attachRelease KEYWORD2
attachExtrasPress KEYWORD2
attachExtrasRelease KEYWORD2
LEDS KEYWORD2 LEDS KEYWORD2
updateLEDS KEYWORD2 updateLEDS KEYWORD2
numLock KEYWORD2 numLock KEYWORD2
capsLock KEYWORD2 capsLock KEYWORD2
scrollLock scrollLock KEYWORD2
# MIDIDevice # MIDIDevice
getType KEYWORD2 getType KEYWORD2
@ -78,4 +80,17 @@ getWheelH KEYWORD2
# JoystickController # JoystickController
joystickDataClear KEYWORD2 joystickDataClear KEYWORD2
getAxis KEYWORD2 getAxis KEYWORD2
axisMask KEYWORD2
# USBSerial
USBHOST_SERIAL_7E1 LITERAL1
USBHOST_SERIAL_7O1 LITERAL1
USBHOST_SERIAL_8N1 LITERAL1
USBHOST_SERIAL_8N2 LITERAL1
USBHOST_SERIAL_8E1 LITERAL1
USBHOST_SERIAL_8O1 LITERAL1
# RAWHid
usage KEYWORD2
attachReceive KEYWORD2
sendPacket KEYWORD2

View File

@ -26,15 +26,15 @@
bool MouseController::claim_collection(Device_t *dev, uint32_t topusage) hidclaim_t MouseController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{ {
// only claim Desktop/Mouse // only claim Desktop/Mouse
if (topusage != 0x10002) return false; if (topusage != 0x10002) return CLAIM_NO;
// only claim from one physical device // only claim from one physical device
if (mydevice != NULL && dev != mydevice) return false; if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
mydevice = dev; mydevice = dev;
collections_claimed++; collections_claimed++;
return true; return CLAIM_REPORT;
} }
void MouseController::disconnect_collection(Device_t *dev) void MouseController::disconnect_collection(Device_t *dev)

120
rawhid.cpp Normal file
View File

@ -0,0 +1,120 @@
/* 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
void RawHIDController::init()
{
USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
USBHIDParser::driver_ready_for_hid_collection(this);
}
hidclaim_t RawHIDController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
// only claim RAWHID devices currently: 16c0:0486
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("Rawhid Claim: %x:%x usage: %x\n", dev->idVendor, dev->idProduct, topusage);
#endif
if ((dev->idVendor != 0x16c0 || (dev->idProduct) != 0x486)) return CLAIM_NO;
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
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
mydevice = dev;
collections_claimed++;
usage_ = topusage;
driver_ = driver; // remember the driver.
return CLAIM_INTERFACE; // We wa
}
void RawHIDController::disconnect_collection(Device_t *dev)
{
if (--collections_claimed == 0) {
mydevice = NULL;
usage_ = 0;
}
}
bool RawHIDController::hid_process_in_data(const Transfer_t *transfer)
{
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHIDController::hid_process_in_data: %x\n", usage_);
#endif
if (receiveCB) {
return (*receiveCB)(usage_, (const uint8_t *)transfer->buffer, transfer->length);
}
return true;
}
bool RawHIDController::hid_process_out_data(const Transfer_t *transfer)
{
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHIDController::hid_process_out_data: %x\n", usage_);
#endif
return true;
}
bool RawHIDController::sendPacket(const uint8_t *buffer)
{
if (!driver_) return false;
return driver_->sendPacket(buffer);
}
void RawHIDController::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 USBHOST_PRINT_DEBUG
Serial.printf("RawHID::hid_input_begin %x %x %x %x\n", topusage, type, lgmin, lgmax);
#endif
//hid_input_begin_ = true;
}
void RawHIDController::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 USBHOST_PRINT_DEBUG
Serial.printf("RawHID: usage=%X, value=%d", usage, value);
if ((value >= ' ') && (value <='~')) Serial.printf("(%c)", value);
Serial.println();
#endif
}
void RawHIDController::hid_input_end()
{
// These should not be called as we are claiming the whole interface and not
// allowing the parse to happen
#ifdef USBHOST_PRINT_DEBUG
Serial.println("RawHID::hid_input_end");
#endif
// if (hid_input_begin_) {
// hid_input_begin_ = false;
// }
}

View File

@ -19,6 +19,8 @@
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Note: special thanks to the Linux kernel for the CH341's method of operation, particularly how the baud rate is encoded.
*/ */
#include <Arduino.h> #include <Arduino.h>
@ -27,15 +29,35 @@
#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_
//#define ENABLE_DEBUG_PINS
#ifdef ENABLE_DEBUG_PINS
#define debugDigitalToggle(pin) {digitalWriteFast(pin, !digitalReadFast(pin));}
#define debugDigitalWrite(pin, state) {digitalWriteFast(pin, state);}
#else
#define debugDigitalToggle(pin) {;}
#define debugDigitalWrite(pin, state) {;}
#endif
/************************************************************/ /************************************************************/
// Control Transfer For Configuration // Define mapping VID/PID - to Serial Device type.
/************************************************************/ /************************************************************/
typedef struct { USBSerial::product_vendor_mapping_t USBSerial::pid_vid_mapping[] = {
uint32_t dwDTERate; // Data Terminal Rate in bits per second // FTDI mappings.
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits {0x0403, 0x6001, USBSerial::FTDI},
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16) // PL2303
} LINE_CODING; {0x67B,0x2303, USBSerial::PL2303},
// CH341
{0x4348, 0x5523, USBSerial::CH341 },
{0x1a86, 0x7523, USBSerial::CH341 },
{0x1a86, 0x5523, USBSerial::CH341 },
// Silex CP210...
{0x10c4, 0xea60, USBSerial::CP210X }
};
/************************************************************/ /************************************************************/
// Initialization and claiming of devices & interfaces // Initialization and claiming of devices & interfaces
@ -47,6 +69,7 @@ void USBSerial::init()
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
driver_ready_for_device(this); driver_ready_for_device(this);
format_ = USBHOST_SERIAL_8N1;
} }
bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
@ -60,51 +83,9 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
println(", bDeviceProtocol = ", dev->bDeviceProtocol); println(", bDeviceProtocol = ", dev->bDeviceProtocol);
print_hexbytes(descriptors, len); print_hexbytes(descriptors, len);
if (type == 0) { if (type == 0) {
if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) { //---------------------------------------------------------------------
// FTDI FT232 // CDCACM
println("len = ", len); if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) {
if (len < 23) return false;
if (descriptors[0] != 9) return false; // length 9
if (descriptors[9] != 7) return false; // length 7
if (descriptors[10] != 5) return false; // ep desc
uint32_t rxep = descriptors[11];
if (descriptors[12] != 2) return false; // bulk type
if (descriptors[13] != 64) return false; // size 64
if (descriptors[14] != 0) return false;
if (descriptors[16] != 7) return false; // length 7
if (descriptors[17] != 5) return false; // ep desc
uint32_t txep = descriptors[18];
if (descriptors[19] != 2) return false; // bulk type
if (descriptors[20] != 64) return false; // size 64
if (descriptors[21] != 0) return false;
if (!check_rxtx_ep(rxep, txep)) return false;
print("FTDI, rxep=", rxep & 15);
println(", txep=", txep);
if (!init_buffers(64, 64)) return false;
rxpipe = new_Pipe(dev, 2, rxep & 15, 1, 64);
if (!rxpipe) return false;
txpipe = new_Pipe(dev, 2, txep, 0, 64);
if (!txpipe) {
// TODO: free rxpipe
return false;
}
sertype = FTDI;
rxpipe->callback_function = rx_callback;
queue_Data_Transfer(rxpipe, rx1, 64, this);
rxstate = 1;
if (rxsize > 128) {
queue_Data_Transfer(rxpipe, rx2, 64, this);
rxstate = 3;
}
txstate = 0;
txpipe->callback_function = tx_callback;
baudrate = 115200;
pending_control = 0x0F;
mk_setup(setup, 0x40, 0, 0, 0, 0); // reset port
queue_Control_Transfer(dev, &setup, NULL, this);
control_queued = true;
return true;
} else if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) {
// It is a communication device see if we can extract the data... // It is a communication device see if we can extract the data...
// Try some ttyACM types? // Try some ttyACM types?
// This code may be similar to MIDI code. // This code may be similar to MIDI code.
@ -197,6 +178,8 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
println(", tx:", tx_ep); println(", tx:", tx_ep);
if (!rx_ep || !tx_ep) return false; // did not get our two end points if (!rx_ep || !tx_ep) return false; // did not get our two end points
if (!init_buffers(rx_size, tx_size)) return false; if (!init_buffers(rx_size, tx_size)) return false;
println(" rx buffer size:", rxsize);
println(" tx buffer size:", txsize);
rxpipe = new_Pipe(dev, 2, rx_ep & 15, 1, rx_size); rxpipe = new_Pipe(dev, 2, rx_ep & 15, 1, rx_size);
if (!rxpipe) return false; if (!rxpipe) return false;
txpipe = new_Pipe(dev, 2, tx_ep, 0, tx_size); txpipe = new_Pipe(dev, 2, tx_ep, 0, tx_size);
@ -226,72 +209,133 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
return true; return true;
} }
// TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them // See if the vendor_id:product_id is in our list of products.
if (dev->idVendor == 0x67B && dev->idProduct == 0x2303) { sertype = UNKNOWN;
// Prolific Technology, Inc. PL2303 Serial Port for (uint8_t i = 0; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) {
println("len = ", len); if ((dev->idVendor == pid_vid_mapping[i].idVendor) && (dev->idProduct == pid_vid_mapping[i].idProduct)) {
uint8_t count_end_points = descriptors[4]; sertype = pid_vid_mapping[i].sertype;
if (count_end_points < 2) return false; // not enough end points break;
if (len < 23) return false; }
if (descriptors[0] != 9) return false; // length 9 }
if (sertype == UNKNOWN) return false; // not one of ours
// Lets walk through end points and see if we // Lets try to locate the end points. Code is common across these devices
// can find an RX and TX bulk transfer end point. println("len = ", len);
//vid=67B, pid=2303 uint8_t count_end_points = descriptors[4];
// 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9 if (count_end_points < 2) return false; // not enough end points
//09 04 00 00 03 FF 00 00 00 07 05 81 03 0A 00 01 07 05 02 02 40 00 00 07 05 83 02 40 00 00 if (len < 23) return false;
uint32_t rxep = 0; if (descriptors[0] != 9) return false; // length 9
uint32_t txep = 0;
uint32_t descriptor_index = 9; // Lets walk through end points and see if we
while (count_end_points-- && ((rxep == 0) || txep == 0)) { // can find an RX and TX bulk transfer end point.
if (descriptors[descriptor_index] != 7) return false; // length 7 //Example vid=67B, pid=2303
if (descriptors[descriptor_index+1] != 5) return false; // ep desc // 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9
if ((descriptors[descriptor_index+3] == 2) //09 04 00 00 03 FF 00 00 00 07 05 81 03 0A 00 01 07 05 02 02 40 00 00 07 05 83 02 40 00 00
&& (descriptors[descriptor_index+4] == 64) uint32_t rxep = 0;
&& (descriptors[descriptor_index+5] == 0)) { uint32_t txep = 0;
// have a bulk EP size uint16_t rx_size = 0;
if (descriptors[descriptor_index+2] & 0x80 ) { uint16_t tx_size = 0;
rxep = descriptors[descriptor_index+2]; uint32_t descriptor_index = 9;
} else { while (count_end_points-- && ((rxep == 0) || txep == 0)) {
txep = descriptors[descriptor_index+2]; if (descriptors[descriptor_index] != 7) return false; // length 7
} if (descriptors[descriptor_index+1] != 5) return false; // ep desc
if ((descriptors[descriptor_index+3] == 2)
&& (descriptors[descriptor_index+4] <= 64)
&& (descriptors[descriptor_index+5] == 0)) {
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) {
rxep = descriptors[descriptor_index+2];
rx_size = descriptors[descriptor_index+4];
} else {
txep = descriptors[descriptor_index+2];
tx_size = descriptors[descriptor_index+4];
} }
descriptor_index += 7; // setup to look at next one...
}
// Try to verify the end points.
if (!check_rxtx_ep(rxep, txep)) return false;
print("FTDI, rxep=", rxep & 15);
println(", txep=", txep);
if (!init_buffers(64, 64)) return false;
rxpipe = new_Pipe(dev, 2, rxep & 15, 1, 64);
if (!rxpipe) return false;
txpipe = new_Pipe(dev, 2, txep, 0, 64);
if (!txpipe) {
// TODO: free rxpipe
return false;
} }
descriptor_index += 7; // setup to look at next one...
}
// Try to verify the end points.
if (!check_rxtx_ep(rxep, txep)) return false;
print("USBSerial, rxep=", rxep & 15);
print("(", rx_size);
print("), txep=", txep);
print("(", tx_size);
println(")");
sertype = PL2303; if (!init_buffers(rx_size, tx_size)) return false;
rxpipe->callback_function = rx_callback; println(" rx buffer size:", rxsize);
queue_Data_Transfer(rxpipe, rx1, 64, this); println(" tx buffer size:", txsize);
rxstate = 1;
if (rxsize > 128) {
queue_Data_Transfer(rxpipe, rx2, 64, this);
rxstate = 3;
}
txstate = 0;
txpipe->callback_function = tx_callback;
baudrate = 115200;
// Lets see if it will handle the same CDCACM - messages? rxpipe = new_Pipe(dev, 2, rxep & 15, 1, rx_size);
println("PL2303: readRegister(0x04)"); if (!rxpipe) return false;
// Need to setup the data the line coding data txpipe = new_Pipe(dev, 2, txep, 0, tx_size);
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); if (!txpipe) {
queue_Control_Transfer(dev, &setup, setupdata, this); //free_Pipe(rxpipe);
control_queued = true; return false;
setup_state = 1; // We are at step one of setup... }
pending_control = 0x3f; // Maybe don't need to do... rxpipe->callback_function = rx_callback;
return true; queue_Data_Transfer(rxpipe, rx1, rx_size, this);
rxstate = 1;
txstate = 0;
txpipe->callback_function = tx_callback;
baudrate = 115200;
// Now do specific setup per type
switch (sertype) {
//---------------------------------------------------------------------
// FTDI
case FTDI:
{
pending_control = 0x0F;
mk_setup(setup, 0x40, 0, 0, 0, 0); // reset port
queue_Control_Transfer(dev, &setup, NULL, this);
control_queued = true;
return true;
}
//------------------------------------------------------------------------
// Prolific
// TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them
case PL2303:
{
// First attempt keep it simple...
println("PL2303: readRegister(0x04)");
// Need to setup the data the line coding data
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(dev, &setup, setupdata, this);
control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0x3f;
return true;
}
//------------------------------------------------------------------------
// CH341
case CH341:
{
println("CH341: 0xC0, 0x5f, 0, 0, 8");
// Need to setup the data the line coding data
mk_setup(setup, 0xC0, 0x5f, 0, 0, sizeof(setupdata));
queue_Control_Transfer(dev, &setup, setupdata, this);
control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0x7f;
return true;
}
//------------------------------------------------------------------------
// CP210X
case CP210X:
{
println("CP210X: 0x41, 0x11, 0, 0, 0 - reset port");
// Need to setup the data the line coding data
mk_setup(setup, 0x41, 0x11, 0, 0, 0);
queue_Control_Transfer(dev, &setup, NULL, this);
control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0xf;
return true;
}
//------------------------------------------------------------------------
// PID:VID - not in our product list.
default:
return false;
} }
} else if (type != 1) return false; } else if (type != 1) return false;
// TTYACM: <Composit device> // TTYACM: <Composit device>
@ -424,7 +468,15 @@ void USBSerial::control(const Transfer_t *transfer)
if (pending_control & 1) { if (pending_control & 1) {
pending_control &= ~1; pending_control &= ~1;
// set data format // set data format
mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1 uint16_t ftdi_format = format_ & 0xf; // This should give us the number of bits.
// now lets extract the parity from our encoding
ftdi_format |= (format_ & 0xe0) << 3; // they encode bits 9-11
// See if two stop bits
if (format_ & 0x100) ftdi_format |= (0x2 << 11);
mk_setup(setup, 0x40, 4, ftdi_format, 0, 0); // data format 8N1
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
@ -454,6 +506,15 @@ void USBSerial::control(const Transfer_t *transfer)
control_queued = true; control_queued = true;
return; return;
} }
// clear DTR
if (pending_control & 0x80) {
pending_control &= ~0x80;
println("FTDI clear DTR");
mk_setup(setup, 0x40, 1, 0x0100, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
} }
@ -467,9 +528,9 @@ void USBSerial::control(const Transfer_t *transfer)
setupdata[1] = (baudrate >> 8) & 0xff; setupdata[1] = (baudrate >> 8) & 0xff;
setupdata[2] = (baudrate >> 16) & 0xff; setupdata[2] = (baudrate >> 16) & 0xff;
setupdata[3] = (baudrate >> 24) & 0xff; setupdata[3] = (baudrate >> 24) & 0xff;
setupdata[4] = 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
setupdata[5] = 0; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
setupdata[6] = 8; // Data bits (5, 6, 7, 8 or 16) setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16)
print("CDCACM setup: "); print("CDCACM setup: ");
print_hexbytes(&setupdata, 7); print_hexbytes(&setupdata, 7);
mk_setup(setup, 0x21, 0x20, 0, 0, 7); mk_setup(setup, 0x21, 0x20, 0, 0, 7);
@ -487,6 +548,15 @@ void USBSerial::control(const Transfer_t *transfer)
control_queued = true; control_queued = true;
return; return;
} }
if (pending_control & 0x80) {
pending_control &= ~0x80;
println("Control - 0x21,0x22, 0x0 - clear DTR");
// Need to setup the data the line coding data
mk_setup(setup, 0x21, 0x22, 0, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -607,9 +677,9 @@ void USBSerial::control(const Transfer_t *transfer)
setupdata[1] = (baudrate >> 8) & 0xff; setupdata[1] = (baudrate >> 8) & 0xff;
setupdata[2] = (baudrate >> 16) & 0xff; setupdata[2] = (baudrate >> 16) & 0xff;
setupdata[3] = (baudrate >> 24) & 0xff; setupdata[3] = (baudrate >> 24) & 0xff;
setupdata[4] = 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
setupdata[5] = 0; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
setupdata[6] = 8; // Data bits (5, 6, 7, 8 or 16) setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16)
print("PL2303: Set baud/control: ", baudrate, HEX); print("PL2303: Set baud/control: ", baudrate, HEX);
print(" = "); print(" = ");
print_hexbytes(&setupdata, 7); print_hexbytes(&setupdata, 7);
@ -639,20 +709,258 @@ void USBSerial::control(const Transfer_t *transfer)
print("PL2303: Returned configuration data: "); print("PL2303: Returned configuration data: ");
print_hexbytes(setupdata, 7); print_hexbytes(setupdata, 7);
// This sets the control lines (0x1=DTR, 0x2=RTS)
println("PL2303: 0x21, 0x22, 0x3"); println("PL2303: 0x21, 0x22, 0x3");
mk_setup(setup, 0x21, 0x22, 3, 0, 0); // mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
} }
if (pending_control & 0x30) { if (pending_control & 0x20) {
pending_control &= ~0x30; pending_control &= ~0x20;
println("PL2303: 0x21, 0x22, 0x3"); println("PL2303: 0x21, 0x22, 0x3");
mk_setup(setup, 0x21, 0x22, 3, 0, 0); // mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
} }
if (pending_control & 0x80) {
pending_control &= ~0x80;
println("PL2303: 0x21, 0x22, 0x0"); // Clear DTR/RTS
mk_setup(setup, 0x21, 0x22, 0, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
}
} }
if (sertype == CH341) {
#if 0
print(" Transfer: ");
print_hexbytes(&transfer->setup, sizeof(setup_t));
if (transfer->length) {
print(" data: ");
print_hexbytes(transfer->buffer, transfer->length);
}
#endif
if (pending_control & 1) {
// Still in larger setup state mode
switch (setup_state) {
case 1:
print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, a1, 0, 0, 0");
mk_setup(setup, 0x40, 0xa1, 0, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 2;
control_queued = true;
return;
case 2:
ch341_setBaud(0); // send the first byte of the baud rate
control_queued = true;
setup_state = 3;
return;
case 3:
ch341_setBaud(1); // send the second byte of the baud rate
control_queued = true;
setup_state = 4;
return;
case 4:
println("CH341: c0, 95, 2518, 0, 8");
mk_setup(setup, 0xc0, 0x95, 0x2518, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this);
setup_state = 5;
control_queued = true;
return;
case 5:
print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, 0x9a, 0x2518, 0x0050, 0");
mk_setup(setup, 0x40, 0x9a, 0x2518, 0x0050, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 6;
control_queued = true;
return;
case 6:
println("CH341: c0, 95, 0x706, 0, 8 - get status");
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this);
setup_state = 7;
control_queued = true;
return;
case 7:
print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, 0xa1, 0x501f, 0xd90a, 0");
mk_setup(setup, 0x40, 0xa1, 0x501f, 0xd90a, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 8;
control_queued = true;
break;
}
pending_control &= ~1; // We are finally going to leave this list and join the rest
if (control_queued) return;
}
// set baud rate
if (pending_control & 2) {
pending_control &= ~2;
ch341_setBaud(0); // send the first byte of the baud rate
control_queued = true;
return;
}
if (pending_control & 4) {
pending_control &= ~4;
ch341_setBaud(1); // send the first byte of the baud rate
control_queued = true;
return;
}
if (pending_control & 8) {
pending_control &= ~8;
uint16_t ch341_format;
switch (format_) {
default:
// These values were observed when used on PC... Need to flush out others.
case USBHOST_SERIAL_8N1: ch341_format = 0xc3; break;
case USBHOST_SERIAL_7E1: ch341_format = 0xda; break;
case USBHOST_SERIAL_7O1: ch341_format = 0xca; break;
case USBHOST_SERIAL_8N2: ch341_format = 0xc7; break;
}
println("CH341: 40, 0x9a, 0x2518: ", ch341_format, HEX);
mk_setup(setup, 0x40, 0x9a, 0x2518, ch341_format, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
if (pending_control & 0x10) {
pending_control &= ~0x10;
// This is setting handshake need to figure out what...
// 0x20=DTR, 0x40=RTS send ~ of values.
println("CH341: 0x40, 0xa4, 0xff9f, 0, 0 - Handshake");
mk_setup(setup, 0x40, 0xa4, 0xff9f, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
if (pending_control & 0x20) {
pending_control &= ~0x20;
// This is setting handshake need to figure out what...
println("CH341: c0, 95, 0x706, 0, 8 - get status");
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true;
return;
}
if (pending_control & 0x40) {
pending_control &= ~0x40;
print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 0x40, 0x9a, 0x2727, 0, 0");
mk_setup(setup, 0x40, 0x9a, 0x2727, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
return;
}
if (pending_control & 0x80) {
pending_control &= ~0x80;
println("CH341: 0x40, 0xa4, 0xffff, 0, 0 - Handshake");
mk_setup(setup, 0x40, 0xa4, 0xffff, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
}
//-------------------------------------------------------------------------
// First CP210X
if (sertype == CP210X) {
if (pending_control & 1) {
pending_control &= ~1;
// set data format
uint16_t cp210x_format = (format_ & 0xf) << 8; // This should give us the number of bits.
// now lets extract the parity from our encoding bits 5-7 and in theres 4-7
cp210x_format |= (format_ & 0xe0) >> 1; // they encode bits 9-11
// See if two stop bits
if (format_ & 0x100) cp210x_format |= 2;
mk_setup(setup, 0x41, 3, cp210x_format, 0, 0); // data format 8N1
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
// set baud rate
if (pending_control & 2) {
pending_control &= ~2;
setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200
setupdata[1] = (baudrate >> 8) & 0xff;
setupdata[2] = (baudrate >> 16) & 0xff;
setupdata[3] = (baudrate >> 24) & 0xff;
mk_setup(setup, 0x40, 0x1e, 0, 0, 4);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true;
return;
}
// configure flow control
if (pending_control & 4) {
pending_control &= ~4;
memset(setupdata, 0, sizeof(setupdata)); // clear out the data
setupdata[0] = 1; // Set dtr active?
mk_setup(setup, 0x41, 13, 0, 0, 0x10);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true;
return;
}
// set DTR
if (pending_control & 8) {
pending_control &= ~8;
mk_setup(setup, 0x41, 7, 0x0101, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
// clear DTR
if (pending_control & 0x80) {
pending_control &= ~0x80;
println("CP210x clear DTR");
mk_setup(setup, 0x40, 1, 0x0100, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
return;
}
}
}
#define CH341_BAUDBASE_FACTOR 1532620800
#define CH341_BAUDBASE_DIVMAX 3
void USBSerial::ch341_setBaud(uint8_t byte_index) {
if (byte_index == 0) {
uint32_t factor;
uint16_t divisor;
factor = (CH341_BAUDBASE_FACTOR / baudrate);
divisor = CH341_BAUDBASE_DIVMAX;
while ((factor > 0xfff0) && divisor) {
factor >>= 3;
divisor--;
}
factor = 0x10000 - factor;
factor = (factor & 0xff00) | divisor;
setupdata[0] = factor & 0xff; // save away the low byte for 2nd message
println("CH341: 40, 0x9a, 0x1312... (Baud word 0):", factor, HEX);
mk_setup(setup, 0x40, 0x9a, 0x1312, factor, 0); //
} else {
// Second packet use the byte we saved away during the calculation above
println("CH341: 40, 0x9a, 0x0f2c... (Baud word 1):", setupdata[0], HEX);
mk_setup(setup, 0x40, 0x9a, 0x0f2c, setupdata[0], 0); //
}
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true;
} }
@ -677,6 +985,7 @@ void USBSerial::rx_data(const Transfer_t *transfer)
{ {
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
debugDigitalToggle(6);
// first update rxstate bitmask, since buffer is no longer queued // first update rxstate bitmask, since buffer is no longer queued
if (transfer->buffer == rx1) { if (transfer->buffer == rx1) {
rxstate &= 0xFE; rxstate &= 0xFE;
@ -694,6 +1003,11 @@ void USBSerial::rx_data(const Transfer_t *transfer)
} }
} }
if (len > 0) { if (len > 0) {
print("rx token: ", transfer->qtd.token, HEX);
print(" transfer length: ", transfer->length, DEC);
print(" len:", len, DEC);
print(" - ", *p, HEX);
println(" ", *(p+1), HEX);
print("rx: "); print("rx: ");
print_hexbytes(p, len); print_hexbytes(p, len);
} }
@ -760,6 +1074,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
{ {
uint32_t mask; uint32_t mask;
uint8_t *p = (uint8_t *)transfer->buffer; uint8_t *p = (uint8_t *)transfer->buffer;
debugDigitalWrite(5, HIGH);
if (p == tx1) { if (p == tx1) {
println("tx1:"); println("tx1:");
mask = 1; mask = 1;
@ -769,6 +1084,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
mask = 2; mask = 2;
//txstate &= 0xFD; //txstate &= 0xFD;
} else { } else {
debugDigitalWrite(5, LOW);
return; // should never happen return; // should never happen
} }
// check how much more data remains in the transmit buffer // check how much more data remains in the transmit buffer
@ -781,50 +1097,72 @@ void USBSerial::tx_data(const Transfer_t *transfer)
count = txsize + head - tail; count = txsize + head - tail;
} }
uint32_t packetsize = tx2 - tx1; uint32_t packetsize = tx2 - tx1;
if (count < packetsize) { // Only output full packets unless the flush bit was set.
if ((count == 0) || ((count < packetsize) && ((txstate & 0x4) == 0) )) {
// not enough data in buffer to fill a full packet // not enough data in buffer to fill a full packet
txstate &= ~mask; txstate &= ~(mask | 4); // turn off that transfer and make sure the flush bit is not set
debugDigitalWrite(5, LOW);
return; return;
} }
// immediately transmit another full packet, if we have enough data // immediately transmit another full packet, if we have enough data
if (count >= packetsize) count = packetsize;
else txstate &= ~(mask | 4); // This packet will complete any outstanding flush
println("TX:moar data!!!!"); println("TX:moar data!!!!");
if (++tail >= txsize) tail = 0; if (++tail >= txsize) tail = 0;
uint32_t n = txsize - tail; uint32_t n = txsize - tail;
if (n > packetsize) n = packetsize; if (n > count) n = count;
memcpy(p, txbuf + tail, n); memcpy(p, txbuf + tail, n);
if (n >= packetsize) { if (n >= count) {
tail += n - 1; tail += n - 1;
if (tail >= txsize) tail = 0; if (tail >= txsize) tail = 0;
} else { } else {
uint32_t len = packetsize - n; uint32_t len = count - n;
memcpy(p + n, txbuf, len); memcpy(p + n, txbuf, len);
tail = len - 1; tail = len - 1;
} }
txtail = tail; txtail = tail;
queue_Data_Transfer(txpipe, p, packetsize, this); queue_Data_Transfer(txpipe, p, count, this);
debugDigitalWrite(5, LOW);
} }
void USBSerial::flush()
{
print("USBSerial::flush");
if (txhead == txtail) {
println(" - Empty");
return; // empty.
}
debugDigitalWrite(32, HIGH);
NVIC_DISABLE_IRQ(IRQ_USBHS);
txtimer.stop(); // Stop longer timer.
txtimer.start(100); // Start a mimimal timeout
// timer_event(nullptr); // Try calling direct - fails to work
NVIC_ENABLE_IRQ(IRQ_USBHS);
while (txstate & 3) ; // wait for all of the USB packets to be sent.
println(" completed");
debugDigitalWrite(32, LOW);
}
void USBSerial::timer_event(USBDriverTimer *whichTimer) void USBSerial::timer_event(USBDriverTimer *whichTimer)
{ {
debugDigitalWrite(7, HIGH);
println("txtimer"); println("txtimer");
uint32_t count; uint32_t count;
uint32_t head = txhead; uint32_t head = txhead;
uint32_t tail = txtail; uint32_t tail = txtail;
if (pending_control) {
// We are still doing setup postpone for awhile..
txtimer.start(1200);
println(" Postpone: setup pending_control");
return; // no outgoing buffers available, try again later
}
if (head == tail) { if (head == tail) {
println(" *** Empty ***"); println(" *** Empty ***");
debugDigitalWrite(7, LOW);
return; // nothing to transmit return; // nothing to transmit
} else if (head > tail) { } else if (head > tail) {
count = head - tail; count = head - tail;
} else { } else {
count = txsize + head - tail; count = txsize + head - tail;
} }
uint8_t *p; uint8_t *p;
if ((txstate & 0x01) == 0) { if ((txstate & 0x01) == 0) {
p = tx1; p = tx1;
@ -833,10 +1171,20 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
p = tx2; p = tx2;
txstate |= 0x02; txstate |= 0x02;
} else { } else {
txtimer.start(1200); txstate |= 4; // Tell the TX code to do flush code.
println(" *** No buffers ***"); println(" *** No buffers ***");
debugDigitalWrite(7, LOW);
return; // no outgoing buffers available, try again later return; // no outgoing buffers available, try again later
} }
uint32_t packetsize = tx2 - tx1;
// Possible for remaining ? packet size and not have both?
if (count > packetsize) {
txstate |= 4; // One of the active transfers will handle the remaining parts
count = packetsize;
}
if (++tail >= txsize) tail = 0; if (++tail >= txsize) tail = 0;
uint32_t n = txsize - tail; uint32_t n = txsize - tail;
if (n > count) n = count; if (n > count) n = count;
@ -854,6 +1202,7 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
print(") "); print(") ");
print_hexbytes(p, count); print_hexbytes(p, count);
queue_Data_Transfer(txpipe, p, count, this); queue_Data_Transfer(txpipe, p, count, this);
debugDigitalWrite(7, LOW);
} }
@ -866,14 +1215,41 @@ void USBSerial::begin(uint32_t baud, uint32_t format)
{ {
NVIC_DISABLE_IRQ(IRQ_USBHS); NVIC_DISABLE_IRQ(IRQ_USBHS);
baudrate = baud; baudrate = baud;
pending_control |= 2; bool format_changed = format != format_;
format_ = format;
switch (sertype) {
default:
case CDCACM: pending_control |= 0x6; break;
case FTDI: pending_control |= (format_changed? 0xf : 0xe); break; // Set BAUD, FLOW, DTR
case PL2303: pending_control |= 0x1e; break; // set more stuff...
case CH341: pending_control |= 0x1e; break;
case CP210X: pending_control |= 0xf; break;
}
if (!control_queued) control(NULL); if (!control_queued) control(NULL);
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);
// Wait until all packets have been queued before we return to caller.
while (pending_control) {
yield(); // not sure if we want to yield or what?
}
} }
void USBSerial::end(void) void USBSerial::end(void)
{ {
// TODO: lower DTR NVIC_DISABLE_IRQ(IRQ_USBHS);
switch (sertype) {
default:
case CDCACM: pending_control |= 0x80; break;
case FTDI: pending_control |= 0x80; break; // clear DTR
case PL2303: pending_control |= 0x80; break;
case CH341: pending_control |= 0x80; break;
}
if (!control_queued) control(NULL);
NVIC_ENABLE_IRQ(IRQ_USBHS);
// Wait until all packets have been queued before we return to caller.
while (pending_control) {
yield(); // not sure if we want to yield or what?
}
} }
int USBSerial::available(void) int USBSerial::available(void)
@ -975,14 +1351,16 @@ size_t USBSerial::write(uint8_t c)
} }
txtail = tail; txtail = tail;
//println("queue tx packet, newtail=", tail); //println("queue tx packet, newtail=", tail);
debugDigitalWrite(7, HIGH);
queue_Data_Transfer(txpipe, p, packetsize, this); queue_Data_Transfer(txpipe, p, packetsize, this);
debugDigitalWrite(7, LOW);
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);
return 1; return 1;
} }
} }
// otherwise, set a latency timer to later transmit partial packet // otherwise, set a latency timer to later transmit partial packet
txtimer.stop(); txtimer.stop();
txtimer.start(3500); txtimer.start(write_timeout_);
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);
return 1; return 1;
} }