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

Merge pull request #13 from KurtE/XBOX1-Keyboard

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

View File

@ -56,7 +56,7 @@
// your best effort to read chapter 4 before asking USB questions!
//#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

View File

@ -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");
}

View File

@ -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
View File

View 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
}
}

View File

67
hid.cpp
View File

@ -128,21 +128,19 @@ bool USBHIDParser::claim(Device_t *dev, int type, const uint8_t *descriptors, ui
if (((endpoint1 & 0xF0) == 0x80) && ((endpoint2 & 0xF0) == 0)) {
// 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;

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -1,123 +0,0 @@
/* USB keyboard power Host for Teensy 3.6
* Copyright 2017 Paul Stoffregen (paul@pjrc.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#define TOPUSAGE_SYS_CONTROL 0x10080
#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001
bool KeyboardHIDExtrasController::claim_collection(Device_t *dev, uint32_t topusage)
{
// Lets try to claim a few specific Keyboard related collection/reports
//Serial.printf("KBH Claim %x\n", topusage);
if ((topusage != TOPUSAGE_SYS_CONTROL)
&& (topusage != TOPUSAGE_CONSUMER_CONTROL)
) return false;
// only claim from one physical device
//Serial.println("KeyboardHIDExtrasController claim collection");
if (mydevice != NULL && dev != mydevice) return false;
mydevice = dev;
collections_claimed_++;
return true;
}
void KeyboardHIDExtrasController::disconnect_collection(Device_t *dev)
{
if (--collections_claimed_ == 0) {
mydevice = NULL;
}
}
void KeyboardHIDExtrasController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
{
//Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax);
topusage_ = topusage; // remember which report we are processing.
hid_input_begin_ = true;
hid_input_data_ = false;
}
void KeyboardHIDExtrasController::hid_input_data(uint32_t usage, int32_t value)
{
// Hack ignore 0xff00 high words as these are user values...
if ((usage & 0xffff0000) == 0xff000000) return;
//Serial.printf("KeyboardHIDExtrasController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);
// See if the value is in our keys_down list
usage &= 0xffff; // only keep the actual key
if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items.
// Remember if we have received any logical key up events. Some keyboard appear to send them
// others do no...
hid_input_data_ = true;
uint8_t key_index;
for (key_index = 0; key_index < count_keys_down_; key_index++) {
if (keys_down[key_index] == usage) {
if (value) return; // still down
if (keyReleasedFunction) {
keyReleasedFunction(topusage_, usage);
}
// Remove from list
count_keys_down_--;
for (;key_index < count_keys_down_; key_index++) {
keys_down[key_index] = keys_down[key_index+1];
}
return;
}
}
// Was not in list
if (!value) return; // still 0
if (keyPressedFunction) {
keyPressedFunction(topusage_, usage);
}
if (count_keys_down_ < MAX_KEYS_DOWN) {
keys_down[count_keys_down_++] = usage;
}
}
void KeyboardHIDExtrasController::hid_input_end()
{
//Serial.println("KPC:hid_input_end");
if (hid_input_begin_) {
// See if we received any data from parser if not, assume all keys released...
if (!hid_input_data_ ) {
if (keyPressedFunction) {
while (count_keys_down_) {
count_keys_down_--;
keyReleasedFunction(topusage_, keys_down[count_keys_down_]);
}
}
count_keys_down_ = 0;
}
event_ = true;
hid_input_begin_ = false;
}
}

View File

@ -8,7 +8,7 @@ MIDIDevice KEYWORD1
USBSerial KEYWORD1
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

View File

@ -26,15 +26,15 @@
bool MouseController::claim_collection(Device_t *dev, uint32_t topusage)
hidclaim_t MouseController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
// only claim Desktop/Mouse
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
View File

@ -0,0 +1,120 @@
/* USB EHCI Host for Teensy 3.6
* Copyright 2017 Paul Stoffregen (paul@pjrc.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
void RawHIDController::init()
{
USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
USBHIDParser::driver_ready_for_hid_collection(this);
}
hidclaim_t RawHIDController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
// only claim RAWHID devices currently: 16c0:0486
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("Rawhid Claim: %x:%x usage: %x\n", dev->idVendor, dev->idProduct, topusage);
#endif
if ((dev->idVendor != 0x16c0 || (dev->idProduct) != 0x486)) return CLAIM_NO;
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
if (usage_) return CLAIM_NO; // Only claim one
if (fixed_usage_ && (fixed_usage_ != topusage)) return CLAIM_NO; // See if we want specific one and if so is it this one
mydevice = dev;
collections_claimed++;
usage_ = topusage;
driver_ = driver; // remember the driver.
return CLAIM_INTERFACE; // We wa
}
void RawHIDController::disconnect_collection(Device_t *dev)
{
if (--collections_claimed == 0) {
mydevice = NULL;
usage_ = 0;
}
}
bool RawHIDController::hid_process_in_data(const Transfer_t *transfer)
{
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHIDController::hid_process_in_data: %x\n", usage_);
#endif
if (receiveCB) {
return (*receiveCB)(usage_, (const uint8_t *)transfer->buffer, transfer->length);
}
return true;
}
bool RawHIDController::hid_process_out_data(const Transfer_t *transfer)
{
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHIDController::hid_process_out_data: %x\n", usage_);
#endif
return true;
}
bool RawHIDController::sendPacket(const uint8_t *buffer)
{
if (!driver_) return false;
return driver_->sendPacket(buffer);
}
void RawHIDController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
{
// These should not be called as we are claiming the whole interface and not
// allowing the parse to happen
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHID::hid_input_begin %x %x %x %x\n", topusage, type, lgmin, lgmax);
#endif
//hid_input_begin_ = true;
}
void RawHIDController::hid_input_data(uint32_t usage, int32_t value)
{
// These should not be called as we are claiming the whole interface and not
// allowing the parse to happen
#ifdef USBHOST_PRINT_DEBUG
Serial.printf("RawHID: usage=%X, value=%d", usage, value);
if ((value >= ' ') && (value <='~')) Serial.printf("(%c)", value);
Serial.println();
#endif
}
void RawHIDController::hid_input_end()
{
// These should not be called as we are claiming the whole interface and not
// allowing the parse to happen
#ifdef USBHOST_PRINT_DEBUG
Serial.println("RawHID::hid_input_end");
#endif
// if (hid_input_begin_) {
// hid_input_begin_ = false;
// }
}

View File

@ -19,6 +19,8 @@
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* 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;
}