mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-11-21 08:35:03 -05:00
commit
5cd2d8c799
212
USBHost_t36.h
212
USBHost_t36.h
@ -56,7 +56,7 @@
|
||||
// your best effort to read chapter 4 before asking USB questions!
|
||||
|
||||
|
||||
//#define USBHOST_PRINT_DEBUG
|
||||
#define USBHOST_PRINT_DEBUG
|
||||
|
||||
/************************************************/
|
||||
/* Data Types */
|
||||
@ -80,6 +80,7 @@ class USBHost;
|
||||
typedef struct Device_struct Device_t;
|
||||
typedef struct Pipe_struct Pipe_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.
|
||||
// Drivers build user-visible functionality on top
|
||||
@ -91,6 +92,7 @@ class USBDriverTimer;
|
||||
/************************************************/
|
||||
/* Added Defines */
|
||||
/************************************************/
|
||||
// Keyboard special Keys
|
||||
#define KEYD_UP 0xDA
|
||||
#define KEYD_DOWN 0xD9
|
||||
#define KEYD_LEFT 0xD8
|
||||
@ -114,6 +116,22 @@ class USBDriverTimer;
|
||||
#define KEYD_F11 0xCC
|
||||
#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 */
|
||||
/************************************************/
|
||||
@ -252,11 +270,12 @@ protected:
|
||||
static void disconnect_Device(Device_t *dev);
|
||||
static void enumeration(const Transfer_t *transfer);
|
||||
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_Pipes(Pipe_t *pipes, 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 volatile bool enumeration_busy;
|
||||
private:
|
||||
static void isr();
|
||||
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
|
||||
// HID input data fully decoded by the USBHIDParser driver
|
||||
class USBHIDParser;
|
||||
|
||||
class USBHIDInput {
|
||||
public:
|
||||
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]]; }
|
||||
|
||||
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_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
@ -559,10 +582,12 @@ private:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
class USBHIDParser : public USBDriver {
|
||||
public:
|
||||
USBHIDParser(USBHost &host) { init(); }
|
||||
static void driver_ready_for_hid_collection(USBHIDInput *driver);
|
||||
bool sendPacket(const uint8_t *buffer);
|
||||
protected:
|
||||
enum { TOPUSAGE_LIST_LEN = 4 };
|
||||
enum { USAGE_LIST_LEN = 24 };
|
||||
@ -578,6 +603,14 @@ protected:
|
||||
USBHIDInput * find_driver(uint32_t topusage);
|
||||
void parse(uint16_t type_and_report_id, const uint8_t *data, uint32_t len);
|
||||
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:
|
||||
Pipe_t *in_pipe;
|
||||
Pipe_t *out_pipe;
|
||||
@ -594,11 +627,15 @@ private:
|
||||
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
|
||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32)));
|
||||
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:
|
||||
typedef union {
|
||||
struct {
|
||||
@ -614,8 +651,10 @@ typedef union {
|
||||
public:
|
||||
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; }
|
||||
uint8_t getModifiers() { return modifiers; }
|
||||
uint8_t getOemKey() { return keyOEM; }
|
||||
@ -630,6 +669,13 @@ public:
|
||||
void numLock(bool f);
|
||||
void capsLock(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:
|
||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
|
||||
virtual void control(const Transfer_t *transfer);
|
||||
@ -637,6 +683,14 @@ protected:
|
||||
static void callback(const Transfer_t *transfer);
|
||||
void new_data(const Transfer_t *transfer);
|
||||
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:
|
||||
void update();
|
||||
uint16_t convert_to_unicode(uint32_t mod, uint32_t key);
|
||||
@ -652,43 +706,22 @@ private:
|
||||
uint8_t keyOEM;
|
||||
uint8_t prev_report[8];
|
||||
KBDLeds_t leds_ = {0};
|
||||
bool update_leds_ = false;
|
||||
bool processing_new_data_ = false;
|
||||
Pipe_t mypipes[2] __attribute__ ((aligned(32)));
|
||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32)));
|
||||
strbuf_t mystring_bufs[1];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class KeyboardHIDExtrasController : public USBHIDInput {
|
||||
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);
|
||||
// Added to process secondary HID data.
|
||||
void (*extrasKeyPressedFunction)(uint32_t top, uint16_t code);
|
||||
void (*extrasKeyReleasedFunction)(uint32_t top, uint16_t code);
|
||||
uint32_t topusage_ = 0; // What top report am I processing?
|
||||
uint8_t collections_claimed_ = 0;
|
||||
volatile bool event_ = false;
|
||||
volatile bool hid_input_begin_ = false;
|
||||
volatile bool hid_input_data_ = false; // did we receive any valid data with report?
|
||||
uint8_t count_keys_down_ = 0;
|
||||
uint16_t keys_down[MAX_KEYS_DOWN];
|
||||
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class MouseController : public USBHIDInput {
|
||||
public:
|
||||
@ -701,7 +734,7 @@ public:
|
||||
int getWheel() { return wheel; }
|
||||
int getWheelH() { return wheelH; }
|
||||
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_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
@ -719,27 +752,76 @@ private:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class JoystickController : public USBHIDInput {
|
||||
class JoystickController : public USBDriver, public USBHIDInput {
|
||||
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; }
|
||||
void joystickDataClear();
|
||||
uint32_t getButtons() { return buttons; }
|
||||
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:
|
||||
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_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
virtual void disconnect_collection(Device_t *dev);
|
||||
private:
|
||||
uint8_t collections_claimed = 0;
|
||||
|
||||
// Class specific
|
||||
void init();
|
||||
|
||||
bool anychange = false;
|
||||
volatile bool joystickEvent = false;
|
||||
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 {
|
||||
@ -889,17 +971,23 @@ private:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class USBSerial: public USBDriver, public Stream {
|
||||
public:
|
||||
public:
|
||||
|
||||
|
||||
// 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 { DEFAULT_WRITE_TIMEOUT = 3500};
|
||||
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);
|
||||
uint32_t writeTimeout() {return write_timeout_;}
|
||||
void writeTimeOut(uint32_t write_timeout) {write_timeout_ = write_timeout;} // Will not impact current ones.
|
||||
virtual int available(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual int availableForWrite();
|
||||
virtual size_t write(uint8_t c);
|
||||
virtual void flush(void);
|
||||
|
||||
using Print::write;
|
||||
protected:
|
||||
@ -916,6 +1004,7 @@ private:
|
||||
void init();
|
||||
static bool check_rxtx_ep(uint32_t &rxep, uint32_t &txep);
|
||||
bool init_buffers(uint32_t rsize, uint32_t tsize);
|
||||
void ch341_setBaud(uint8_t byte_index);
|
||||
private:
|
||||
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
|
||||
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
|
||||
@ -923,8 +1012,10 @@ private:
|
||||
USBDriverTimer txtimer;
|
||||
uint32_t bigbuffer[(BUFFER_SIZE+3)/4];
|
||||
setup_t setup;
|
||||
uint8_t setupdata[8];
|
||||
uint8_t setupdata[16]; //
|
||||
uint32_t baudrate;
|
||||
uint32_t format_;
|
||||
uint32_t write_timeout_ = DEFAULT_WRITE_TIMEOUT;
|
||||
Pipe_t *rxpipe;
|
||||
Pipe_t *txpipe;
|
||||
uint8_t *rx1; // location for first incoming packet
|
||||
@ -947,7 +1038,16 @@ private:
|
||||
uint8_t pl2303_v2;
|
||||
uint8_t interface;
|
||||
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)
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
39
ehci.cpp
39
ehci.cpp
@ -1252,12 +1252,28 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
|
||||
// TODO: does this write interfere UPI & UAI (bits 18 & 19) ??
|
||||
}
|
||||
// find & free all the transfers which completed
|
||||
println(" Free transfers");
|
||||
Transfer_t *t = async_followup_first;
|
||||
while (t) {
|
||||
print(" * ", (uint32_t)t);
|
||||
Transfer_t *next = t->next_followup;
|
||||
if (t->pipe == pipe) {
|
||||
print(" * remove");
|
||||
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;
|
||||
}
|
||||
@ -1286,12 +1302,28 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
|
||||
// TODO: subtract bandwidth from uframe_bandwidth array
|
||||
|
||||
// find & free all the transfers which completed
|
||||
println(" Free transfers");
|
||||
Transfer_t *t = periodic_followup_first;
|
||||
while (t) {
|
||||
print(" * ", (uint32_t)t);
|
||||
Transfer_t *next = t->next_followup;
|
||||
if (t->pipe == pipe) {
|
||||
print(" * remove");
|
||||
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;
|
||||
}
|
||||
@ -1300,14 +1332,17 @@ void USBHost::delete_Pipe(Pipe_t *pipe)
|
||||
// TODO: do we need to look at pipe->qh.current ??
|
||||
//
|
||||
// free all the transfers still attached to the QH
|
||||
println(" Free transfers attached to QH");
|
||||
Transfer_t *tr = (Transfer_t *)(pipe->qh.next);
|
||||
while ((uint32_t)tr & 0xFFFFFFE0) {
|
||||
println(" * ", (uint32_t)tr);
|
||||
Transfer_t *next = (Transfer_t *)(tr->qtd.next);
|
||||
free_Transfer(tr);
|
||||
tr = next;
|
||||
}
|
||||
// hopefully we found everything...
|
||||
free_Pipe(pipe);
|
||||
println("* Delete Pipe completed");
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,11 +7,9 @@
|
||||
USBHost myusb;
|
||||
USBHub hub1(myusb);
|
||||
USBHub hub2(myusb);
|
||||
USBHub hub3(myusb);
|
||||
USBHub hub4(myusb);
|
||||
KeyboardController keyboard1(myusb);
|
||||
KeyboardController keyboard2(myusb);
|
||||
KeyboardHIDExtrasController hidextras(myusb);
|
||||
//KeyboardHIDExtrasController hidextras(myusb);
|
||||
USBHIDParser hid1(myusb);
|
||||
USBHIDParser hid2(myusb);
|
||||
USBHIDParser hid3(myusb);
|
||||
@ -19,16 +17,18 @@ USBHIDParser hid4(myusb);
|
||||
USBHIDParser hid5(myusb);
|
||||
MouseController mouse1(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]))
|
||||
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};
|
||||
|
||||
// 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]))
|
||||
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};
|
||||
|
||||
|
||||
@ -40,8 +40,13 @@ void setup()
|
||||
myusb.begin();
|
||||
keyboard1.attachPress(OnPress);
|
||||
keyboard2.attachPress(OnPress);
|
||||
hidextras.attachPress(OnHIDExtrasPress);
|
||||
hidextras.attachRelease(OnHIDExtrasRelease);
|
||||
keyboard1.attachExtrasPress(OnHIDExtrasPress);
|
||||
keyboard1.attachExtrasRelease(OnHIDExtrasRelease);
|
||||
keyboard2.attachExtrasPress(OnHIDExtrasPress);
|
||||
keyboard2.attachExtrasRelease(OnHIDExtrasRelease);
|
||||
|
||||
rawhid1.attachReceive(OnReceiveHidData);
|
||||
rawhid2.attachReceive(OnReceiveHidData);
|
||||
}
|
||||
|
||||
|
||||
@ -104,25 +109,31 @@ void loop()
|
||||
mouse1.mouseDataClear();
|
||||
}
|
||||
if (joystick1.available()) {
|
||||
uint32_t axis_mask = joystick1.axisMask();
|
||||
Serial.print("Joystick: buttons = ");
|
||||
Serial.print(joystick1.getButtons(), HEX);
|
||||
Serial.print(", X = ");
|
||||
Serial.print(joystick1.getAxis(0));
|
||||
Serial.print(", Y = ");
|
||||
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));
|
||||
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
|
||||
if (axis_mask & 1) {
|
||||
Serial.printf(" %d:%d", i, joystick1.getAxis(i));
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
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.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
0
examples/Mouse/defs.h
Normal file
@ -4,6 +4,8 @@
|
||||
|
||||
#include "USBHost_t36.h"
|
||||
#define USBBAUD 115200
|
||||
uint32_t baud = USBBAUD;
|
||||
uint32_t format = USBHOST_SERIAL_8N1;
|
||||
USBHost myusb;
|
||||
USBHub hub1(myusb);
|
||||
USBHub hub2(myusb);
|
||||
@ -60,23 +62,8 @@ void loop()
|
||||
// If this is a new Serial device.
|
||||
if (drivers[i] == &userial) {
|
||||
// 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 == '$') {
|
||||
BioloidTest();
|
||||
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 0xfd
|
||||
// Extract stuff from Bioloid library..
|
||||
#define AX12_BUFFER_SIZE 128
|
||||
#define COUNTER_TIMEOUT 12000
|
||||
|
||||
/** Instruction Set **/
|
||||
#define AX_PING 1
|
||||
/** Instruction Set **/ #define AX_PING 1
|
||||
#define AX_READ_DATA 2
|
||||
#define AX_WRITE_DATA 3
|
||||
#define AX_REG_WRITE 4
|
||||
@ -244,7 +289,7 @@ int ax12ReadPacket(int length) {
|
||||
while ((ch = userial.read()) == -1) {
|
||||
if ((millis() - ulStart) > 10) {
|
||||
//if (!--ulCounter) {
|
||||
// Serial.println("Timeout");
|
||||
Serial.println("Timeout");
|
||||
return 0; // Timeout
|
||||
}
|
||||
}
|
||||
|
0
examples/SerialTest/defs.h
Normal file
0
examples/SerialTest/defs.h
Normal file
67
hid.cpp
67
hid.cpp
@ -128,21 +128,19 @@ bool USBHIDParser::claim(Device_t *dev, int type, const uint8_t *descriptors, ui
|
||||
if (((endpoint1 & 0xF0) == 0x80) && ((endpoint2 & 0xF0) == 0)) {
|
||||
// first endpoint is IN, second endpoint is OUT
|
||||
in_pipe = new_Pipe(dev, 3, endpoint1 & 0x0F, 1, size1, interval1);
|
||||
//out_pipe = new_Pipe(dev, 3, endpoint2, 0, size2, interval2);
|
||||
out_pipe = NULL; // TODO; fixme
|
||||
out_pipe = new_Pipe(dev, 3, endpoint2, 0, size2, interval2);
|
||||
in_size = size1;
|
||||
out_size = size2;
|
||||
} else if (((endpoint1 & 0xF0) == 0) && ((endpoint2 & 0xF0) == 0x80)) {
|
||||
// first endpoint is OUT, second endpoint is IN
|
||||
in_pipe = new_Pipe(dev, 3, endpoint2 & 0x0F, 1, size2, interval2);
|
||||
//out_pipe = new_Pipe(dev, 3, endpoint1, 0, size1, interval1);
|
||||
out_pipe = NULL; // TODO; fixme
|
||||
out_pipe = new_Pipe(dev, 3, endpoint1, 0, size1, interval1);
|
||||
in_size = size2;
|
||||
out_size = size1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
//out_pipe->callback_function = out_callback;
|
||||
out_pipe->callback_function = out_callback;
|
||||
}
|
||||
in_pipe->callback_function = in_callback;
|
||||
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)
|
||||
{
|
||||
//println("USBHIDParser:: out_callback (static)");
|
||||
if (transfer->driver) {
|
||||
((USBHIDParser*)(transfer->driver))->out_data(transfer);
|
||||
}
|
||||
@ -215,14 +214,22 @@ void USBHIDParser::in_data(const Transfer_t *transfer)
|
||||
Serial.println(); */
|
||||
|
||||
print("HID: ");
|
||||
print(use_report_id);
|
||||
print(" - ");
|
||||
print_hexbytes(transfer->buffer, transfer->length);
|
||||
const uint8_t *buf = (const uint8_t *)transfer->buffer;
|
||||
uint32_t len = transfer->length;
|
||||
if (use_report_id == false) {
|
||||
parse(0x0100, buf, len);
|
||||
} else {
|
||||
if (len > 1) {
|
||||
parse(0x0100 | buf[0], buf + 1, len - 1);
|
||||
|
||||
// See if the first top report wishes to bypass the
|
||||
// parse...
|
||||
if (!(topusage_drivers[0] && topusage_drivers[0]->hid_process_in_data(transfer))) {
|
||||
|
||||
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);
|
||||
@ -231,8 +238,44 @@ void USBHIDParser::in_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
|
||||
// HID report descriptor. It finds all the top level collections
|
||||
// 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");
|
||||
USBHIDInput *driver = available_hid_drivers_list;
|
||||
hidclaim_t claim_type;
|
||||
while (driver) {
|
||||
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;
|
||||
}
|
||||
driver = driver->next;
|
||||
|
230
joystick.cpp
230
joystick.cpp
@ -24,24 +24,80 @@
|
||||
#include <Arduino.h>
|
||||
#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
|
||||
if (topusage != 0x10004 && topusage != 0x10005) return false;
|
||||
if (topusage != 0x10004 && topusage != 0x10005) return CLAIM_NO;
|
||||
// only claim from one physical device
|
||||
if (mydevice != NULL && dev != mydevice) return false;
|
||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
|
||||
mydevice = dev;
|
||||
collections_claimed++;
|
||||
anychange = true; // always report values on first read
|
||||
return true;
|
||||
return CLAIM_REPORT;
|
||||
}
|
||||
|
||||
void JoystickController::disconnect_collection(Device_t *dev)
|
||||
{
|
||||
if (--collections_claimed == 0) {
|
||||
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) {
|
||||
// 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;
|
||||
axis_mask_ |= (1 << i); // Keep record of which axis we have data on.
|
||||
if (axis[i] != value) {
|
||||
axis[i] = value;
|
||||
anychange = true;
|
||||
@ -92,4 +149,167 @@ void JoystickController::joystickDataClear() {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
114
keyboard.cpp
114
keyboard.cpp
@ -98,6 +98,7 @@ void KeyboardController::init()
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
processing_new_data_ = true;
|
||||
println("KeyboardController Callback (member)");
|
||||
print(" KB Data: ");
|
||||
print_hexbytes(transfer->buffer, 8);
|
||||
@ -197,12 +197,6 @@ void KeyboardController::new_data(const Transfer_t *transfer)
|
||||
}
|
||||
memcpy(prev_report, report, 8);
|
||||
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() {
|
||||
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.
|
||||
static uint8_t keyboard_keys_report[1] = {0};
|
||||
setup_t keys_setup;
|
||||
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;
|
||||
mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds
|
||||
queue_Control_Transfer(device, &setup, &leds_.byte, this);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
19
keywords.txt
19
keywords.txt
@ -8,7 +8,7 @@ MIDIDevice KEYWORD1
|
||||
USBSerial KEYWORD1
|
||||
AntPlus KEYWORD1
|
||||
JoystickController KEYWORD1
|
||||
KeyboardHIDExtrasController KEYWORD1
|
||||
RawHIDController KEYWORD1
|
||||
|
||||
# Common Functions
|
||||
Task KEYWORD2
|
||||
@ -24,11 +24,13 @@ getModifiers KEYWORD2
|
||||
getOemKey KEYWORD2
|
||||
attachPress KEYWORD2
|
||||
attachRelease KEYWORD2
|
||||
attachExtrasPress KEYWORD2
|
||||
attachExtrasRelease KEYWORD2
|
||||
LEDS KEYWORD2
|
||||
updateLEDS KEYWORD2
|
||||
numLock KEYWORD2
|
||||
capsLock KEYWORD2
|
||||
scrollLock
|
||||
scrollLock KEYWORD2
|
||||
|
||||
# MIDIDevice
|
||||
getType KEYWORD2
|
||||
@ -78,4 +80,17 @@ getWheelH KEYWORD2
|
||||
# JoystickController
|
||||
joystickDataClear 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
|
||||
|
@ -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
|
||||
if (topusage != 0x10002) return false;
|
||||
if (topusage != 0x10002) return CLAIM_NO;
|
||||
// only claim from one physical device
|
||||
if (mydevice != NULL && dev != mydevice) return false;
|
||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
|
||||
mydevice = dev;
|
||||
collections_claimed++;
|
||||
return true;
|
||||
return CLAIM_REPORT;
|
||||
}
|
||||
|
||||
void MouseController::disconnect_collection(Device_t *dev)
|
||||
|
120
rawhid.cpp
Normal file
120
rawhid.cpp
Normal 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;
|
||||
// }
|
||||
}
|
||||
|
||||
|
654
serial.cpp
654
serial.cpp
@ -19,6 +19,8 @@
|
||||
* 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.
|
||||
*
|
||||
* Note: special thanks to the Linux kernel for the CH341's method of operation, particularly how the baud rate is encoded.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
@ -27,15 +29,35 @@
|
||||
#define print USBHost::print_
|
||||
#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 {
|
||||
uint32_t dwDTERate; // Data Terminal Rate in bits per second
|
||||
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
|
||||
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
|
||||
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
|
||||
} LINE_CODING;
|
||||
USBSerial::product_vendor_mapping_t USBSerial::pid_vid_mapping[] = {
|
||||
// FTDI mappings.
|
||||
{0x0403, 0x6001, USBSerial::FTDI},
|
||||
|
||||
// PL2303
|
||||
{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
|
||||
@ -47,6 +69,7 @@ void USBSerial::init()
|
||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
|
||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
|
||||
driver_ready_for_device(this);
|
||||
format_ = USBHOST_SERIAL_8N1;
|
||||
}
|
||||
|
||||
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);
|
||||
print_hexbytes(descriptors, len);
|
||||
if (type == 0) {
|
||||
if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) {
|
||||
// FTDI FT232
|
||||
println("len = ", len);
|
||||
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)) {
|
||||
//---------------------------------------------------------------------
|
||||
// CDCACM
|
||||
if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) {
|
||||
// It is a communication device see if we can extract the data...
|
||||
// Try some ttyACM types?
|
||||
// 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);
|
||||
if (!rx_ep || !tx_ep) return false; // did not get our two end points
|
||||
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);
|
||||
if (!rxpipe) return false;
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them
|
||||
if (dev->idVendor == 0x67B && dev->idProduct == 0x2303) {
|
||||
// Prolific Technology, Inc. PL2303 Serial Port
|
||||
println("len = ", len);
|
||||
uint8_t count_end_points = descriptors[4];
|
||||
if (count_end_points < 2) return false; // not enough end points
|
||||
if (len < 23) return false;
|
||||
if (descriptors[0] != 9) return false; // length 9
|
||||
// See if the vendor_id:product_id is in our list of products.
|
||||
sertype = UNKNOWN;
|
||||
for (uint8_t i = 0; 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)) {
|
||||
sertype = pid_vid_mapping[i].sertype;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sertype == UNKNOWN) return false; // not one of ours
|
||||
|
||||
// Lets walk through end points and see if we
|
||||
// can find an RX and TX bulk transfer end point.
|
||||
//vid=67B, pid=2303
|
||||
// 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
|
||||
//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
|
||||
uint32_t rxep = 0;
|
||||
uint32_t txep = 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] == 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];
|
||||
} else {
|
||||
txep = descriptors[descriptor_index+2];
|
||||
}
|
||||
// Lets try to locate the end points. Code is common across these devices
|
||||
println("len = ", len);
|
||||
uint8_t count_end_points = descriptors[4];
|
||||
if (count_end_points < 2) return false; // not enough end points
|
||||
if (len < 23) return false;
|
||||
if (descriptors[0] != 9) return false; // length 9
|
||||
|
||||
// Lets walk through end points and see if we
|
||||
// can find an RX and TX bulk transfer end point.
|
||||
//Example vid=67B, pid=2303
|
||||
// 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
|
||||
//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
|
||||
uint32_t rxep = 0;
|
||||
uint32_t txep = 0;
|
||||
uint16_t rx_size = 0;
|
||||
uint16_t 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] == 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;
|
||||
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;
|
||||
if (!init_buffers(rx_size, tx_size)) return false;
|
||||
println(" rx buffer size:", rxsize);
|
||||
println(" tx buffer size:", txsize);
|
||||
|
||||
// Lets see if it will handle the same CDCACM - messages?
|
||||
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; // Maybe don't need to do...
|
||||
return true;
|
||||
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, 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;
|
||||
// TTYACM: <Composit device>
|
||||
@ -424,7 +468,15 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
if (pending_control & 1) {
|
||||
pending_control &= ~1;
|
||||
// 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);
|
||||
control_queued = true;
|
||||
return;
|
||||
@ -454,6 +506,15 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
control_queued = true;
|
||||
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[2] = (baudrate >> 16) & 0xff;
|
||||
setupdata[3] = (baudrate >> 24) & 0xff;
|
||||
setupdata[4] = 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[6] = 8; // Data bits (5, 6, 7, 8 or 16)
|
||||
setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
|
||||
setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
|
||||
setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16)
|
||||
print("CDCACM setup: ");
|
||||
print_hexbytes(&setupdata, 7);
|
||||
mk_setup(setup, 0x21, 0x20, 0, 0, 7);
|
||||
@ -487,6 +548,15 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
control_queued = true;
|
||||
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[2] = (baudrate >> 16) & 0xff;
|
||||
setupdata[3] = (baudrate >> 24) & 0xff;
|
||||
setupdata[4] = 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[6] = 8; // Data bits (5, 6, 7, 8 or 16)
|
||||
setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
|
||||
setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
|
||||
setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16)
|
||||
print("PL2303: Set baud/control: ", baudrate, HEX);
|
||||
print(" = ");
|
||||
print_hexbytes(&setupdata, 7);
|
||||
@ -639,20 +709,258 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
print("PL2303: Returned configuration data: ");
|
||||
print_hexbytes(setupdata, 7);
|
||||
|
||||
// This sets the control lines (0x1=DTR, 0x2=RTS)
|
||||
println("PL2303: 0x21, 0x22, 0x3");
|
||||
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
if (pending_control & 0x30) {
|
||||
pending_control &= ~0x30;
|
||||
if (pending_control & 0x20) {
|
||||
pending_control &= ~0x20;
|
||||
println("PL2303: 0x21, 0x22, 0x3");
|
||||
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
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);
|
||||
|
||||
debugDigitalToggle(6);
|
||||
// first update rxstate bitmask, since buffer is no longer queued
|
||||
if (transfer->buffer == rx1) {
|
||||
rxstate &= 0xFE;
|
||||
@ -694,6 +1003,11 @@ void USBSerial::rx_data(const Transfer_t *transfer)
|
||||
}
|
||||
}
|
||||
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_hexbytes(p, len);
|
||||
}
|
||||
@ -760,6 +1074,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
|
||||
{
|
||||
uint32_t mask;
|
||||
uint8_t *p = (uint8_t *)transfer->buffer;
|
||||
debugDigitalWrite(5, HIGH);
|
||||
if (p == tx1) {
|
||||
println("tx1:");
|
||||
mask = 1;
|
||||
@ -769,6 +1084,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
|
||||
mask = 2;
|
||||
//txstate &= 0xFD;
|
||||
} else {
|
||||
debugDigitalWrite(5, LOW);
|
||||
return; // should never happen
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
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
|
||||
txstate &= ~mask;
|
||||
txstate &= ~(mask | 4); // turn off that transfer and make sure the flush bit is not set
|
||||
debugDigitalWrite(5, LOW);
|
||||
return;
|
||||
}
|
||||
// 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!!!!");
|
||||
if (++tail >= txsize) tail = 0;
|
||||
uint32_t n = txsize - tail;
|
||||
if (n > packetsize) n = packetsize;
|
||||
if (n > count) n = count;
|
||||
memcpy(p, txbuf + tail, n);
|
||||
if (n >= packetsize) {
|
||||
if (n >= count) {
|
||||
tail += n - 1;
|
||||
if (tail >= txsize) tail = 0;
|
||||
} else {
|
||||
uint32_t len = packetsize - n;
|
||||
uint32_t len = count - n;
|
||||
memcpy(p + n, txbuf, len);
|
||||
tail = len - 1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
debugDigitalWrite(7, HIGH);
|
||||
println("txtimer");
|
||||
uint32_t count;
|
||||
uint32_t head = txhead;
|
||||
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) {
|
||||
println(" *** Empty ***");
|
||||
debugDigitalWrite(7, LOW);
|
||||
return; // nothing to transmit
|
||||
} else if (head > tail) {
|
||||
count = head - tail;
|
||||
} else {
|
||||
count = txsize + head - tail;
|
||||
}
|
||||
|
||||
uint8_t *p;
|
||||
if ((txstate & 0x01) == 0) {
|
||||
p = tx1;
|
||||
@ -833,10 +1171,20 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
|
||||
p = tx2;
|
||||
txstate |= 0x02;
|
||||
} else {
|
||||
txtimer.start(1200);
|
||||
txstate |= 4; // Tell the TX code to do flush code.
|
||||
println(" *** No buffers ***");
|
||||
debugDigitalWrite(7, LOW);
|
||||
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;
|
||||
uint32_t n = txsize - tail;
|
||||
if (n > count) n = count;
|
||||
@ -854,6 +1202,7 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
|
||||
print(") ");
|
||||
print_hexbytes(p, count);
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
@ -975,14 +1351,16 @@ size_t USBSerial::write(uint8_t c)
|
||||
}
|
||||
txtail = tail;
|
||||
//println("queue tx packet, newtail=", tail);
|
||||
debugDigitalWrite(7, HIGH);
|
||||
queue_Data_Transfer(txpipe, p, packetsize, this);
|
||||
debugDigitalWrite(7, LOW);
|
||||
NVIC_ENABLE_IRQ(IRQ_USBHS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// otherwise, set a latency timer to later transmit partial packet
|
||||
txtimer.stop();
|
||||
txtimer.start(3500);
|
||||
txtimer.start(write_timeout_);
|
||||
NVIC_ENABLE_IRQ(IRQ_USBHS);
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user