Browse Source

reorg files into include & src dirs

main
John Robinson 3 years ago
parent
commit
2c1a6fe531
No known key found for this signature in database
24 changed files with 597 additions and 710 deletions
  1. +0
    -0
      include/usbhost/antplusdefs.h
  2. +0
    -0
      include/usbhost/usbhost.h
  3. +0
    -0
      include/usbhost/utility/imxrt_usbhs.h
  4. +0
    -0
      include/usbhost/utility/msc.h
  5. +0
    -113
      keywords.txt
  6. +12
    -12
      src/MassStorageDriver.cpp
  7. +12
    -12
      src/SerEMU.cpp
  8. +85
    -85
      src/adk.cpp
  9. +4
    -4
      src/antplus.cpp
  10. +142
    -142
      src/bluetooth.cpp
  11. +4
    -4
      src/digitizer.cpp
  12. +2
    -2
      src/ehci.cpp
  13. +7
    -7
      src/enumeration.cpp
  14. +14
    -14
      src/hid.cpp
  15. +2
    -2
      src/hub.cpp
  16. +124
    -124
      src/joystick.cpp
  17. +49
    -49
      src/keyboard.cpp
  18. +0
    -0
      src/keyboardHIDExtras.cpp
  19. +4
    -4
      src/memory.cpp
  20. +2
    -2
      src/midi.cpp
  21. +12
    -12
      src/mouse.cpp
  22. +2
    -2
      src/print.cpp
  23. +7
    -7
      src/rawhid.cpp
  24. +113
    -113
      src/serial.cpp

antplusdefs.h → include/usbhost/antplusdefs.h View File


USBHost_t36.h → include/usbhost/usbhost.h View File


utility/imxrt_usbhs.h → include/usbhost/utility/imxrt_usbhs.h View File


utility/msc.h → include/usbhost/utility/msc.h View File


+ 0
- 113
keywords.txt View File

# Objects
USBHost KEYWORD1
USBHub KEYWORD1
USBHIDParser KEYWORD1
KeyboardController KEYWORD1
MouseController KEYWORD1
DigitizerController KEYWORD1
MIDIDevice KEYWORD1
MIDIDevice_BigBuffer KEYWORD1
USBSerial KEYWORD1
USBSerial_BigBuffer KEYWORD1
USBSerialEmu KEYWORD1
USBSerialBase KEYWORD1
AntPlus KEYWORD1
JoystickController KEYWORD1
RawHIDController KEYWORD1
BluetoothController KEYWORD1
# Common Functions
Task KEYWORD2
idVendor KEYWORD2
idProduct KEYWORD2
manufacturer KEYWORD2
product KEYWORD2
serialNumber KEYWORD2

# KeyboardController
getKey KEYWORD2
getModifiers KEYWORD2
getOemKey KEYWORD2
attachPress KEYWORD2
attachRelease KEYWORD2
attachExtrasPress KEYWORD2
attachExtrasRelease KEYWORD2
LEDS KEYWORD2
updateLEDS KEYWORD2
numLock KEYWORD2
capsLock KEYWORD2
scrollLock KEYWORD2
forceBootProtocol KEYWORD2

# MIDIDevice
getType KEYWORD2
getChannel KEYWORD2
getData1 KEYWORD2
getData2 KEYWORD2
setHandleNoteOff KEYWORD2
setHandleNoteOn KEYWORD2
setHandleVelocityChange KEYWORD2
setHandleControlChange KEYWORD2
setHandleProgramChange KEYWORD2
setHandleAfterTouch KEYWORD2
setHandlePitchChange KEYWORD2
setHandleSysEx KEYWORD2
setHandleRealTimeSystem KEYWORD2
setHandleTimeCodeQuarterFrame KEYWORD2
sendNoteOff KEYWORD2
sendNoteOn KEYWORD2
sendPolyPressure KEYWORD2
sendControlChange KEYWORD2
sendProgramChange KEYWORD2
sendAfterTouch KEYWORD2
sendPitchBend KEYWORD2
sendSysEx KEYWORD2
sendRealTime KEYWORD2
sendTimeCodeQuarterFrame KEYWORD2
sendTimeCodeQuarterFrame KEYWORD2
SYSEX_MAX_LEN LITERAL1 KEYWORD2

# AntPlus
onStatusChange KEYWORD2
onDeviceID KEYWORD2
onHeartRateMonitor KEYWORD2
onSpeedCadence KEYWORD2
onSpeed KEYWORD2
onCadence KEYWORD2
setWheelCircumference KEYWORD2

# MouseController
mouseDataClear KEYWORD2
getButtons KEYWORD2
getMouseX KEYWORD2
getMouseY KEYWORD2
getWheel KEYWORD2
getWheelH KEYWORD2

# JoystickController
joystickDataClear KEYWORD2
getAxis KEYWORD2
axisMask KEYWORD2
axisChangedMask KEYWORD2
axisChangeNotifyMask KEYWORD2
userAxisMask KEYWORD2
setRumbleOn KEYWORD2
setLEDs KEYWORD2
joystickType KEYWORD2
PS3 LITERAL1
PS3_MOTION LITERAL1
PS4 LITERAL1
XBOXONE LITERAL1
XBOX360 LITERAL1
SWITCH LITERAL1
# 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

MassStorageDriver.cpp → src/MassStorageDriver.cpp View File



//MassStorageDriver.cpp //MassStorageDriver.cpp


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_
// only claim at interface level // only claim at interface level


if (type != 1) return false; if (type != 1) return false;
if (len < 9+7+7) return false; // Interface descriptor + 2 endpoint decriptors
if (len < 9+7+7) return false; // Interface descriptor + 2 endpoint decriptors


print_hexbytes(descriptors, len); print_hexbytes(descriptors, len);


uint32_t numendpoint = descriptors[4]; uint32_t numendpoint = descriptors[4];
if (numendpoint < 1) return false;
if (numendpoint < 1) return false;
if (descriptors[5] != 8) return false; // bInterfaceClass, 8 = MASS Storage class if (descriptors[5] != 8) return false; // bInterfaceClass, 8 = MASS Storage class
if (descriptors[6] != 6) return false; // bInterfaceSubClass, 6 = SCSI transparent command set (SCSI Standards) if (descriptors[6] != 6) return false; // bInterfaceSubClass, 6 = SCSI transparent command set (SCSI Standards)
if (descriptors[7] != 80) return false; // bInterfaceProtocol, 80 = BULK-ONLY TRANSPORT if (descriptors[7] != 80) return false; // bInterfaceProtocol, 80 = BULK-ONLY TRANSPORT


uint32_t sizeOut = descriptors[out_index+4] | (descriptors[out_index+5] << 8); uint32_t sizeOut = descriptors[out_index+4] | (descriptors[out_index+5] << 8);
println("packet size out (msController) = ", sizeOut); println("packet size out (msController) = ", sizeOut);
packetSizeIn = sizeIn;
packetSizeOut = sizeOut;
packetSizeIn = sizeIn;
packetSizeOut = sizeOut;


uint32_t intervalIn = descriptors[in_index+6]; uint32_t intervalIn = descriptors[in_index+6];
uint32_t intervalOut = descriptors[out_index+6]; uint32_t intervalOut = descriptors[out_index+6];
println(msDriveInfo.connected); println(msDriveInfo.connected);
print(" initialized = "); print(" initialized = ");
println(msDriveInfo.initialized); println(msDriveInfo.initialized);
#endif
#endif
return true; return true;
} }


} }
yield(); yield();
} while(!available()); } while(!available());
msReset(); msReset();
// delay(500); // Not needed any more. // delay(500); // Not needed any more.
maxLUN = msGetMaxLun(); maxLUN = msGetMaxLun();
msResult = WaitMediaReady(); msResult = WaitMediaReady();
if(msResult) if(msResult)
return msResult; return msResult;
// Retrieve drive information. // Retrieve drive information.
msDriveInfo.initialized = true; msDriveInfo.initialized = true;
msDriveInfo.hubNumber = getHubNumber(); // Which HUB. msDriveInfo.hubNumber = getHubNumber(); // Which HUB.
mscTransferComplete = false; mscTransferComplete = false;
#ifdef DBGprint #ifdef DBGprint
println("msDoCommand()"); println("msDoCommand()");
#endif
#endif
if(CBWTag == 0xFFFFFFFF) CBWTag = 1; if(CBWTag == 0xFFFFFFFF) CBWTag = 1;
queue_Data_Transfer(datapipeOut, CBW, sizeof(msCommandBlockWrapper_t), this); // Command stage. queue_Data_Transfer(datapipeOut, CBW, sizeof(msCommandBlockWrapper_t), this); // Command stage.
while(!msOutCompleted) yield(); while(!msOutCompleted) yield();
} }
CSWResult = msGetCSW(); // Status stage. CSWResult = msGetCSW(); // Status stage.
// All stages of this transfer have completed. // All stages of this transfer have completed.
//Check for special cases.
//Check for special cases.
//If test for unit ready command is given then //If test for unit ready command is given then
// return the CSW status byte. // return the CSW status byte.
//Bit 0 == 1 == not ready else //Bit 0 == 1 == not ready else
uint8_t BlockLo = Blocks & 0xFF; uint8_t BlockLo = Blocks & 0xFF;
msCommandBlockWrapper_t CommandBlockWrapper = (msCommandBlockWrapper_t) msCommandBlockWrapper_t CommandBlockWrapper = (msCommandBlockWrapper_t)
{ {
.Signature = CBW_SIGNATURE, .Signature = CBW_SIGNATURE,
.Tag = ++CBWTag, .Tag = ++CBWTag,
.TransferLength = (uint32_t)(Blocks * BlockSize), .TransferLength = (uint32_t)(Blocks * BlockSize),

SerEMU.cpp → src/SerEMU.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


//#define SEREMU_PRINT_DEBUG //#define SEREMU_PRINT_DEBUG


void USBSerialEmu::init() void USBSerialEmu::init()
{ {
USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
USBHIDParser::driver_ready_for_hid_collection(this);
USBHIDParser::driver_ready_for_hid_collection(this);
} }


hidclaim_t USBSerialEmu::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage) hidclaim_t USBSerialEmu::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
mydevice = dev; mydevice = dev;
collections_claimed++; collections_claimed++;
usage_ = topusage; usage_ = topusage;
driver_ = driver; // remember the driver.
driver_ = driver; // remember the driver.
rx_head_ = 0;// receive head rx_head_ = 0;// receive head
rx_tail_ = 0;// receive tail rx_tail_ = 0;// receive tail
tx_head_ = 0; tx_head_ = 0;
} }
} }


bool USBSerialEmu::hid_process_in_data(const Transfer_t *transfer)
bool USBSerialEmu::hid_process_in_data(const Transfer_t *transfer)
{ {
uint16_t len = transfer->length; uint16_t len = transfer->length;
const uint8_t *buffer = (const uint8_t *)transfer->buffer; const uint8_t *buffer = (const uint8_t *)transfer->buffer;
while ((buffer_end > buffer) && (*buffer_end == 0))buffer_end--; while ((buffer_end > buffer) && (*buffer_end == 0))buffer_end--;
// lets trim off the trailing null characters. // lets trim off the trailing null characters.


// Now lets move the bytes onto our queue.
// Now lets move the bytes onto our queue.
uint16_t tail = rx_tail_; uint16_t tail = rx_tail_;
while (buffer <= buffer_end) { while (buffer <= buffer_end) {
uint16_t new_head = rx_head_ + 1; uint16_t new_head = rx_head_ + 1;
if (new_head == RX_BUFFER_SIZE) new_head = 0; if (new_head == RX_BUFFER_SIZE) new_head = 0;
if (new_head == tail) break; // we don't have room so bail out.
if (new_head == tail) break; // we don't have room so bail out.
rx_buffer_[rx_head_] = *buffer++; rx_buffer_[rx_head_] = *buffer++;
rx_head_ = new_head; // point off to the new next head. rx_head_ = new_head; // point off to the new next head.
} }
return true; return true;
} }


bool USBSerialEmu::hid_process_out_data(const Transfer_t *transfer)
bool USBSerialEmu::hid_process_out_data(const Transfer_t *transfer)
{ {
#ifdef SEREMU_PRINT_DEBUG #ifdef SEREMU_PRINT_DEBUG
USBHDBGSerial.printf("USBSerialEmu::hid_process_out_data: %x\n", usage_); USBHDBGSerial.printf("USBSerialEmu::hid_process_out_data: %x\n", usage_);
return true; return true;
} }


bool USBSerialEmu::sendPacket()
bool USBSerialEmu::sendPacket()
{ {
USBHDBGSerial.printf("SEMU: SendPacket\n"); USBHDBGSerial.printf("SEMU: SendPacket\n");




size_t USBSerialEmu::write(uint8_t c) size_t USBSerialEmu::write(uint8_t c)
{ {
// Single buffer, as our HID device has double buffers.
// Single buffer, as our HID device has double buffers.
if (c >= ' ') USBHDBGSerial.printf("SEMU: %c\n", c); if (c >= ' ') USBHDBGSerial.printf("SEMU: %c\n", c);
else USBHDBGSerial.printf("SEMU: 0x%x\n", c); else USBHDBGSerial.printf("SEMU: 0x%x\n", c);


if (!driver_) return 0; if (!driver_) return 0;


if (tx_head_ == tx_pipe_size_) { if (tx_head_ == tx_pipe_size_) {
while (!sendPacket()) yield(); // wait until the device above queues this packet
while (!sendPacket()) yield(); // wait until the device above queues this packet
} }
tx_buffer_[tx_head_++] = c; tx_buffer_[tx_head_++] = c;


return 1; return 1;
} }


void USBSerialEmu::flush(void)
void USBSerialEmu::flush(void)
{ {
if (!driver_) return; if (!driver_) return;



adk.cpp → src/adk.cpp View File

* *
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_
#define ADK_PID 0x2D00 #define ADK_PID 0x2D00
#define ADB_PID 0x2D01 #define ADB_PID 0x2D01
#define USB_SETUP_DEVICE_TO_HOST 0x80 #define USB_SETUP_DEVICE_TO_HOST 0x80
#define USB_SETUP_HOST_TO_DEVICE 0x00
#define USB_SETUP_TYPE_VENDOR 0x40
#define USB_SETUP_RECIPIENT_DEVICE 0x00
#define USB_SETUP_HOST_TO_DEVICE 0x00
#define USB_SETUP_TYPE_VENDOR 0x40
#define USB_SETUP_RECIPIENT_DEVICE 0x00
#define UHS_ADK_bmREQ_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE #define UHS_ADK_bmREQ_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define UHS_ADK_bmREQ_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE #define UHS_ADK_bmREQ_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define UHS_ADK_GETPROTO 51 // check USB accessory protocol version #define UHS_ADK_GETPROTO 51 // check USB accessory protocol version
{ {
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
rx_head = 0; rx_head = 0;
rx_tail = 0; rx_tail = 0;
driver_ready_for_device(this); driver_ready_for_device(this);
state = 0; state = 0;
} }


bool ADK::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) bool ADK::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{ {
// only claim at interface level // only claim at interface level
if (type != 1)
if (type != 1)
return false; return false;
// Check for ADK or ADB PIDs // Check for ADK or ADB PIDs
if (dev->idVendor == ADK_VID && (dev->idProduct == ADK_PID || dev->idProduct == ADB_PID)) if (dev->idVendor == ADK_VID && (dev->idProduct == ADK_PID || dev->idProduct == ADB_PID))
{
{
const uint8_t *p = descriptors; const uint8_t *p = descriptors;
const uint8_t *end = p + len; const uint8_t *end = p + len;


// Interface descriptor // Interface descriptor
if (p[0] != 9 || p[1] != 4)
return false;
if (p[0] != 9 || p[1] != 4)
return false;


// bInterfaceClass: 255 Vendor Specific // bInterfaceClass: 255 Vendor Specific
if (p[5] != 255)
if (p[5] != 255)
{ {
return false;
return false;
} }
// bInterfaceSubClass: 255 // bInterfaceSubClass: 255
if (p[6] != 255)
if (p[6] != 255)
{ {
return false; return false;
} }
println("ADK claim this=", (uint32_t)this, HEX); println("ADK claim this=", (uint32_t)this, HEX);
print("vid=", dev->idVendor, HEX); print("vid=", dev->idVendor, HEX);
print(", pid=", dev->idProduct, HEX); print(", pid=", dev->idProduct, HEX);
println(" bInterfaceClass=", p[5]); println(" bInterfaceClass=", p[5]);
println(" bInterfaceSubClass=", p[6]); println(" bInterfaceSubClass=", p[6]);
print_hexbytes(descriptors, len); print_hexbytes(descriptors, len);
p += 9; p += 9;
rx_ep = 0; rx_ep = 0;
tx_ep = 0; tx_ep = 0;


while (p < end)
while (p < end)
{ {
len = *p; len = *p;
if (len < 4)
if (len < 4)
return false; // all desc are at least 4 bytes return false; // all desc are at least 4 bytes
if (p + len > end)
if (p + len > end)
return false; // reject if beyond end of data return false; // reject if beyond end of data
uint32_t type = p[1]; uint32_t type = p[1];
if (type == 5)
if (type == 5)
{ {
// endpoint descriptor // endpoint descriptor
if (p[0] < 7)
if (p[0] < 7)
return false; // at least 7 bytes return false; // at least 7 bytes
if (p[3] != 2)
if (p[3] != 2)
return false; // must be bulk type return false; // must be bulk type
println(" Endpoint: ", p[2], HEX); println(" Endpoint: ", p[2], HEX);
switch (p[2] & 0xF0)
switch (p[2] & 0xF0)
{ {
case 0x80: case 0x80:
// IN endpoint // IN endpoint
if (rx_ep == 0)
if (rx_ep == 0)
{ {
rx_ep = p[2] & 0x0F; rx_ep = p[2] & 0x0F;
rx_size = p[4] | (p[5] << 8); rx_size = p[4] | (p[5] << 8);
break; break;
case 0x00: case 0x00:
// OUT endpoint // OUT endpoint
if (tx_ep == 0)
if (tx_ep == 0)
{ {
tx_ep = p[2]; tx_ep = p[2];
tx_size = p[4] | (p[5] << 8); tx_size = p[4] | (p[5] << 8);
return false; return false;
} }
} }
// ADK uses the first two endpoints for communication // ADK uses the first two endpoints for communication
if (rx_ep && tx_ep) if (rx_ep && tx_ep)
{ {
} }
p += len; p += len;
} }
// if an IN endpoint was found, create its pipe // if an IN endpoint was found, create its pipe
if (rx_ep && rx_size <= MAX_PACKET_SIZE)
if (rx_ep && rx_size <= MAX_PACKET_SIZE)
{ {
rxpipe = new_Pipe(dev, 2, rx_ep, 1, rx_size); rxpipe = new_Pipe(dev, 2, rx_ep, 1, rx_size);
if (rxpipe)
if (rxpipe)
{ {
rxpipe->callback_function = rx_callback; rxpipe->callback_function = rx_callback;
queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this); queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this);
rx_packet_queued = true; rx_packet_queued = true;
println("Done creating RX pipe"); println("Done creating RX pipe");
} }
}
else
}
else
{ {
rxpipe = NULL; rxpipe = NULL;
} }
// if an OUT endpoint was found, create its pipe // if an OUT endpoint was found, create its pipe
if (tx_ep && tx_size <= MAX_PACKET_SIZE)
if (tx_ep && tx_size <= MAX_PACKET_SIZE)
{ {
txpipe = new_Pipe(dev, 2, tx_ep, 0, tx_size); txpipe = new_Pipe(dev, 2, tx_ep, 0, tx_size);
if (txpipe)
if (txpipe)
{ {
txpipe->callback_function = tx_callback; txpipe->callback_function = tx_callback;
println("Done creating TX pipe"); println("Done creating TX pipe");
} }
}
else
}
else
{ {
txpipe = NULL; txpipe = NULL;
} }
rx_head = 0; rx_head = 0;
rx_tail = 0; rx_tail = 0;


// claim if either pipe created // claim if either pipe created
bool created = (rxpipe || txpipe); bool created = (rxpipe || txpipe);
if (created) if (created)
{ {
println("Done with init."); println("Done with init.");
state = 8; state = 8;
} }
return created; return created;
} }
else else
{ {
state = 0; state = 0;
println("Not in accessory mode."); println("Not in accessory mode.");
// Kick off switch to Accessory Mode // Kick off switch to Accessory Mode
mk_setup(adksetup, UHS_ADK_bmREQ_GET, UHS_ADK_GETPROTO, 0, 0, 2); mk_setup(adksetup, UHS_ADK_bmREQ_GET, UHS_ADK_GETPROTO, 0, 0, 2);
queue_Control_Transfer(dev, &adksetup, adkbuf, this); queue_Control_Transfer(dev, &adksetup, adkbuf, this);
return true; return true;
} }
return false; return false;
} }
void ADK::sendStr(Device_t *dev, uint8_t index, char *str) void ADK::sendStr(Device_t *dev, uint8_t index, char *str)
{
{
strcpy((char *)adkbuf, str); strcpy((char *)adkbuf, str);
mk_setup(adksetup, UHS_ADK_bmREQ_SEND, UHS_ADK_SENDSTR, 0, index, strlen(str)); mk_setup(adksetup, UHS_ADK_bmREQ_SEND, UHS_ADK_SENDSTR, 0, index, strlen(str));
queue_Control_Transfer(dev, &adksetup, adkbuf, this); queue_Control_Transfer(dev, &adksetup, adkbuf, this);
void ADK::control(const Transfer_t *transfer) void ADK::control(const Transfer_t *transfer)
{ {
println("Control callback state=",state); println("Control callback state=",state);
switch (state) switch (state)
{ {
case 0: case 0:
void ADK::rx_data(const Transfer_t *transfer) void ADK::rx_data(const Transfer_t *transfer)
{ {
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
println("ADK Receive rx_data"); println("ADK Receive rx_data");
print("Len: "); print("Len: ");
print(len); print(len);
print(" Data: "); print(" Data: ");
print_hexbytes(transfer->buffer, len); print_hexbytes(transfer->buffer, len);
uint32_t head = rx_head; uint32_t head = rx_head;
uint8_t *p = (uint8_t *)transfer->buffer; uint8_t *p = (uint8_t *)transfer->buffer;
if (p != NULL && len != 0) if (p != NULL && len != 0)
{ {
do
do
{ {
if (++head >= RX_QUEUE_SIZE)
if (++head >= RX_QUEUE_SIZE)
head = 0; head = 0;
rx_queue[head] = *p++; rx_queue[head] = *p++;
} while (--len); } while (--len);
} }
rx_head = head; rx_head = head;
rx_packet_queued = false; rx_packet_queued = false;
rx_queue_packets(rx_head, rx_tail); rx_queue_packets(rx_head, rx_tail);
} }
{ {
if (rx_packet_queued) if (rx_packet_queued)
return; return;
uint32_t avail = (head < tail) ? tail - head - 1 : RX_QUEUE_SIZE - 1 - head + tail; uint32_t avail = (head < tail) ? tail - head - 1 : RX_QUEUE_SIZE - 1 - head + tail;
println("rx_size = ", rx_size); println("rx_size = ", rx_size);
println("avail = ", avail); println("avail = ", avail);
if (avail >= rx_size)
if (avail >= rx_size)
{ {
// enough space to accept another full packet // enough space to accept another full packet
println("queue another receive packet"); println("queue another receive packet");
queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this); queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this);
rx_packet_queued = true; rx_packet_queued = true;
} else { } else {


rxpipe = NULL; rxpipe = NULL;
txpipe = NULL; txpipe = NULL;
state = 0; state = 0;
} }


void ADK::begin(char *adk_manufacturer, char *adk_model, char *adk_desc, char *adk_version, char *adk_uri, char *adk_serial) void ADK::begin(char *adk_manufacturer, char *adk_model, char *adk_desc, char *adk_version, char *adk_uri, char *adk_serial)
{
{
manufacturer = adk_manufacturer; manufacturer = adk_manufacturer;
model = adk_model; model = adk_model;
desc = adk_desc; desc = adk_desc;


int ADK::available(void) int ADK::available(void)
{ {
if (!device)
if (!device)
return 0; return 0;
uint32_t head = rx_head; uint32_t head = rx_head;
uint32_t tail = rx_tail; uint32_t tail = rx_tail;
if (head >= tail)
if (head >= tail)
return head - tail; return head - tail;
return RX_QUEUE_SIZE + head - tail; return RX_QUEUE_SIZE + head - tail;
} }


int ADK::peek(void) int ADK::peek(void)
{ {
if (!device)
if (!device)
return -1; return -1;
uint32_t head = rx_head; uint32_t head = rx_head;
uint32_t tail = rx_tail; uint32_t tail = rx_tail;
if (head == tail)
if (head == tail)
return -1; return -1;
if (++tail >= RX_QUEUE_SIZE)
if (++tail >= RX_QUEUE_SIZE)
tail = 0; tail = 0;
return rx_queue[tail]; return rx_queue[tail];
} }


int ADK::read(void) int ADK::read(void)
{ {
if (!device)
if (!device)
return -1; return -1;
uint32_t head = rx_head; uint32_t head = rx_head;
uint32_t tail = rx_tail; uint32_t tail = rx_tail;
if (head == tail)
if (head == tail)
return -1; return -1;
if (++tail >= RX_QUEUE_SIZE)
if (++tail >= RX_QUEUE_SIZE)
tail = 0; tail = 0;
int c = rx_queue[tail]; int c = rx_queue[tail];
rx_tail = tail; rx_tail = tail;
rx_queue_packets(head, tail); rx_queue_packets(head, tail);
return c; return c;
} }


__disable_irq(); __disable_irq();
queue_Data_Transfer(txpipe, tx_buffer, len, this); queue_Data_Transfer(txpipe, tx_buffer, len, this);
__enable_irq(); __enable_irq();
return len; return len;
} }



antplus.cpp → src/antplus.cpp View File

// https://forum.pjrc.com/threads/43110 // https://forum.pjrc.com/threads/43110
// https://github.com/PaulStoffregen/antplus // https://github.com/PaulStoffregen/antplus


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#include "antplusdefs.h" // Ant internal defines, not for Arduino sketches
#include "usbhost/antplusdefs.h" // Ant internal defines, not for Arduino sketches


#define ANTPLUS_VID 0x0FCF #define ANTPLUS_VID 0x0FCF
#define ANTPLUS_2_PID 0x1008 #define ANTPLUS_2_PID 0x1008
#define printf(...) Serial.printf(__VA_ARGS__); Serial.write("\r\n") #define printf(...) Serial.printf(__VA_ARGS__); Serial.write("\r\n")
#else #else
#undef printf #undef printf
#define printf(...)
#define printf(...)
#endif #endif





bluetooth.cpp → src/bluetooth.cpp View File

* plus... http://affon.narod.ru/BT/bluetooth_app_c10.pdf * plus... http://affon.narod.ru/BT/bluetooth_app_c10.pdf
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_//#define DEBUG_BT #define println USBHost::println_//#define DEBUG_BT




/************************************************************/ /************************************************************/
// Define HCI Commands OGF HIgh byte OCF is low byte...
// Define HCI Commands OGF HIgh byte OCF is low byte...
// Actually shifted values... // Actually shifted values...
/************************************************************/ /************************************************************/
#define HCI_INQUIRY 0x0401 #define HCI_INQUIRY 0x0401
#define HID_CTRL_PSM 0x11 // HID_Control PSM Value #define HID_CTRL_PSM 0x11 // HID_Control PSM Value
#define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value


// Used For Connection Response
// Used For Connection Response
#define PENDING 0x01 #define PENDING 0x01
#define SUCCESSFUL 0x00 #define SUCCESSFUL 0x00


#define L2CAP_CMD_INFORMATION_REQUEST 0x0A #define L2CAP_CMD_INFORMATION_REQUEST 0x0A
#define L2CAP_CMD_INFORMATION_RESPONSE 0x0B #define L2CAP_CMD_INFORMATION_RESPONSE 0x0B


#define HID_THDR_DATA_INPUT 0xa1
#define HID_THDR_DATA_INPUT 0xa1
// HID stuff // HID stuff
#define HID_BOOT_PROTOCOL 0x00 #define HID_BOOT_PROTOCOL 0x00
#define HID_RPT_PROTOCOL 0x01 #define HID_RPT_PROTOCOL 0x01




// different modes // different modes
enum {PC_RESET = 1, PC_WRITE_CLASS_DEVICE, PC_READ_BDADDR, PC_READ_LOCAL_VERSION,
PC_SEND_WRITE_INQUIRE_MODE, PC_SEND_SET_EVENT_MASK, PC_SEND_INQUIRE,
enum {PC_RESET = 1, PC_WRITE_CLASS_DEVICE, PC_READ_BDADDR, PC_READ_LOCAL_VERSION,
PC_SEND_WRITE_INQUIRE_MODE, PC_SEND_SET_EVENT_MASK, PC_SEND_INQUIRE,
PC_INQUIRE_CANCEL=100, PC_AUTHENTICATION_REQUESTED=110, PC_LINK_KEY_NEGATIVE=120, PC_PIN_CODE_REPLY=130, PC_INQUIRE_CANCEL=100, PC_AUTHENTICATION_REQUESTED=110, PC_LINK_KEY_NEGATIVE=120, PC_PIN_CODE_REPLY=130,
PC_WRITE_SCAN_PAGE=200}; PC_WRITE_SCAN_PAGE=200};
////////////// //////////////


bool BluetoothController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) bool BluetoothController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{ {
// only claim at device level
// only claim at device level
println("BluetoothController claim this=", (uint32_t)this, HEX); println("BluetoothController claim this=", (uint32_t)this, HEX);


if (type != 0) return false; // claim at the device level if (type != 0) return false; // claim at the device level
if (len > 512) { if (len > 512) {
DBGPrintf(" Descriptor length %d only showing first 512\n "); DBGPrintf(" Descriptor length %d only showing first 512\n ");
len = 512; len = 512;
}
}
for (uint16_t i=0; i < len; i++) { for (uint16_t i=0; i < len; i++) {
DBGPrintf("%x ", descriptors[i]); DBGPrintf("%x ", descriptors[i]);
if ((i & 0x3f) == 0x3f) DBGPrintf("\n "); if ((i & 0x3f) == 0x3f) DBGPrintf("\n ");
rx_size_ = 0; rx_size_ = 0;
rx2_size_ = 0; rx2_size_ = 0;
tx_size_ = 0; tx_size_ = 0;
uint32_t descriptor_index = 9;
uint32_t descriptor_index = 9;
while (count_end_points-- /*&& ((rxep == 0) || txep == 0) */) { while (count_end_points-- /*&& ((rxep == 0) || txep == 0) */) {
if (descriptors[descriptor_index] != 7) return false; // length 7 if (descriptors[descriptor_index] != 7) return false; // length 7
if (descriptors[descriptor_index+1] != 5) return false; // ep desc if (descriptors[descriptor_index+1] != 5) return false; // ep desc
if ((descriptors[descriptor_index+4] <= 64) if ((descriptors[descriptor_index+4] <= 64)
&& (descriptors[descriptor_index+5] == 0)) { && (descriptors[descriptor_index+5] == 0)) {
// have a bulk EP size
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) { if (descriptors[descriptor_index+2] & 0x80 ) {
if (descriptors[descriptor_index+3] == 3) { // Interrupt if (descriptors[descriptor_index+3] == 3) { // Interrupt
rxep = descriptors[descriptor_index+2]; rxep = descriptors[descriptor_index+2];
rx2_interval = descriptors[descriptor_index+6]; rx2_interval = descriptors[descriptor_index+6];
} }
} else { } else {
txep = descriptors[descriptor_index+2];
txep = descriptors[descriptor_index+2];
tx_size_ = descriptors[descriptor_index+4]; tx_size_ = descriptors[descriptor_index+4];
tx_interval = descriptors[descriptor_index+6]; tx_interval = descriptors[descriptor_index+6];
} }
USBHDBGSerial.printf("Bluetooth end points not found: %d %d\n", rxep, txep); USBHDBGSerial.printf("Bluetooth end points not found: %d %d\n", rxep, txep);
return false; // did not find two end points. return false; // did not find two end points.
} }
DBGPrintf(" rxep=%d(%d) txep=%d(%d) rx2ep=%d(%d)\n", rxep&15, rx_size_, txep, tx_size_,
DBGPrintf(" rxep=%d(%d) txep=%d(%d) rx2ep=%d(%d)\n", rxep&15, rx_size_, txep, tx_size_,
rx2ep&15, rx2_size_); rx2ep&15, rx2_size_);


print("BluetoothController, rxep=", rxep & 15); print("BluetoothController, rxep=", rxep & 15);
// Send out the reset // Send out the reset
device = dev; // yes this is normally done on return from this but should not hurt if we do it here. device = dev; // yes this is normally done on return from this but should not hurt if we do it here.
sendResetHCI(); sendResetHCI();
pending_control_ = PC_RESET;
pending_control_tx_ = 0; //
pending_control_ = PC_RESET;
pending_control_tx_ = 0; //


return true; return true;
} }


void BluetoothController::timer_event(USBDriverTimer *whichTimer) void BluetoothController::timer_event(USBDriverTimer *whichTimer)
{ {
} }






// Note the logical packets returned from the device may be larger // Note the logical packets returned from the device may be larger
// than can fit in one of our packets, so we will detect this and // than can fit in one of our packets, so we will detect this and
// the next read will be continue in or rx_buf_ in the next logical
// the next read will be continue in or rx_buf_ in the next logical
// location. We will only go into process the next logical state // location. We will only go into process the next logical state
// when we have the full response read in...
// when we have the full response read in...
if (rx_packet_data_remaining == 0) { // Previous command was fully handled if (rx_packet_data_remaining == 0) { // Previous command was fully handled
rx_packet_data_remaining = rxbuf_[1] + 2; // length of data plus the two bytes at start... rx_packet_data_remaining = rxbuf_[1] + 2; // length of data plus the two bytes at start...
}
// Now see if the data
}
// Now see if the data
rx_packet_data_remaining -= len; // remove the length of this packet from length rx_packet_data_remaining -= len; // remove the length of this packet from length


if (rx_packet_data_remaining == 0) { // read started at beginning of packet so get the total length of packet if (rx_packet_data_remaining == 0) { // read started at beginning of packet so get the total length of packet
break; break;
case EV_REMOTE_NAME_COMPLETE: // 0x07 case EV_REMOTE_NAME_COMPLETE: // 0x07
handle_hci_remote_name_complete(); handle_hci_remote_name_complete();
break;
break;
case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE:
handle_hci_remote_version_information_complete(); handle_hci_remote_version_information_complete();
break; break;
handle_hci_link_key_request(); handle_hci_link_key_request();
break; break;
case EV_LINK_KEY_NOTIFICATION: // 0x18 case EV_LINK_KEY_NOTIFICATION: // 0x18
handle_hci_link_key_notification();
handle_hci_link_key_notification();
break; break;
case EV_INQUIRY_RESULTS_WITH_RSSI: case EV_INQUIRY_RESULTS_WITH_RSSI:
handle_hci_inquiry_result(true); handle_hci_inquiry_result(true);
default: default:
break; break;
} }
// Start read at start of buffer.
// Start read at start of buffer.
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this); queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
} else { } else {
// Continue the read - Todo - maybe verify len == rx_size_ // Continue the read - Todo - maybe verify len == rx_size_
queue_Data_Transfer(rxpipe_, buffer + rx_size_, rx_size_, this); queue_Data_Transfer(rxpipe_, buffer + rx_size_, rx_size_, this);
return; // Don't process the message yet as we still have data to receive.
return; // Don't process the message yet as we still have data to receive.
} }
} }


//=================================================================== //===================================================================
// Called when an HCI command completes. // Called when an HCI command completes.
void BluetoothController::handle_hci_command_complete()
void BluetoothController::handle_hci_command_complete()
{ {
uint16_t hci_command = rxbuf_[3] + (rxbuf_[4] << 8); uint16_t hci_command = rxbuf_[3] + (rxbuf_[4] << 8);
uint8_t buffer_index; uint8_t buffer_index;
if(!rxbuf_[5]) {
if(!rxbuf_[5]) {
VDBGPrintf(" Command Completed! \n"); VDBGPrintf(" Command Completed! \n");
} else { } else {
VDBGPrintf(" Command(%x) Completed - Error: %d! \n", hci_command, rxbuf_[5]); VDBGPrintf(" Command(%x) Completed - Error: %d! \n", hci_command, rxbuf_[5]);
// BUGBUG:: probably need to queue something?
// BUGBUG:: probably need to queue something?
} }


switch (hci_command) { switch (hci_command) {
break; break;
case HCI_RESET: //0x0c03 case HCI_RESET: //0x0c03
if (!rxbuf_[5]) pending_control_ = PC_WRITE_CLASS_DEVICE; if (!rxbuf_[5]) pending_control_ = PC_WRITE_CLASS_DEVICE;
// If it fails, will retry. maybe should have repeat max...
// If it fails, will retry. maybe should have repeat max...
break; break;
case HCI_Set_Event_Filter_Clear: //0x0c05 case HCI_Set_Event_Filter_Clear: //0x0c05
break; break;
case HCI_Read_Local_Name: //0x0c14 case HCI_Read_Local_Name: //0x0c14
// received name back...
// received name back...
{ {
//BUGBUG:: probably want to grab string object and copy to
//BUGBUG:: probably want to grab string object and copy to
USBHDBGSerial.printf(" Local name: %s\n", &rxbuf_[6]); USBHDBGSerial.printf(" Local name: %s\n", &rxbuf_[6]);
/* /*
uint8_t len = rxbuf_[1]+2; // Length field +2 for total bytes read uint8_t len = rxbuf_[1]+2; // Length field +2 for total bytes read
case HCI_Read_Inquiry_Response_Transmit_Power_Level: //0x0c58 case HCI_Read_Inquiry_Response_Transmit_Power_Level: //0x0c58
break; break;
case HCI_Read_Local_Supported_Features: //0x1003 case HCI_Read_Local_Supported_Features: //0x1003
// Remember the features supported by local...
// Remember the features supported by local...
for (buffer_index = 0; buffer_index < 8; buffer_index++) { for (buffer_index = 0; buffer_index < 8; buffer_index++) {
features[buffer_index] = rxbuf_[buffer_index+6]; features[buffer_index] = rxbuf_[buffer_index+6];
} }
} }
break; break;
case HCI_Read_Local_Version_Information: //0x1001 case HCI_Read_Local_Version_Information: //0x1001
hciVersion = rxbuf_[6]; // Should do error checking above...
hciVersion = rxbuf_[6]; // Should do error checking above...
DBGPrintf(" Local Version: %x\n", hciVersion); DBGPrintf(" Local Version: %x\n", hciVersion);
pending_control_ = (do_pair_device_)? PC_SEND_WRITE_INQUIRE_MODE : PC_WRITE_SCAN_PAGE; pending_control_ = (do_pair_device_)? PC_SEND_WRITE_INQUIRE_MODE : PC_WRITE_SCAN_PAGE;
break; break;
case HCI_WRITE_SCAN_ENABLE: //0x0c1a case HCI_WRITE_SCAN_ENABLE: //0x0c1a
DBGPrintf("Write_Scan_enable Completed\n"); DBGPrintf("Write_Scan_enable Completed\n");
// See if we have driver and a remote // See if we have driver and a remote
if (connections_[current_connection_].device_driver_ && connections_[current_connection_].connection_complete_) { // We have a driver call their
if (connections_[current_connection_].device_driver_ && connections_[current_connection_].connection_complete_) { // We have a driver call their
connections_[current_connection_].device_driver_->connectionComplete(); connections_[current_connection_].device_driver_->connectionComplete();
connections_[current_connection_].connection_complete_ = false; // only call once connections_[current_connection_].connection_complete_ = false; // only call once
} }
void BluetoothController::queue_next_hci_command() void BluetoothController::queue_next_hci_command()
{ {
// Ok We completed a command now see if we need to queue another command // Ok We completed a command now see if we need to queue another command
// Still probably need to reorganize...
// Still probably need to reorganize...
switch (pending_control_) { switch (pending_control_) {
// Initial setup states.
case PC_RESET:
// Initial setup states.
case PC_RESET:
sendResetHCI(); sendResetHCI();
break; break;
case PC_WRITE_CLASS_DEVICE: case PC_WRITE_CLASS_DEVICE:
//pending_control_++; //pending_control_++;
break; break;


// These are used when we are pairing.
// These are used when we are pairing.
case PC_SEND_WRITE_INQUIRE_MODE: case PC_SEND_WRITE_INQUIRE_MODE:
sendHCIHCIWriteInquiryMode(2); // lets set into extended inquire mode sendHCIHCIWriteInquiryMode(2); // lets set into extended inquire mode
pending_control_++; pending_control_++;
sendHCI_INQUIRY(); sendHCI_INQUIRY();
pending_control_++; pending_control_++;
break; break;
case PC_INQUIRE_CANCEL:
case PC_INQUIRE_CANCEL:
// lets try to create a connection... // lets try to create a connection...
sendHCICreateConnection(); sendHCICreateConnection();
pending_control_++; pending_control_++;
break; break;
case PC_AUTHENTICATION_REQUESTED:
case PC_AUTHENTICATION_REQUESTED:
break; break;
case PC_LINK_KEY_NEGATIVE: case PC_LINK_KEY_NEGATIVE:
break; break;
// None Pair mode // None Pair mode
case PC_WRITE_SCAN_PAGE: case PC_WRITE_SCAN_PAGE:
sendHCIWriteScanEnable(2); sendHCIWriteScanEnable(2);
pending_control_ = 0; //
pending_control_ = 0; //
break; break;
default:
default:
break; break;
} }


} }




void BluetoothController::handle_hci_command_status()
void BluetoothController::handle_hci_command_status()
{ {
// <event type><param count><status><num packets allowed to be sent><CMD><CMD> // <event type><param count><status><num packets allowed to be sent><CMD><CMD>
uint16_t hci_command = rxbuf_[4] + (rxbuf_[5] << 8); uint16_t hci_command = rxbuf_[4] + (rxbuf_[5] << 8);
default: DBGPrintf("???\n"); break; default: DBGPrintf("???\n"); break;
} }
#endif #endif
// lets try recovering from some errors...
// lets try recovering from some errors...
switch (hci_command) { switch (hci_command) {
case HCI_OP_ACCEPT_CONN_REQ: case HCI_OP_ACCEPT_CONN_REQ:
// We assume that the connection failed... // We assume that the connection failed...
} }
} }


void BluetoothController::handle_hci_inquiry_result(bool fRSSI)
void BluetoothController::handle_hci_inquiry_result(bool fRSSI)
{ {
// result - versus result with RSSI // result - versus result with RSSI
// | Diverge here...
// 2 f 1 79 22 23 a c5 cc 1 2 0 40 25 0 3b 2
// | Diverge here...
// 2 f 1 79 22 23 a c5 cc 1 2 0 40 25 0 3b 2
// 22 f 1 79 22 23 a c5 cc 1 2 40 25 0 3e 31 d2 // 22 f 1 79 22 23 a c5 cc 1 2 40 25 0 3e 31 d2


// Wondered if multiple items if all of the BDADDR are first then next field... // Wondered if multiple items if all of the BDADDR are first then next field...
// Handle the differences in offsets here... // Handle the differences in offsets here...
index_class = 3 + (8*rxbuf_[2]) + i; index_class = 3 + (8*rxbuf_[2]) + i;
index_clock_offset = 3 + (11*rxbuf_[2]) + i; index_clock_offset = 3 + (11*rxbuf_[2]) + i;
}
}
uint32_t bluetooth_class = rxbuf_[index_class] + ((uint32_t)rxbuf_[index_class+1] << 8) + ((uint32_t)rxbuf_[index_class+2] << 16); uint32_t bluetooth_class = rxbuf_[index_class] + ((uint32_t)rxbuf_[index_class+1] << 8) + ((uint32_t)rxbuf_[index_class+2] << 16);
DBGPrintf(" BD:%x:%x:%x:%x:%x:%x, PS:%d, class: %x\n",
DBGPrintf(" BD:%x:%x:%x:%x:%x:%x, PS:%d, class: %x\n",
rxbuf_[index_bd],rxbuf_[index_bd+1],rxbuf_[index_bd+2],rxbuf_[index_bd+3],rxbuf_[index_bd+4],rxbuf_[index_bd+5], rxbuf_[index_bd],rxbuf_[index_bd+1],rxbuf_[index_bd+2],rxbuf_[index_bd+3],rxbuf_[index_bd+4],rxbuf_[index_bd+5],
rxbuf_[index_ps], bluetooth_class); rxbuf_[index_ps], bluetooth_class);
// See if we know the class
// See if we know the class
if (((bluetooth_class & 0xff00) == 0x2500) || ((bluetooth_class & 0xff00) == 0x500)) { if (((bluetooth_class & 0xff00) == 0x2500) || ((bluetooth_class & 0xff00) == 0x500)) {
DBGPrintf(" Peripheral device\n"); DBGPrintf(" Peripheral device\n");
if (bluetooth_class & 0x80) DBGPrintf(" Mouse\n"); if (bluetooth_class & 0x80) DBGPrintf(" Mouse\n");
if (bluetooth_class & 0x40) DBGPrintf(" Keyboard\n");
if (bluetooth_class & 0x40) DBGPrintf(" Keyboard\n");
switch(bluetooth_class & 0x3c) { switch(bluetooth_class & 0x3c) {
case 4: DBGPrintf(" Joystick\n"); break; case 4: DBGPrintf(" Joystick\n"); break;
case 8: DBGPrintf(" Gamepad\n"); break; case 8: DBGPrintf(" Gamepad\n"); break;
} }


void BluetoothController::handle_hci_extended_inquiry_result() void BluetoothController::handle_hci_extended_inquiry_result()
{
{
DBGPrintf(" Extended Inquiry Result - Count: %d\n", rxbuf_[2]); DBGPrintf(" Extended Inquiry Result - Count: %d\n", rxbuf_[2]);
// Should always be only one result here.
// Should always be only one result here.
uint8_t index_bd = 3; uint8_t index_bd = 3;
uint8_t index_ps = 9; uint8_t index_ps = 9;
uint8_t index_class = 11; uint8_t index_class = 11;
uint8_t index_local_name = 0; uint8_t index_local_name = 0;
uint8_t size_local_name = 0; uint8_t size_local_name = 0;
uint32_t bluetooth_class = rxbuf_[index_class] + ((uint32_t)rxbuf_[index_class+1] << 8) + ((uint32_t)rxbuf_[index_class+2] << 16); uint32_t bluetooth_class = rxbuf_[index_class] + ((uint32_t)rxbuf_[index_class+1] << 8) + ((uint32_t)rxbuf_[index_class+2] << 16);
DBGPrintf(" BD:%x:%x:%x:%x:%x:%x, PS:%d, class: %x\n",
DBGPrintf(" BD:%x:%x:%x:%x:%x:%x, PS:%d, class: %x\n",
rxbuf_[index_bd],rxbuf_[index_bd+1],rxbuf_[index_bd+2],rxbuf_[index_bd+3],rxbuf_[index_bd+4],rxbuf_[index_bd+5], rxbuf_[index_bd],rxbuf_[index_bd+1],rxbuf_[index_bd+2],rxbuf_[index_bd+3],rxbuf_[index_bd+4],rxbuf_[index_bd+5],
rxbuf_[index_ps], bluetooth_class); rxbuf_[index_ps], bluetooth_class);
// Lets see if we can find a name // Lets see if we can find a name
DBGPrintf(" Local Name: %s\n", &rxbuf_[index_local_name]); DBGPrintf(" Local Name: %s\n", &rxbuf_[index_local_name]);
} }


// See if we know the class
// See if we know the class
if (((bluetooth_class & 0xff00) == 0x2500) || ((bluetooth_class & 0xff00) == 0x500)) { if (((bluetooth_class & 0xff00) == 0x2500) || ((bluetooth_class & 0xff00) == 0x500)) {
DBGPrintf(" Peripheral device\n"); DBGPrintf(" Peripheral device\n");
if (bluetooth_class & 0x80) DBGPrintf(" Mouse\n"); if (bluetooth_class & 0x80) DBGPrintf(" Mouse\n");
if (bluetooth_class & 0x40) DBGPrintf(" Keyboard\n");
if (bluetooth_class & 0x40) DBGPrintf(" Keyboard\n");
switch(bluetooth_class & 0x3c) { switch(bluetooth_class & 0x3c) {
case 4: DBGPrintf(" Joystick\n"); break; case 4: DBGPrintf(" Joystick\n"); break;
case 8: DBGPrintf(" Gamepad\n"); break; case 8: DBGPrintf(" Gamepad\n"); break;
connections_[current_connection_].device_clock_offset_[0] = rxbuf_[index_clock_offset]; connections_[current_connection_].device_clock_offset_[0] = rxbuf_[index_clock_offset];
connections_[current_connection_].device_clock_offset_[1] = rxbuf_[index_clock_offset+1]; connections_[current_connection_].device_clock_offset_[1] = rxbuf_[index_clock_offset+1];


// and if we found a driver, save away the name
// and if we found a driver, save away the name
if (connections_[current_connection_].device_driver_ && index_local_name && size_local_name) { if (connections_[current_connection_].device_driver_ && index_local_name && size_local_name) {
uint8_t buffer_index; uint8_t buffer_index;
for (buffer_index = 0; size_local_name && (buffer_index < BTHIDInput::REMOTE_NAME_SIZE-1); buffer_index++) { for (buffer_index = 0; size_local_name && (buffer_index < BTHIDInput::REMOTE_NAME_SIZE-1); buffer_index++) {
void BluetoothController::handle_hci_connection_complete() { void BluetoothController::handle_hci_connection_complete() {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 // 0 1 2 3 4 5 6 7 8 9 10 11 12
// ST CH CH BD BD BD BD BD BD LT EN // ST CH CH BD BD BD BD BD BD LT EN
// 03 0b 04 00 00 40 25 00 58 4b 00 01 00
// 03 0b 04 00 00 40 25 00 58 4b 00 01 00
connections_[current_connection_].device_connection_handle_ = rxbuf_[3]+ (uint16_t)(rxbuf_[4]<<8); connections_[current_connection_].device_connection_handle_ = rxbuf_[3]+ (uint16_t)(rxbuf_[4]<<8);
DBGPrintf(" Connection Complete - ST:%x LH:%x\n", rxbuf_[2], connections_[current_connection_].device_connection_handle_); DBGPrintf(" Connection Complete - ST:%x LH:%x\n", rxbuf_[2], connections_[current_connection_].device_connection_handle_);
if (do_pair_device_ && !(connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_DONT_NEED_CONNECT))) { if (do_pair_device_ && !(connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_DONT_NEED_CONNECT))) {
pending_control_ = PC_AUTHENTICATION_REQUESTED; pending_control_ = PC_AUTHENTICATION_REQUESTED;
} else if (connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_NEED_CONNECT)) { } else if (connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_NEED_CONNECT)) {
DBGPrintf(" Needs connect to device(PS4?)\n"); DBGPrintf(" Needs connect to device(PS4?)\n");
// The PS4 requires a connection request to it.
// The PS4 requires a connection request to it.
delay(1); delay(1);
sendl2cap_ConnectionRequest(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].control_dcid_, HID_CTRL_PSM); sendl2cap_ConnectionRequest(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].control_dcid_, HID_CTRL_PSM);
#if 0
#if 0
delay(1); delay(1);
uint8_t packet[2]; uint8_t packet[2];
memset(packet, 0, sizeof(packet)); memset(packet, 0, sizeof(packet));
packet[0] = 0x43;
packet[0] = 0x43;
packet[1] = 0x02; // Report ID packet[1] = 0x02; // Report ID
USBHDBGSerial.printf("SixAxis Command Issued!\r\n"); USBHDBGSerial.printf("SixAxis Command Issued!\r\n");
sendL2CapCommand(packet, sizeof(packet), 0x40);
#endif
sendL2CapCommand(packet, sizeof(packet), 0x40);
#endif
} }
} }


// BD BD BD BD BD BD CL CL CL LT // BD BD BD BD BD BD CL CL CL LT
// 0x04 0x0A 0x79 0x22 0x23 0x0A 0xC5 0xCC 0x40 0x05 0x00 0x01 // 0x04 0x0A 0x79 0x22 0x23 0x0A 0xC5 0xCC 0x40 0x05 0x00 0x01
uint32_t class_of_device = rxbuf_[8] + (uint16_t)(rxbuf_[9]<<8) + (uint32_t)(rxbuf_[10]<<16); uint32_t class_of_device = rxbuf_[8] + (uint16_t)(rxbuf_[9]<<8) + (uint32_t)(rxbuf_[10]<<16);
DBGPrintf(" Event: Incoming Connect - %x:%x:%x:%x:%x:%x CL:%x LT:%x\n",
DBGPrintf(" Event: Incoming Connect - %x:%x:%x:%x:%x:%x CL:%x LT:%x\n",
rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7], class_of_device, rxbuf_[11]); rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7], class_of_device, rxbuf_[11]);
if (((class_of_device & 0xff00) == 0x2500) || ((class_of_device & 0xff00) == 0x500)) { if (((class_of_device & 0xff00) == 0x2500) || ((class_of_device & 0xff00) == 0x500)) {
DBGPrintf(" Peripheral device\n"); DBGPrintf(" Peripheral device\n");
if (class_of_device & 0x80) DBGPrintf(" Mouse\n"); if (class_of_device & 0x80) DBGPrintf(" Mouse\n");
if (class_of_device & 0x40) DBGPrintf(" Keyboard\n");
if (class_of_device & 0x40) DBGPrintf(" Keyboard\n");
switch(class_of_device & 0x3c) { switch(class_of_device & 0x3c) {
case 4: DBGPrintf(" Joystick\n"); break; case 4: DBGPrintf(" Joystick\n"); break;
case 8: DBGPrintf(" Gamepad\n"); break; case 8: DBGPrintf(" Gamepad\n"); break;


// We need to save away the BDADDR and class link type? // We need to save away the BDADDR and class link type?
for(uint8_t i=0; i<6; i++) connections_[current_connection_].device_bdaddr_[i] = rxbuf_[i+2]; for(uint8_t i=0; i<6; i++) connections_[current_connection_].device_bdaddr_[i] = rxbuf_[i+2];
connections_[current_connection_].device_class_ = class_of_device;
connections_[current_connection_].device_class_ = class_of_device;
sendHCIRemoteNameRequest(); sendHCIRemoteNameRequest();
} }




void BluetoothController::handle_hci_pin_code_request() { void BluetoothController::handle_hci_pin_code_request() {
// 0x16 0x06 0x79 0x22 0x23 0x0A 0xC5 0xCC // 0x16 0x06 0x79 0x22 0x23 0x0A 0xC5 0xCC
DBGPrintf(" Event: Pin Code Request %x:%x:%x:%x:%x:%x\n",
DBGPrintf(" Event: Pin Code Request %x:%x:%x:%x:%x:%x\n",
rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7]); rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7]);
sendHCIPinCodeReply(); sendHCIPinCodeReply();
pending_control_ = PC_PIN_CODE_REPLY; pending_control_ = PC_PIN_CODE_REPLY;
} }


void BluetoothController::handle_hci_link_key_request() { void BluetoothController::handle_hci_link_key_request() {
// 17 6 79 22 23 a c5 cc
DBGPrintf(" Event: Link Key Request %x:%x:%x:%x:%x:%x\n",
// 17 6 79 22 23 a c5 cc
DBGPrintf(" Event: Link Key Request %x:%x:%x:%x:%x:%x\n",
rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7]); rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7]);


// Now here is where we need to decide to say we have key or tell them to
// Now here is where we need to decide to say we have key or tell them to
// cancel key... right now hard code to cancel... // cancel key... right now hard code to cancel...
sendHCILinkKeyNegativeReply(); sendHCILinkKeyNegativeReply();
pending_control_ = PC_LINK_KEY_NEGATIVE; pending_control_ = PC_LINK_KEY_NEGATIVE;


void BluetoothController::handle_hci_link_key_notification() { void BluetoothController::handle_hci_link_key_notification() {
// 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 // 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
// 18 17 79 22 23 a c5 cc 5e 98 d4 5e bb 15 66 da 67 fe 4f 87 2b 61 46 b4 0
DBGPrintf(" Event: Link Key Notificaton %x:%x:%x:%x:%x:%x Type:%x\n key:",
// 18 17 79 22 23 a c5 cc 5e 98 d4 5e bb 15 66 da 67 fe 4f 87 2b 61 46 b4 0
DBGPrintf(" Event: Link Key Notificaton %x:%x:%x:%x:%x:%x Type:%x\n key:",
rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7], rxbuf_[24]); rxbuf_[2], rxbuf_[3], rxbuf_[4], rxbuf_[5], rxbuf_[6], rxbuf_[7], rxbuf_[24]);
for (uint8_t i = 8; i < 24; i++) DBGPrintf("%02x ", rxbuf_[i]); for (uint8_t i = 8; i < 24; i++) DBGPrintf("%02x ", rxbuf_[i]);
DBGPrintf("\n"); DBGPrintf("\n");


// Now here is where we need to decide to say we have key or tell them to
// Now here is where we need to decide to say we have key or tell them to
// cancel key... right now hard code to cancel... // cancel key... right now hard code to cancel...


} }
void BluetoothController::handle_hci_disconnect_complete() void BluetoothController::handle_hci_disconnect_complete()
{ {
//5 4 0 48 0 13 //5 4 0 48 0 13
DBGPrintf(" Event: HCI Disconnect complete(%d): handle: %x, reason:%x\n", rxbuf_[2],
DBGPrintf(" Event: HCI Disconnect complete(%d): handle: %x, reason:%x\n", rxbuf_[2],
rxbuf_[3]+(rxbuf_[4]<<8), rxbuf_[5]); rxbuf_[3]+(rxbuf_[4]<<8), rxbuf_[5]);
if (connections_[current_connection_].device_driver_) { if (connections_[current_connection_].device_driver_) {
connections_[current_connection_].device_driver_->release_bluetooth(); connections_[current_connection_].device_driver_->release_bluetooth();
connections_[current_connection_].device_driver_->remote_name_[0] = 0; connections_[current_connection_].device_driver_->remote_name_[0] = 0;
connections_[current_connection_].device_driver_ = nullptr; connections_[current_connection_].device_driver_ = nullptr;
// Restore to normal...
// Restore to normal...
connections_[current_connection_].control_dcid_ = 0x70; connections_[current_connection_].control_dcid_ = 0x70;
connections_[current_connection_].interrupt_dcid_ = 0x71; connections_[current_connection_].interrupt_dcid_ = 0x71;
} }
// Probably should clear out connection data.
// Probably should clear out connection data.
#if 0 #if 0
connections_[current_connection_].device_connection_handle_ = 0; connections_[current_connection_].device_connection_handle_ = 0;
connections_[current_connection_].device_class_ = 0;
connections_[current_connection_].device_class_ = 0;
memset(connections_[current_connection_].device_bdaddr_, 0, sizeof(connections_[current_connection_].device_bdaddr_)); memset(connections_[current_connection_].device_bdaddr_, 0, sizeof(connections_[current_connection_].device_bdaddr_));
#endif #endif
// Now we need to remove that item from our list of connections. // Now we need to remove that item from our list of connections.
count_connections_--;
count_connections_--;
if (count_connections_ == 0) { if (count_connections_ == 0) {
// reset the next connection counts back to initial states. // reset the next connection counts back to initial states.
next_dcid_ = 0x70; // Lets try not hard coding control and interrupt dcid next_dcid_ = 0x70; // Lets try not hard coding control and interrupt dcid
void BluetoothController::handle_hci_authentication_complete() void BluetoothController::handle_hci_authentication_complete()
{ {
// 6 3 13 48 0 // 6 3 13 48 0
DBGPrintf(" Event: HCI Authentication complete(%d): handle: %x\n", rxbuf_[2],
DBGPrintf(" Event: HCI Authentication complete(%d): handle: %x\n", rxbuf_[2],
rxbuf_[3]+(rxbuf_[4]<<8)); rxbuf_[3]+(rxbuf_[4]<<8));
// Start up lcap connection... // Start up lcap connection...
connections_[current_connection_].connection_rxid_ = 0; connections_[current_connection_].connection_rxid_ = 0;
connections_[current_connection_].device_driver_->release_bluetooth(); connections_[current_connection_].device_driver_->release_bluetooth();
connections_[current_connection_].device_driver_ = nullptr; connections_[current_connection_].device_driver_ = nullptr;
} }
}
}
if (!connections_[current_connection_].device_driver_) { if (!connections_[current_connection_].device_driver_) {
connections_[current_connection_].device_driver_ = find_driver(connections_[current_connection_].device_class_, &rxbuf_[9]); connections_[current_connection_].device_driver_ = find_driver(connections_[current_connection_].device_class_, &rxbuf_[9]);
// not sure I should call remote name again, but they already process... // not sure I should call remote name again, but they already process...
} }
} }
if (connections_[current_connection_].device_driver_) { if (connections_[current_connection_].device_driver_) {
// lets save away the string.
// lets save away the string.
uint8_t buffer_index; uint8_t buffer_index;
for (buffer_index = 0; buffer_index < BTHIDInput::REMOTE_NAME_SIZE-1; buffer_index++) { for (buffer_index = 0; buffer_index < BTHIDInput::REMOTE_NAME_SIZE-1; buffer_index++) {
connections_[current_connection_].device_driver_->remote_name_[buffer_index] = rxbuf_[9+buffer_index]; connections_[current_connection_].device_driver_->remote_name_[buffer_index] = rxbuf_[9+buffer_index];
connections_[current_connection_].device_driver_->remote_name_[buffer_index] = 0; // make sure null terminated connections_[current_connection_].device_driver_->remote_name_[buffer_index] = 0; // make sure null terminated


if (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_PS3_IDS) { if (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_PS3_IDS) {
// Real hack see if PS3...
// Real hack see if PS3...
connections_[current_connection_].control_dcid_ = 0x40; connections_[current_connection_].control_dcid_ = 0x40;
connections_[current_connection_].interrupt_dcid_ = 0x41; connections_[current_connection_].interrupt_dcid_ = 0x41;
} else { } else {
} }


// If we are in the connection complete mode, then this is a pairing state and needed to call // If we are in the connection complete mode, then this is a pairing state and needed to call
// get remote name later.
if (connections_[current_connection_].connection_complete_) {
if (connections_[current_connection_].device_driver_) { // We have a driver call their
// get remote name later.
if (connections_[current_connection_].connection_complete_) {
if (connections_[current_connection_].device_driver_) { // We have a driver call their
connections_[current_connection_].device_driver_->connectionComplete(); connections_[current_connection_].device_driver_->connectionComplete();
connections_[current_connection_].connection_complete_ = false; // only call once connections_[current_connection_].connection_complete_ = false; // only call once
} }
} else { } else {
sendHCIAcceptConnectionRequest();
}
sendHCIAcceptConnectionRequest();
}
} }


void BluetoothController::handle_hci_remote_version_information_complete() { void BluetoothController::handle_hci_remote_version_information_complete() {
connections_[current_connection_].remote_ver_ = rxbuf_[6]; connections_[current_connection_].remote_ver_ = rxbuf_[6];
connections_[current_connection_].remote_man_ = rxbuf_[7]+((uint16_t)rxbuf_[8]<< 8); connections_[current_connection_].remote_man_ = rxbuf_[7]+((uint16_t)rxbuf_[8]<< 8);
connections_[current_connection_].remote_subv_ = rxbuf_[9]; connections_[current_connection_].remote_subv_ = rxbuf_[9];
DBGPrintf(" Event: handle_hci_remote_version_information_complete(%d): ", rxbuf_[2]); DBGPrintf(" Event: handle_hci_remote_version_information_complete(%d): ", rxbuf_[2]);
DBGPrintf(" Handle: %x, Ver:%x, Man: %x, SV: %x\n",
DBGPrintf(" Handle: %x, Ver:%x, Man: %x, SV: %x\n",
rxbuf_[3]+((uint16_t)rxbuf_[4]<< 8), connections_[current_connection_].remote_ver_, connections_[current_connection_].remote_man_, connections_[current_connection_].remote_subv_); rxbuf_[3]+((uint16_t)rxbuf_[4]<< 8), connections_[current_connection_].remote_ver_, connections_[current_connection_].remote_man_, connections_[current_connection_].remote_subv_);
// Lets now try to accept the connection.
// Lets now try to accept the connection.
sendHCIAcceptConnectionRequest(); sendHCIAcceptConnectionRequest();
} }


DBGPrintf("\n"); DBGPrintf("\n");


// call backs. See if this is an L2CAP reply. example // call backs. See if this is an L2CAP reply. example
// HCI | l2cap
// HCI | l2cap
//48 20 10 0 | c 0 1 0 | 3 0 8 0 44 0 70 0 0 0 0 0 //48 20 10 0 | c 0 1 0 | 3 0 8 0 44 0 70 0 0 0 0 0
// BUGBUG need to do more verification, like the handle // BUGBUG need to do more verification, like the handle
uint16_t hci_length = buffer[2] + ((uint16_t)buffer[3]<<8); uint16_t hci_length = buffer[2] + ((uint16_t)buffer[3]<<8);
} }






// Queue up for next read... // Queue up for next read...
queue_Data_Transfer(rx2pipe_, rx2buf_, rx2_size_, this); queue_Data_Transfer(rx2pipe_, rx2buf_, rx2_size_, this);


//--------------------------------------------- //---------------------------------------------
void BluetoothController::sendHCIHCIWriteInquiryMode(uint8_t inquiry_mode) { void BluetoothController::sendHCIHCIWriteInquiryMode(uint8_t inquiry_mode) {
// Setup Inquiry mode
// Setup Inquiry mode
DBGPrintf("HCI_WRITE_INQUIRY_MODE called ("); DBGPrintf("HCI_WRITE_INQUIRY_MODE called (");
sendHCICommand(HCI_WRITE_INQUIRY_MODE, 1, &inquiry_mode);
sendHCICommand(HCI_WRITE_INQUIRY_MODE, 1, &inquiry_mode);
} }


void BluetoothController::sendHCISetEventMask() { void BluetoothController::sendHCISetEventMask() {
// Setup Inquiry mode
// Setup Inquiry mode
DBGPrintf("HCI_Set_Event_Mask called ("); DBGPrintf("HCI_Set_Event_Mask called (");
static const uint8_t hci_event_mask_data[8] = { static const uint8_t hci_event_mask_data[8] = {
// Default: 0x0000 1FFF FFFF FFFF
// Default: 0x0000 1FFF FFFF FFFF
0xff,0xff, 0xff,0xff, 0xff,0x5f, 0x00,0x00}; // default plus extended inquiry mode 0xff,0xff, 0xff,0xff, 0xff,0x5f, 0x00,0x00}; // default plus extended inquiry mode
sendHCICommand(HCI_Set_Event_Mask, sizeof(hci_event_mask_data), hci_event_mask_data);
sendHCICommand(HCI_Set_Event_Mask, sizeof(hci_event_mask_data), hci_event_mask_data);
} }


//--------------------------------------------- //---------------------------------------------
void BluetoothController::sendHCI_INQUIRY() { void BluetoothController::sendHCI_INQUIRY() {
// Start unlimited inqury, set timeout to max and
// Start unlimited inqury, set timeout to max and
DBGPrintf("HCI_INQUIRY called ("); DBGPrintf("HCI_INQUIRY called (");
static const uint8_t hci_inquiry_data[ ] = { static const uint8_t hci_inquiry_data[ ] = {
0x33, 0x8B, 0x9E, // Bluetooth assigned number LAP 0x9E8B33 General/unlimited inquiry Access mode 0x33, 0x8B, 0x9E, // Bluetooth assigned number LAP 0x9E8B33 General/unlimited inquiry Access mode
0x30, 0xa}; // Max inquiry time little over minute and up to 10 responses 0x30, 0xa}; // Max inquiry time little over minute and up to 10 responses
sendHCICommand(HCI_INQUIRY, sizeof(hci_inquiry_data), hci_inquiry_data);
sendHCICommand(HCI_INQUIRY, sizeof(hci_inquiry_data), hci_inquiry_data);
} }


//--------------------------------------------- //---------------------------------------------
void BluetoothController::sendHCIInquiryCancel() { void BluetoothController::sendHCIInquiryCancel() {
DBGPrintf("HCI_INQUIRY_CANCEL called ("); DBGPrintf("HCI_INQUIRY_CANCEL called (");
sendHCICommand(HCI_INQUIRY_CANCEL, 0, nullptr);
sendHCICommand(HCI_INQUIRY_CANCEL, 0, nullptr);
} }


//--------------------------------------------- //---------------------------------------------
// BD BD BD BD BD BD PT PT PRS 0 CS CS ARS // BD BD BD BD BD BD PT PT PRS 0 CS CS ARS
//0x79 0x22 0x23 0x0A 0xC5 0xCC 0x18 0xCC 0x01 0x00 0x00 0x00 0x00 //0x79 0x22 0x23 0x0A 0xC5 0xCC 0x18 0xCC 0x01 0x00 0x00 0x00 0x00
//0x05 0x04 0x0D 0x79 0x22 0x23 0x0A 0xC5 0xCC 0x18 0xCC 0x01 0x00 0x00 0x00 0x00 //0x05 0x04 0x0D 0x79 0x22 0x23 0x0A 0xC5 0xCC 0x18 0xCC 0x01 0x00 0x00 0x00 0x00
// 05 04 0d 40 25 00 c4 01 00 18 cc 01 00 00 00 00
// 05 04 0d 40 25 00 c4 01 00 18 cc 01 00 00 00 00


for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i]; for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i];
connection_data[6] = 0x18; //DM1/DH1 connection_data[6] = 0x18; //DM1/DH1
connection_data[7] = 0xcc; // connection_data[7] = 0xcc; //
connection_data[8] = connections_[current_connection_].device_ps_repetion_mode_; // from device connection_data[8] = connections_[current_connection_].device_ps_repetion_mode_; // from device
connection_data[9] = 0; // connection_data[9] = 0; //
connection_data[10] = 0; // clock offset
connection_data[11] = 0; // clock offset
connection_data[12] = 0; // allow role swith no
sendHCICommand(HCI_CREATE_CONNECTION, sizeof(connection_data), connection_data);
connection_data[10] = 0; // clock offset
connection_data[11] = 0; // clock offset
connection_data[12] = 0; // allow role swith no
sendHCICommand(HCI_CREATE_CONNECTION, sizeof(connection_data), connection_data);
} }


//--------------------------------------------- //---------------------------------------------
uint8_t connection_data[7]; uint8_t connection_data[7];


// 0 1 2 3 4 5 6 7 8 9 10 11 12 // 0 1 2 3 4 5 6 7 8 9 10 11 12
// BD BD BD BD BD BD role
// BD BD BD BD BD BD role
//0x79 0x22 0x23 0x0A 0xC5 0xCC 0x00 //0x79 0x22 0x23 0x0A 0xC5 0xCC 0x00
for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i]; for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i];
connection_data[6] = 0; // Role as master connection_data[6] = 0; // Role as master
sendHCICommand(HCI_OP_ACCEPT_CONN_REQ, sizeof(connection_data), connection_data);
sendHCICommand(HCI_OP_ACCEPT_CONN_REQ, sizeof(connection_data), connection_data);
} }


//--------------------------------------------- //---------------------------------------------
uint8_t connection_data[2]; uint8_t connection_data[2];
connection_data[0] = connections_[current_connection_].device_connection_handle_ & 0xff; connection_data[0] = connections_[current_connection_].device_connection_handle_ & 0xff;
connection_data[1] = (connections_[current_connection_].device_connection_handle_>>8) & 0xff; connection_data[1] = (connections_[current_connection_].device_connection_handle_>>8) & 0xff;
sendHCICommand(HCI_AUTH_REQUESTED, sizeof(connection_data), connection_data);
sendHCICommand(HCI_AUTH_REQUESTED, sizeof(connection_data), connection_data);
} }


//--------------------------------------------- //---------------------------------------------
DBGPrintf("HCI_LINK_KEY_NEG_REPLY called ("); DBGPrintf("HCI_LINK_KEY_NEG_REPLY called (");
uint8_t connection_data[6]; uint8_t connection_data[6];
for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i]; for (uint8_t i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i];
sendHCICommand(HCI_LINK_KEY_NEG_REPLY, sizeof(connection_data), connection_data);
sendHCICommand(HCI_LINK_KEY_NEG_REPLY, sizeof(connection_data), connection_data);
} }


//--------------------------------------------- //---------------------------------------------
for (i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i]; for (i=0; i<6; i++) connection_data[i] = connections_[current_connection_].device_bdaddr_[i];


for (i=0; pair_pincode_[i] !=0; i++) connection_data[7+i] = pair_pincode_[i]; for (i=0; pair_pincode_[i] !=0; i++) connection_data[7+i] = pair_pincode_[i];
connection_data[6] = i; // remember the length
connection_data[6] = i; // remember the length
for (uint8_t i=7+connection_data[6]; i<23; i++) connection_data[i] = 0; for (uint8_t i=7+connection_data[6]; i<23; i++) connection_data[i] = 0;
sendHCICommand(HCI_PIN_CODE_REPLY, sizeof(connection_data), connection_data);
sendHCICommand(HCI_PIN_CODE_REPLY, sizeof(connection_data), connection_data);
} }


//--------------------------------------------- //---------------------------------------------
void BluetoothController::sendResetHCI() { void BluetoothController::sendResetHCI() {
DBGPrintf("HCI_RESET called ("); DBGPrintf("HCI_RESET called (");
sendHCICommand(HCI_RESET, 0, nullptr);
sendHCICommand(HCI_RESET, 0, nullptr);
} }


void BluetoothController::sendHDCWriteClassOfDev() { void BluetoothController::sendHDCWriteClassOfDev() {
// 0x24 0x0C 0x03 0x04 0x08 0x00 // 0x24 0x0C 0x03 0x04 0x08 0x00
const static uint8_t device_class_data[] = {BT_CLASS_DEVICE & 0xff, (BT_CLASS_DEVICE >> 8) & 0xff, (BT_CLASS_DEVICE >> 16) & 0xff}; const static uint8_t device_class_data[] = {BT_CLASS_DEVICE & 0xff, (BT_CLASS_DEVICE >> 8) & 0xff, (BT_CLASS_DEVICE >> 16) & 0xff};
DBGPrintf("HCI_WRITE_CLASS_OF_DEV called ("); DBGPrintf("HCI_WRITE_CLASS_OF_DEV called (");
sendHCICommand(HCI_WRITE_CLASS_OF_DEV, sizeof(device_class_data), device_class_data);
sendHCICommand(HCI_WRITE_CLASS_OF_DEV, sizeof(device_class_data), device_class_data);
} }






void BluetoothController::sendHCIReadBDAddr() { void BluetoothController::sendHCIReadBDAddr() {
DBGPrintf("HCI_Read_BD_ADDR called ("); DBGPrintf("HCI_Read_BD_ADDR called (");
sendHCICommand(HCI_Read_BD_ADDR, 0, nullptr);
sendHCICommand(HCI_Read_BD_ADDR, 0, nullptr);
} }


void BluetoothController::sendHCIReadLocalVersionInfo() { void BluetoothController::sendHCIReadLocalVersionInfo() {
DBGPrintf("HCI_Read_Local_Version_Information called ("); DBGPrintf("HCI_Read_Local_Version_Information called (");
sendHCICommand(HCI_Read_Local_Version_Information, 0, nullptr);
sendHCICommand(HCI_Read_Local_Version_Information, 0, nullptr);
} }




connection_data[6] = 1; // page scan repeat mode... connection_data[6] = 1; // page scan repeat mode...
connection_data[7] = 0; // 0 connection_data[7] = 0; // 0
connection_data[8] = 0; // Clk offset connection_data[8] = 0; // Clk offset
connection_data[9] = 0;
sendHCICommand(HCI_OP_REMOTE_NAME_REQ, sizeof(connection_data), connection_data);
connection_data[9] = 0;
sendHCICommand(HCI_OP_REMOTE_NAME_REQ, sizeof(connection_data), connection_data);
} }


void BluetoothController::sendHCIRemoteVersionInfoRequest() { // 0x041D void BluetoothController::sendHCIRemoteVersionInfoRequest() { // 0x041D
uint8_t connection_data[2]; uint8_t connection_data[2];
connection_data[0] = connections_[current_connection_].device_connection_handle_ & 0xff; connection_data[0] = connections_[current_connection_].device_connection_handle_ & 0xff;
connection_data[1] = (connections_[current_connection_].device_connection_handle_>>8) & 0xff; connection_data[1] = (connections_[current_connection_].device_connection_handle_>>8) & 0xff;
sendHCICommand(HCI_OP_READ_REMOTE_VERSION_INFORMATION, sizeof(connection_data), connection_data);
sendHCICommand(HCI_OP_READ_REMOTE_VERSION_INFORMATION, sizeof(connection_data), connection_data);
} }


// l2cap support functions.
// l2cap support functions.
void BluetoothController::sendl2cap_ConnectionResponse(uint16_t handle, uint8_t rxid, uint16_t dcid, uint16_t scid, uint8_t result) { void BluetoothController::sendl2cap_ConnectionResponse(uint16_t handle, uint8_t rxid, uint16_t dcid, uint16_t scid, uint8_t result) {
uint8_t l2capbuf[12]; uint8_t l2capbuf[12];
l2capbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code l2capbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code




//******************************************************************* //*******************************************************************
//
//
// HCI ACL Packets // HCI ACL Packets
// HCI Handle Low, HCI_Handle_High (PB, BC), Total length low, TLH - HCI ACL Data packet // HCI Handle Low, HCI_Handle_High (PB, BC), Total length low, TLH - HCI ACL Data packet
// length Low, length high, channel id low, channel id high - L2CAP header // length Low, length high, channel id low, channel id high - L2CAP header
// code, identifier, length, ... - Control-frame
// code, identifier, length, ... - Control-frame


/************************************************************/ /************************************************************/
/* L2CAP Commands */ /* L2CAP Commands */
nbytes = nbytes+8; nbytes = nbytes+8;
for (uint8_t i=0; i< nbytes; i++) DBGPrintf("%02x ", txbuf_[i]); for (uint8_t i=0; i< nbytes; i++) DBGPrintf("%02x ", txbuf_[i]);
DBGPrintf(")\n"); DBGPrintf(")\n");
if (!queue_Data_Transfer(txpipe_, txbuf_, nbytes, this)) { if (!queue_Data_Transfer(txpipe_, txbuf_, nbytes, this)) {
println("sendL2CapCommand failed"); println("sendL2CapCommand failed");
} }
} }


void BluetoothController::process_l2cap_connection_request(uint8_t *data) { void BluetoothController::process_l2cap_connection_request(uint8_t *data) {
// ID LEN LEN PSM PSM SCID SCID
// ID LEN LEN PSM PSM SCID SCID
// 0x02 0x02 0x04 0x00 0x11 0x00 0x43 0x00 // 0x02 0x02 0x04 0x00 0x11 0x00 0x43 0x00


uint16_t psm = data[4]+((uint16_t)data[5] << 8);
uint16_t psm = data[4]+((uint16_t)data[5] << 8);
uint16_t scid = data[6]+((uint16_t)data[7] << 8); uint16_t scid = data[6]+((uint16_t)data[7] << 8);
connections_[current_connection_].connection_rxid_ = data[1]; connections_[current_connection_].connection_rxid_ = data[1];
DBGPrintf(" L2CAP Connection Request: ID: %d, PSM: %x, SCID: %x\n",connections_[current_connection_].connection_rxid_, psm, scid); DBGPrintf(" L2CAP Connection Request: ID: %d, PSM: %x, SCID: %x\n",connections_[current_connection_].connection_rxid_, psm, scid);
if (psm == HID_CTRL_PSM) { if (psm == HID_CTRL_PSM) {
connections_[current_connection_].control_scid_ = scid; connections_[current_connection_].control_scid_ = scid;
sendl2cap_ConnectionResponse(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].control_dcid_, connections_[current_connection_].control_scid_, PENDING); sendl2cap_ConnectionResponse(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].control_dcid_, connections_[current_connection_].control_scid_, PENDING);
pending_control_tx_ = STATE_TX_SEND_CONECT_RSP_SUCCESS;
pending_control_tx_ = STATE_TX_SEND_CONECT_RSP_SUCCESS;
} else if (psm == HID_INTR_PSM) { } else if (psm == HID_INTR_PSM) {
connections_[current_connection_].interrupt_scid_ = scid; connections_[current_connection_].interrupt_scid_ = scid;
sendl2cap_ConnectionResponse(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].interrupt_dcid_, connections_[current_connection_].interrupt_scid_, PENDING); sendl2cap_ConnectionResponse(connections_[current_connection_].device_connection_handle_, connections_[current_connection_].connection_rxid_, connections_[current_connection_].interrupt_dcid_, connections_[current_connection_].interrupt_scid_, PENDING);
pending_control_tx_ = STATE_TX_SEND_CONECT_ISR_RSP_SUCCESS;
pending_control_tx_ = STATE_TX_SEND_CONECT_ISR_RSP_SUCCESS;


} }
} }
// Process the l2cap_connection_response... // Process the l2cap_connection_response...
void BluetoothController::process_l2cap_connection_response(uint8_t *data) { void BluetoothController::process_l2cap_connection_response(uint8_t *data) {


uint16_t scid = data[4]+((uint16_t)data[5] << 8);
uint16_t dcid = data[6]+((uint16_t)data[7] << 8);
uint16_t scid = data[4]+((uint16_t)data[5] << 8);
uint16_t dcid = data[6]+((uint16_t)data[7] << 8);


DBGPrintf(" L2CAP Connection Response: ID: %d, Dest:%x, Source:%x, Result:%x, Status: %x\n", DBGPrintf(" L2CAP Connection Response: ID: %d, Dest:%x, Source:%x, Result:%x, Status: %x\n",
data[1], scid, dcid, data[1], scid, dcid,


void BluetoothController::process_l2cap_config_request(uint8_t *data) { void BluetoothController::process_l2cap_config_request(uint8_t *data) {
//48 20 10 0 c 0 1 0 *4 2 8 0 70 0 0 0 1 2 30 0 //48 20 10 0 c 0 1 0 *4 2 8 0 70 0 0 0 1 2 30 0
uint16_t dcid = data[4]+((uint16_t)data[5] << 8);
uint16_t dcid = data[4]+((uint16_t)data[5] << 8);
DBGPrintf(" L2CAP config Request: ID: %d, Dest:%x, Flags:%x, Options: %x %x %x %x\n", DBGPrintf(" L2CAP config Request: ID: %d, Dest:%x, Flags:%x, Options: %x %x %x %x\n",
data[1], dcid, data[6]+((uint16_t)data[7] << 8), data[1], dcid, data[6]+((uint16_t)data[7] << 8),
data[8], data[9], data[10], data[11]); data[8], data[9], data[10], data[11]);


void BluetoothController::process_l2cap_config_response(uint8_t *data) { void BluetoothController::process_l2cap_config_response(uint8_t *data) {
// 48 20 12 0 e 0 1 0 5 0 a 0 70 0 0 0 0 0 1 2 30 0 // 48 20 12 0 e 0 1 0 5 0 a 0 70 0 0 0 0 0 1 2 30 0
uint16_t scid = data[4]+((uint16_t)data[5] << 8);
uint16_t scid = data[4]+((uint16_t)data[5] << 8);
DBGPrintf(" L2CAP config Response: ID: %d, Source:%x, Flags:%x, Result:%x, Config: %x\n", DBGPrintf(" L2CAP config Response: ID: %d, Source:%x, Flags:%x, Result:%x, Config: %x\n",
data[1], scid, data[6]+((uint16_t)data[7] << 8), data[1], scid, data[6]+((uint16_t)data[7] << 8),
data[8]+((uint16_t)data[9] << 8), data[10]+((uint16_t)data[11] << 8)); data[8]+((uint16_t)data[9] << 8), data[10]+((uint16_t)data[11] << 8));
pending_control_tx_ = STATE_TX_SEND_CONNECT_INT; pending_control_tx_ = STATE_TX_SEND_CONNECT_INT;
} else if (connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_NEED_CONNECT)) { } else if (connections_[current_connection_].device_driver_ && (connections_[current_connection_].device_driver_->special_process_required & BTHIDInput::SP_NEED_CONNECT)) {
DBGPrintf(" Needs connect to device INT(PS4?)\n"); DBGPrintf(" Needs connect to device INT(PS4?)\n");
// The PS4 requires a connection request to it.
// The PS4 requires a connection request to it.
pending_control_tx_ = STATE_TX_SEND_CONNECT_INT; pending_control_tx_ = STATE_TX_SEND_CONNECT_INT;
} else { } else {
pending_control_ = 0; pending_control_ = 0;
} }
} }


void BluetoothController::process_l2cap_command_reject(uint8_t *data) {
// 48 20 b 0 7 0 70 0 *1 0 0 0 2 0 4
void BluetoothController::process_l2cap_command_reject(uint8_t *data) {
// 48 20 b 0 7 0 70 0 *1 0 0 0 2 0 4
DBGPrintf(" L2CAP command reject: ID: %d, length:%x, Reason:%x, Data: %x %x \n", DBGPrintf(" L2CAP command reject: ID: %d, length:%x, Reason:%x, Data: %x %x \n",
data[1], data[2] + ((uint16_t)data[3] << 8), data[4], data[5], data[6]); data[1], data[2] + ((uint16_t)data[3] << 8), data[4], data[5], data[6]);


} }


void BluetoothController::process_l2cap_disconnect_request(uint8_t *data) { void BluetoothController::process_l2cap_disconnect_request(uint8_t *data) {
uint16_t dcid = data[4]+((uint16_t)data[5] << 8);
uint16_t scid = data[6]+((uint16_t)data[7] << 8);
uint16_t dcid = data[4]+((uint16_t)data[5] << 8);
uint16_t scid = data[6]+((uint16_t)data[7] << 8);
DBGPrintf(" L2CAP disconnect request: ID: %d, Length:%x, Dest:%x, Source:%x\n", DBGPrintf(" L2CAP disconnect request: ID: %d, Length:%x, Dest:%x, Source:%x\n",
data[1], data[2] + ((uint16_t)data[3] << 8), dcid, scid); data[1], data[2] + ((uint16_t)data[3] << 8), dcid, scid);
} }
uint16_t len = data[4] + ((uint16_t)data[5] << 8); uint16_t len = data[4] + ((uint16_t)data[5] << 8);
DBGPrintf("HID HDR Data: len: %d, Type: %d Con:%d\n", len, data[9], current_connection_); DBGPrintf("HID HDR Data: len: %d, Type: %d Con:%d\n", len, data[9], current_connection_);


// ??? How to parse??? Use HID object???
// ??? How to parse??? Use HID object???
if (connections_[current_connection_].device_driver_) { if (connections_[current_connection_].device_driver_) {
connections_[current_connection_].device_driver_->process_bluetooth_HID_data(&data[9], len-1); // We skip the first byte... connections_[current_connection_].device_driver_->process_bluetooth_HID_data(&data[9], len-1); // We skip the first byte...
} else { } else {
case 1: case 1:
DBGPrintf(" Keyboard report type\n"); DBGPrintf(" Keyboard report type\n");
break; break;
case 2:
DBGPrintf(" Mouse report type\n");
case 2:
DBGPrintf(" Mouse report type\n");
break; break;
case 3:
case 3:
DBGPrintf(" Combo keyboard/pointing\n"); DBGPrintf(" Combo keyboard/pointing\n");
break; break;
default: default:
DBGPrintf(" Unknown report\n");
DBGPrintf(" Unknown report\n");
} }
} }
} }

digitizer.cpp → src/digitizer.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info




void DigitizerController::init() void DigitizerController::init()
uint32_t usage_page = usage >> 16; uint32_t usage_page = usage >> 16;
usage &= 0xFFFF; usage &= 0xFFFF;
USBHDBGSerial.printf("Digitizer: &usage=%X, usage_page=%x\n", usage, usage_page); USBHDBGSerial.printf("Digitizer: &usage=%X, usage_page=%x\n", usage, usage_page);
// This is Mikes version... // This is Mikes version...
if (usage_page == 0xff00 && usage >= 100 && usage <= 0x108) { if (usage_page == 0xff00 && usage >= 100 && usage <= 0x108) {
switch (usage) { switch (usage) {
if (usage_page == 0xff0D) { if (usage_page == 0xff0D) {
if (usage >= 0 && usage < 0x138) { //at least to start if (usage >= 0 && usage < 0x138) { //at least to start
switch (usage) { switch (usage) {
case 0x130:
case 0x130:
mouseX = value; mouseX = value;
break; break;
case 0x131: case 0x131:

ehci.cpp → src/ehci.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


// All USB EHCI controller hardware access is done from this file's code. // All USB EHCI controller hardware access is done from this file's code.
// Hardware services are made available to the rest of this library by // Hardware services are made available to the rest of this library by

enumeration.cpp → src/enumeration.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info




// USB devices are managed from this file. // USB devices are managed from this file.
free_Device(dev); free_Device(dev);
return NULL; return NULL;
} }
dev->strbuf = allocate_string_buffer(); // try to allocate a string buffer;
dev->strbuf = allocate_string_buffer(); // try to allocate a string buffer;
dev->control_pipe->callback_function = &enumeration; dev->control_pipe->callback_function = &enumeration;
dev->control_pipe->direction = 1; // 1=IN dev->control_pipe->direction = 1; // 1=IN
// Here is where the enumeration process officially begins. // Here is where the enumeration process officially begins.
} }


void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) {
strbuf_t *strbuf = dev->strbuf;
strbuf_t *strbuf = dev->strbuf;
if (!strbuf) return; // don't have a buffer if (!strbuf) return; // don't have a buffer


uint8_t *buffer = (uint8_t*)transfer->buffer; uint8_t *buffer = (uint8_t*)transfer->buffer;
if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE)
count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2;


// Now copy into our storage buffer.
// Now copy into our storage buffer.
for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) {
strbuf->buffer[buf_index++] = buffer[i]; strbuf->buffer[buf_index++] = buffer[i];
}
strbuf->buffer[buf_index] = 0; // null terminate.
}
strbuf->buffer[buf_index] = 0; // null terminate.


// Update other indexes to point to null character // Update other indexes to point to null character
while (++string_index < 3) { while (++string_index < 3) {

hid.cpp → src/hid.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info




// This HID driver claims a USB interface and parses its incoming // This HID driver claims a USB interface and parses its incoming
topusage_drivers[i] = NULL; topusage_drivers[i] = NULL;
} }
// request the HID report descriptor // request the HID report descriptor
bInterfaceNumber = descriptors[2]; // save away the interface number;
bInterfaceNumber = descriptors[2]; // save away the interface number;
mk_setup(setup, 0x81, 6, 0x2200, descriptors[2], descsize); // get report desc mk_setup(setup, 0x81, 6, 0x2200, descriptors[2], descsize); // get report desc
queue_Control_Transfer(dev, &setup, descriptor, this); queue_Control_Transfer(dev, &setup, descriptor, this);
return true; return true;
println(" got report descriptor"); println(" got report descriptor");
parse(); parse();
queue_Data_Transfer(in_pipe, report, in_size, this); queue_Data_Transfer(in_pipe, report, in_size, this);
if (device->idVendor == 0x054C &&
if (device->idVendor == 0x054C &&
((device->idProduct == 0x0268) || (device->idProduct == 0x042F)/* || (device->idProduct == 0x03D5)*/)) { ((device->idProduct == 0x0268) || (device->idProduct == 0x042F)/* || (device->idProduct == 0x03D5)*/)) {
println("send special PS3 feature command"); println("send special PS3 feature command");
mk_setup(setup, 0x21, 9, 0x03F4, 0, 4); // ps3 tell to send report 1? mk_setup(setup, 0x21, 9, 0x03F4, 0, 4); // ps3 tell to send report 1?
println("USBHIDParser:out_data called (instance)"); println("USBHIDParser:out_data called (instance)");
// A packet completed. lets mark it as done and call back // A packet completed. lets mark it as done and call back
// to top reports handler. We unmark our checkmark to // to top reports handler. We unmark our checkmark to
// handle case where they may want to queue up another one.
// handle case where they may want to queue up another one.
if (transfer->buffer == tx1) txstate &= ~1; if (transfer->buffer == tx1) txstate &= ~1;
if (transfer->buffer == tx2) txstate &= ~2; if (transfer->buffer == tx2) txstate &= ~2;
if (topusage_drivers[0]) { if (topusage_drivers[0]) {
{ {
if (topusage_drivers[0]) { if (topusage_drivers[0]) {
topusage_drivers[0]->hid_timer_event(whichTimer); topusage_drivers[0]->hid_timer_event(whichTimer);
}
}
} }




bool USBHIDParser::sendPacket(const uint8_t *buffer, int cb) { bool USBHIDParser::sendPacket(const uint8_t *buffer, int cb) {
if (!out_size || !out_pipe) return false;
if (!out_size || !out_pipe) return false;
if (!tx1) { if (!tx1) {
// Was not init before, for now lets put it at end of descriptor // Was not init before, for now lets put it at end of descriptor
// TODO: should verify that either don't exceed overlap descsize // TODO: should verify that either don't exceed overlap descsize
if ((txstate & 1) == 0) { if ((txstate & 1) == 0) {
txstate |= 1; txstate |= 1;
} else { } else {
if (!tx2)
if (!tx2)
return false; // only one buffer return false; // only one buffer
txstate |= 2; txstate |= 2;
p = tx2; p = tx2;
} }
// copy the users data into our out going buffer // copy the users data into our out going buffer
memcpy(p, buffer, cb);
memcpy(p, buffer, cb);
println("USBHIDParser Send packet"); println("USBHIDParser Send packet");
print_hexbytes(buffer, cb); print_hexbytes(buffer, cb);
queue_Data_Transfer(out_pipe, p, cb, this); queue_Data_Transfer(out_pipe, p, cb, this);
bool USBHIDParser::sendControlPacket(uint32_t bmRequestType, uint32_t bRequest, bool USBHIDParser::sendControlPacket(uint32_t bmRequestType, uint32_t bRequest,
uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf) uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf)
{ {
// Use setup structure to build packet
// Use setup structure to build packet
mk_setup(setup, bmRequestType, bRequest, wValue, wIndex, wLength); // ps3 tell to send report 1? mk_setup(setup, bmRequestType, bRequest, wValue, wIndex, wLength); // ps3 tell to send report 1?
return queue_Control_Transfer(device, &setup, buf, this); return queue_Control_Transfer(device, &setup, buf, this);
} }
uindex_max = usage[1]; uindex_max = usage[1];
uminmax = true; uminmax = true;
} else if ((report_count > 1) && (usage_count <= 1)) { } else if ((report_count > 1) && (usage_count <= 1)) {
// Special cases: Either only one or no usages specified and there are more than one
// report counts .
// Special cases: Either only one or no usages specified and there are more than one
// report counts .
if (usage_count == 1) { if (usage_count == 1) {
uindex = usage[0]; uindex = usage[0];
} else { } else {
} }
uminmax = true; uminmax = true;
} }
//USBHDBGSerial.printf("TU:%x US:%x %x %d %d: C:%d, %d, MM:%d, %x %x\n", topusage, usage_page, val, logical_min, logical_max,
//USBHDBGSerial.printf("TU:%x US:%x %x %d %d: C:%d, %d, MM:%d, %x %x\n", topusage, usage_page, val, logical_min, logical_max,
// report_count, usage_count, uminmax, usage[0], usage[1]); // report_count, usage_count, uminmax, usage[0], usage[1]);
for (uint32_t i=0; i < report_count; i++) { for (uint32_t i=0; i < report_count; i++) {
uint32_t u; uint32_t u;
uindex = USAGE_LIST_LEN-1; uindex = USAGE_LIST_LEN-1;
} }
} }
last_usage = u; // remember the last one we used...
last_usage = u; // remember the last one we used...
u |= (uint32_t)usage_page << 16; u |= (uint32_t)usage_page << 16;
print(" usage = ", u, HEX); print(" usage = ", u, HEX);



hub.cpp → src/hub.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


// True when any hub port is in the reset or reset recovery phase. // True when any hub port is in the reset or reset recovery phase.
// Only one USB device may be reset at a time, because it will // Only one USB device may be reset at a time, because it will

joystick.cpp → src/joystick.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_
#ifdef DEBUG_JOYSTICK #ifdef DEBUG_JOYSTICK
#define DBGPrintf USBHDBGSerial.printf #define DBGPrintf USBHDBGSerial.printf
#else #else
#define DBGPrintf(...)
#define DBGPrintf(...)
#endif #endif


// PID/VID to joystick mapping - Only the XBOXOne is used to claim the USB interface directly,
// The others are used after claim-hid code to know which one we have and to use it for
// doing other features.
// PID/VID to joystick mapping - Only the XBOXOne is used to claim the USB interface directly,
// The others are used after claim-hid code to know which one we have and to use it for
// doing other features.
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = { JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
{ 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false }, { 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false },
{ 0x045e, 0x0719, XBOX360, false}, { 0x045e, 0x0719, XBOX360, false},
{ 0x045e, 0x028E, SWITCH, false}, // Switch?
{ 0x054C, 0x0268, PS3, true},
{ 0x045e, 0x028E, SWITCH, false}, // Switch?
{ 0x054C, 0x0268, PS3, true},
{ 0x054C, 0x042F, PS3, true}, // PS3 Navigation controller { 0x054C, 0x042F, PS3, true}, // PS3 Navigation controller
{ 0x054C, 0x03D5, PS3_MOTION, true}, // PS3 Motion controller { 0x054C, 0x03D5, PS3_MOTION, true}, // PS3 Motion controller
{ 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true }, { 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true },
if (exclude_hid_devices && pid_vid_mapping[i].hidDevice) return UNKNOWN; if (exclude_hid_devices && pid_vid_mapping[i].hidDevice) return UNKNOWN;
return pid_vid_mapping[i].joyType; return pid_vid_mapping[i].joyType;
} }
}
}
return UNKNOWN; // Not in our list return UNKNOWN; // Not in our list
} }


// Some simple query functions depend on which interface we are using... // Some simple query functions depend on which interface we are using...
//***************************************************************************** //*****************************************************************************


uint16_t JoystickController::idVendor()
uint16_t JoystickController::idVendor()
{ {
if (device != nullptr) return device->idVendor; if (device != nullptr) return device->idVendor;
if (mydevice != nullptr) return mydevice->idVendor; if (mydevice != nullptr) return mydevice->idVendor;
return 0; return 0;
} }


uint16_t JoystickController::idProduct()
uint16_t JoystickController::idProduct()
{ {
if (device != nullptr) return device->idProduct; if (device != nullptr) return device->idProduct;
if (mydevice != nullptr) return mydevice->idProduct; if (mydevice != nullptr) return mydevice->idProduct;
const uint8_t *JoystickController::manufacturer() const uint8_t *JoystickController::manufacturer()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
//if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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]];
//if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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; return nullptr;
} }


const uint8_t *JoystickController::product() const uint8_t *JoystickController::product()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; 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]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
if (btdevice != nullptr) return remote_name_; if (btdevice != nullptr) return remote_name_;
return nullptr; return nullptr;
} }
const uint8_t *JoystickController::serialNumber() const uint8_t *JoystickController::serialNumber()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; 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]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
return nullptr; return nullptr;
} }




static uint8_t rumble_counter = 0;
static uint8_t rumble_counter = 0;


bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeout) bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeout)
{ {
// Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known // Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known
// joystick types.
rumble_lValue_ = lValue;
// joystick types.
rumble_lValue_ = lValue;
rumble_rValue_ = rValue; rumble_rValue_ = rValue;
rumble_timeout_ = timeout; rumble_timeout_ = timeout;


txbuf_[8] = lValue; // L force txbuf_[8] = lValue; // L force
txbuf_[9] = rValue; // R force txbuf_[9] = rValue; // R force
txbuf_[10] = 0xff; // Length of pulse txbuf_[10] = 0xff; // Length of pulse
txbuf_[11] = 0x00; // Period between pulses
txbuf_[12] = 0x00; // Repeat
txbuf_[11] = 0x00; // Period between pulses
txbuf_[12] = 0x00; // Repeat
if (!queue_Data_Transfer(txpipe_, txbuf_, 13, this)) { if (!queue_Data_Transfer(txpipe_, txbuf_, 13, this)) {
println("XBoxOne rumble transfer fail"); println("XBoxOne rumble transfer fail");
} }
return true; //
return true; //
case XBOX360: case XBOX360:
txbuf_[0] = 0x00; txbuf_[0] = 0x00;
txbuf_[1] = 0x01; txbuf_[1] = 0x01;
Serial.printf("Switch Rumble transfer fail\n"); Serial.printf("Switch Rumble transfer fail\n");
} }
return true; return true;
}
}
return false; return false;
} }


bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb) bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb)
{ {
// Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known // Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known
// joystick types.
// joystick types.
Serial.printf("::setLEDS(%x %x %x)\n", lr, lg, lb); Serial.printf("::setLEDS(%x %x %x)\n", lr, lg, lb);
if ((leds_[0] != lr) || (leds_[1] != lg) || (leds_[2] != lb)) { if ((leds_[0] != lr) || (leds_[1] != lg) || (leds_[2] != lb)) {
leds_[0] = lr; leds_[0] = lr;
case XBOX360: case XBOX360:
// 0: off, 1: all blink then return to before // 0: off, 1: all blink then return to before
// 2-5(TL, TR, BL, BR) - blink on then stay on // 2-5(TL, TR, BL, BR) - blink on then stay on
// 6-9() - On
// 6-9() - On
// ... // ...
txbuf_[1] = 0x00; txbuf_[1] = 0x00;
txbuf_[2] = 0x08; txbuf_[2] = 0x08;
case XBOXONE: case XBOXONE:
default: default:
return false; return false;
}
}
} }
return false; return false;
} }


packet[4] = rumble_lValue_; // Small Rumble packet[4] = rumble_lValue_; // Small Rumble
packet[5] = rumble_rValue_; // Big rumble packet[5] = rumble_rValue_; // Big rumble
packet[6] = leds_[0]; // RGB value
packet[7] = leds_[1];
packet[6] = leds_[0]; // RGB value
packet[7] = leds_[1];
packet[8] = leds_[2]; packet[8] = leds_[2];
// 9, 10 flash ON, OFF times in 100ths of second? 2.5 seconds = 255 // 9, 10 flash ON, OFF times in 100ths of second? 2.5 seconds = 255
DBGPrintf("Joystick update Rumble/LEDs\n"); DBGPrintf("Joystick update Rumble/LEDs\n");
uint8_t packet[79]; uint8_t packet[79];
memset(packet, 0, sizeof(packet)); memset(packet, 0, sizeof(packet));
//0xa2, 0x11, 0xc0, 0x20, 0xf0, 0x04, 0x00 //0xa2, 0x11, 0xc0, 0x20, 0xf0, 0x04, 0x00
packet[0] = 0x52;
packet[0] = 0x52;
packet[1] = 0x11; // Report ID packet[1] = 0x11; // Report ID
packet[2] = 0x80; packet[2] = 0x80;
//packet[3] = 0x20; //packet[3] = 0x20;


packet[7] = rumble_lValue_; // Small Rumble packet[7] = rumble_lValue_; // Small Rumble
packet[8] = rumble_rValue_; // Big rumble packet[8] = rumble_rValue_; // Big rumble
packet[9] = leds_[0]; // RGB value
packet[10] = leds_[1];
packet[9] = leds_[0]; // RGB value
packet[10] = leds_[1];
packet[11] = leds_[2]; packet[11] = leds_[2];


// 12, 13 flash ON, OFF times in 100ths of sedond? 2.5 seconds = 255 // 12, 13 flash ON, OFF times in 100ths of sedond? 2.5 seconds = 255


txbuf_[1] = rumble_lValue_? rumble_timeout_ : 0; txbuf_[1] = rumble_lValue_? rumble_timeout_ : 0;
txbuf_[2] = rumble_lValue_; // Small Rumble txbuf_[2] = rumble_lValue_; // Small Rumble
txbuf_[3] = rumble_rValue_? rumble_timeout_ : 0;
txbuf_[3] = rumble_rValue_? rumble_timeout_ : 0;
txbuf_[4] = rumble_rValue_; // Big rumble txbuf_[4] = rumble_rValue_; // Big rumble
txbuf_[9] = leds_[2] << 1; // RGB value // using third led now... txbuf_[9] = leds_[2] << 1; // RGB value // using third led now...
//DBGPrintf("\nJoystick update Rumble/LEDs %d %d %d %d %d\n", txbuf_[1], txbuf_[2], txbuf_[3], txbuf_[4], txbuf_[9]); //DBGPrintf("\nJoystick update Rumble/LEDs %d %d %d %d %d\n", txbuf_[1], txbuf_[2], txbuf_[3], txbuf_[4], txbuf_[9]);
return driver_->sendControlPacket(0x21, 9, 0x201, 0, 48, txbuf_);
return driver_->sendControlPacket(0x21, 9, 0x201, 0, 48, txbuf_);
} else if (btdriver_) { } else if (btdriver_) {
txbuf_[0] = 0x52; txbuf_[0] = 0x52;
txbuf_[1] = 0x1; txbuf_[1] = 0x1;


txbuf_[3] = rumble_lValue_? rumble_timeout_ : 0; txbuf_[3] = rumble_lValue_? rumble_timeout_ : 0;
txbuf_[4] = rumble_lValue_; // Small Rumble txbuf_[4] = rumble_lValue_; // Small Rumble
txbuf_[5] = rumble_rValue_? rumble_timeout_ : 0;
txbuf_[5] = rumble_rValue_? rumble_timeout_ : 0;
txbuf_[6] = rumble_rValue_; // Big rumble txbuf_[6] = rumble_rValue_; // Big rumble
txbuf_[11] = leds_[2] << 1; // RGB value
txbuf_[11] = leds_[2] << 1; // RGB value
DBGPrintf("\nJoystick update Rumble/LEDs %d %d %d %d %d\n", txbuf_[3], txbuf_[4], txbuf_[5], txbuf_[6], txbuf_[11]); DBGPrintf("\nJoystick update Rumble/LEDs %d %d %d %d %d\n", txbuf_[3], txbuf_[4], txbuf_[5], txbuf_[6], txbuf_[11]);
btdriver_->sendL2CapCommand(txbuf_, 50, BluetoothController::CONTROL_SCID); btdriver_->sendL2CapCommand(txbuf_, 50, BluetoothController::CONTROL_SCID);
return true; return true;
txbuf_[4] = leds_[2]; txbuf_[4] = leds_[2];
txbuf_[6] = rumble_lValue_; // Set the rumble value into the write buffer txbuf_[6] = rumble_lValue_; // Set the rumble value into the write buffer


//return driver_->sendControlPacket(0x21, 9, 0x201, 0, MOVE_REPORT_BUFFER_SIZE, txbuf_);
//return driver_->sendControlPacket(0x21, 9, 0x201, 0, MOVE_REPORT_BUFFER_SIZE, txbuf_);
return driver_->sendPacket(txbuf_, MOVE_REPORT_BUFFER_SIZE); return driver_->sendPacket(txbuf_, MOVE_REPORT_BUFFER_SIZE);


} else if (btdriver_) { } else if (btdriver_) {
} }


//***************************************************************************** //*****************************************************************************
// Support for Joysticks that Use HID data.
// Support for Joysticks that Use HID data.
//***************************************************************************** //*****************************************************************************


hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage) hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
mydevice = dev; mydevice = dev;
collections_claimed++; collections_claimed++;
anychange = true; // always report values on first read anychange = true; // always report values on first read
driver_ = driver; // remember the driver.
driver_ = driver; // remember the driver.
driver_->setTXBuffers(txbuf_, nullptr, sizeof(txbuf_)); driver_->setTXBuffers(txbuf_, nullptr, sizeof(txbuf_));
connected_ = true; // remember that hardware is actually connected... connected_ = true; // remember that hardware is actually connected...


additional_axis_usage_page_ = 0x1; additional_axis_usage_page_ = 0x1;
additional_axis_usage_start_ = 0x100; additional_axis_usage_start_ = 0x100;
additional_axis_usage_count_ = 39; additional_axis_usage_count_ = 39;
axis_change_notify_mask_ = (uint64_t)-1; // Start off assume all bits
axis_change_notify_mask_ = (uint64_t)-1; // Start off assume all bits
break; break;
case PS4: case PS4:
additional_axis_usage_page_ = 0xFF00; additional_axis_usage_page_ = 0xFF00;
additional_axis_usage_count_ = 54; additional_axis_usage_count_ = 54;
axis_change_notify_mask_ = (uint64_t)0xfffffffffffff3ffl; // Start off assume all bits - 10 and 11 axis_change_notify_mask_ = (uint64_t)0xfffffffffffff3ffl; // Start off assume all bits - 10 and 11
break; break;
default:
default:
additional_axis_usage_page_ = 0x09; additional_axis_usage_page_ = 0x09;
additional_axis_usage_start_ = 0x21; additional_axis_usage_start_ = 0x21;
additional_axis_usage_count_ = 5; additional_axis_usage_count_ = 5;
if (--collections_claimed == 0) { if (--collections_claimed == 0) {
mydevice = NULL; mydevice = NULL;
driver_ = nullptr; driver_ = nullptr;
axis_mask_ = 0;
axis_mask_ = 0;
axis_changed_mask_ = 0; axis_changed_mask_ = 0;
} }
} }
// see if the usage is witin range. // see if the usage is witin range.
//DBGPrintf("UP: usage_page=%x usage=%x User: %x %d\n", usage_page, usage, user_buttons_usage_start, user_buttons_count_); //DBGPrintf("UP: usage_page=%x usage=%x User: %x %d\n", usage_page, usage, user_buttons_usage_start, user_buttons_count_);
if ((usage >= additional_axis_usage_start_) && (usage < (additional_axis_usage_start_ + additional_axis_usage_count_))) { if ((usage >= additional_axis_usage_start_) && (usage < (additional_axis_usage_start_ + additional_axis_usage_count_))) {
// We are in the user range.
// We are in the user range.
uint16_t usage_index = usage - additional_axis_usage_start_ + STANDARD_AXIS_COUNT; uint16_t usage_index = usage - additional_axis_usage_start_ + STANDARD_AXIS_COUNT;
if (usage_index < (sizeof(axis)/sizeof(axis[0]))) { if (usage_index < (sizeof(axis)/sizeof(axis[0]))) {
if (axis[usage_index] != value) { if (axis[usage_index] != value) {
if (usage_index > 63) usage_index = 63; // don't overflow our mask if (usage_index > 63) usage_index = 63; // don't overflow our mask
axis_changed_mask_ |= ((uint64_t)1 << usage_index); // Keep track of which ones changed. axis_changed_mask_ |= ((uint64_t)1 << usage_index); // Keep track of which ones changed.
if (axis_changed_mask_ & axis_change_notify_mask_) if (axis_changed_mask_ & axis_change_notify_mask_)
anychange = true; // We have changes...
anychange = true; // We have changes...
} }
axis_mask_ |= ((uint64_t)1 << usage_index); // Keep record of which axis we have data on. axis_mask_ |= ((uint64_t)1 << usage_index); // Keep record of which axis we have data on.
} }
} }
} }


bool JoystickController::hid_process_out_data(const Transfer_t *transfer)
bool JoystickController::hid_process_out_data(const Transfer_t *transfer)
{ {
//DBGPrintf("JoystickController::hid_process_out_data\n"); //DBGPrintf("JoystickController::hid_process_out_data\n");
return true; return true;


//***************************************************************************** //*****************************************************************************
// Support for Joysticks that are class specific and do not use HID // Support for Joysticks that are class specific and do not use HID
// Example: XBox One controller.
// Example: XBox One controller.
//***************************************************************************** //*****************************************************************************


static uint8_t xboxone_start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00}; static uint8_t xboxone_start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true); JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true);
println("Jtype=", (uint8_t)jtype, DEC); println("Jtype=", (uint8_t)jtype, DEC);
if (jtype == UNKNOWN) if (jtype == UNKNOWN)
return false;
return false;


// XBOX One // XBOX One
// 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.
// 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.


// XBOX 360 wireless... Has 8 interfaces. 4 joysticks (1, 3, 5, 7) and 4 headphones assume 2,4,6, 8...
// Shows data for #1 only...
// XBOX 360 wireless... Has 8 interfaces. 4 joysticks (1, 3, 5, 7) and 4 headphones assume 2,4,6, 8...
// Shows data for #1 only...
// Also they have some unknown data type we need to ignore between interface and end points. // Also they have some unknown data type we need to ignore between interface and end points.
// 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
// 09 04 00 00 02 FF 5D 81 00 14 22 00 01 13 81 1D 00 17 01 02 08 13 01 0C 00 0C 01 02 08
// 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
// 09 04 00 00 02 FF 5D 81 00 14 22 00 01 13 81 1D 00 17 01 02 08 13 01 0C 00 0C 01 02 08


// 29 30 1 2 3 4 5 6 7 8 9 40 41 42 // 29 30 1 2 3 4 5 6 7 8 9 40 41 42
// 07 05 81 03 20 00 01 07 05 01 03 20 00 08
// 07 05 81 03 20 00 01 07 05 01 03 20 00 08


// Switch // Switch
// 09 04 00 00 02 FF 5D 01 00
// 10 21 10 01 01 24 81 14 03 00 03 13 02 00 03 00
// 07 05 81 03 20 00 08
// 07 05 02 03 20 00 08
// 09 04 00 00 02 FF 5D 01 00
// 10 21 10 01 01 24 81 14 03 00 03 13 02 00 03 00
// 07 05 81 03 20 00 08
// 07 05 02 03 20 00 08






uint8_t tx_interval = 0; uint8_t tx_interval = 0;
rx_size_ = 0; rx_size_ = 0;
tx_size_ = 0; tx_size_ = 0;
uint32_t descriptor_index = 9;
uint32_t descriptor_index = 9;
if (descriptors[descriptor_index+1] == 0x22) { if (descriptors[descriptor_index+1] == 0x22) {
if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions... if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions...
descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup... descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup...
}
}
while ((rx_ep_ == 0) || txep == 0) { while ((rx_ep_ == 0) || txep == 0) {
print(" Index:", descriptor_index, DEC); print(" Index:", descriptor_index, DEC);


if ((descriptors[descriptor_index+3] == 3) // Type 3... if ((descriptors[descriptor_index+3] == 3) // Type 3...
&& (descriptors[descriptor_index+4] <= 64) && (descriptors[descriptor_index+4] <= 64)
&& (descriptors[descriptor_index+5] == 0)) { && (descriptors[descriptor_index+5] == 0)) {
// have a bulk EP size
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) { if (descriptors[descriptor_index+2] & 0x80 ) {
rx_ep_ = descriptors[descriptor_index+2]; rx_ep_ = descriptors[descriptor_index+2];
rx_size_ = descriptors[descriptor_index+4]; rx_size_ = descriptors[descriptor_index+4];
rx_interval = descriptors[descriptor_index+6]; rx_interval = descriptors[descriptor_index+6];
} else { } else {
txep = descriptors[descriptor_index+2];
txep = descriptors[descriptor_index+2];
tx_size_ = descriptors[descriptor_index+4]; tx_size_ = descriptors[descriptor_index+4];
tx_interval = descriptors[descriptor_index+6]; tx_interval = descriptors[descriptor_index+6];
} }
queue_Data_Transfer(txpipe_, switch_start_input, sizeof(switch_start_input), this); queue_Data_Transfer(txpipe_, switch_start_input, sizeof(switch_start_input), this);
connected_ = true; // remember that hardware is actually connected... connected_ = true; // remember that hardware is actually connected...
} }
memset(axis, 0, sizeof(axis)); // clear out any data.
joystickType_ = jtype; // remember we are an XBox One.
memset(axis, 0, sizeof(axis)); // clear out any data.
joystickType_ = jtype; // remember we are an XBox One.
DBGPrintf(" JoystickController::claim joystickType_ %d\n", joystickType_); DBGPrintf(" JoystickController::claim joystickType_ %d\n", joystickType_);
return true; return true;
} }
/************************************************************/ /************************************************************/
// Interrupt-based Data Movement // Interrupt-based Data Movement
// XBox one input data when type == 0x20 // XBox one input data when type == 0x20
// Information came from several places on the web including:
// Information came from several places on the web including:
// https://github.com/quantus/xbox-one-controller-protocol // https://github.com/quantus/xbox-one-controller-protocol
/************************************************************/ /************************************************************/
// 20 00 C5 0E 00 00 00 00 00 00 F0 06 AD FB 7A 0A DD F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // 20 00 C5 0E 00 00 00 00 00 00 F0 06 AD FB 7A 0A DD F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
uint8_t type; uint8_t type;
uint8_t const_0; uint8_t const_0;
uint16_t id; uint16_t id;
// From online references button order:
// From online references button order:
// sync, dummy, start, back, a, b, x, y // sync, dummy, start, back, a, b, x, y
// dpad up, down left, right // dpad up, down left, right
// lb, rb, left stick, right stick // lb, rb, left stick, right stick
// Axis:
// Axis:
// lt, rt, lx, ly, rx, ry // lt, rt, lx, ly, rx, ry
//
uint16_t buttons;
//
uint16_t buttons;
int16_t axis[6]; int16_t axis[6];
} xbox1data20_t; } xbox1data20_t;


uint8_t id_or_type; uint8_t id_or_type;
uint16_t controller_status; uint16_t controller_status;
uint16_t unknown; uint16_t unknown;
// From online references button order:
// From online references button order:
// sync, dummy, start, back, a, b, x, y // sync, dummy, start, back, a, b, x, y
// dpad up, down left, right // dpad up, down left, right
// lb, rb, left stick, right stick // lb, rb, left stick, right stick
// Axis:
// Axis:
// lt, rt, lx, ly, rx, ry // lt, rt, lx, ly, rx, ry
// //
uint16_t buttons;
uint16_t buttons;
uint8_t lt; uint8_t lt;
uint8_t rt; uint8_t rt;
int16_t axis[4]; int16_t axis[4];
typedef struct { typedef struct {
uint8_t state; uint8_t state;
uint8_t id_or_type; uint8_t id_or_type;
// From online references button order:
// From online references button order:
// sync, dummy, start, back, a, b, x, y // sync, dummy, start, back, a, b, x, y
// dpad up, down left, right // dpad up, down left, right
// lb, rb, left stick, right stick // lb, rb, left stick, right stick
// Axis:
// Axis:
// lt, rt, lx, ly, rx, ry // lt, rt, lx, ly, rx, ry
// //
uint8_t buttons_h;
uint8_t buttons_l;
uint8_t buttons_h;
uint8_t buttons_l;
uint8_t lt; uint8_t lt;
uint8_t rt; uint8_t rt;
int16_t axis[4]; int16_t axis[4];


if (joystickType_ == XBOXONE) { if (joystickType_ == XBOXONE) {
// Process XBOX One data // Process XBOX One data
axis_mask_ = 0x3f;
axis_mask_ = 0x3f;
axis_changed_mask_ = 0; // assume none for now axis_changed_mask_ = 0; // assume none for now
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer; xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer;
if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) { if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) {
println(" Button Change: ", buttons, HEX); println(" Button Change: ", buttons, HEX);
} }
for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) { for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) {
// The first two values were unsigned.
// The first two values were unsigned.
int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i]; int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i];
if (axis_value != axis[xbox_axis_order_mapping[i]]) { if (axis_value != axis[xbox_axis_order_mapping[i]]) {
axis[xbox_axis_order_mapping[i]] = axis_value; axis[xbox_axis_order_mapping[i]] = axis_value;
} }


} else if (joystickType_ == XBOX360) { } else if (joystickType_ == XBOX360) {
// First byte appears to status - if the byte is 0x8 it is a connect or disconnect of the controller.
// First byte appears to status - if the byte is 0x8 it is a connect or disconnect of the controller.
xbox360data_t *xb360d = (xbox360data_t *)transfer->buffer; xbox360data_t *xb360d = (xbox360data_t *)transfer->buffer;
if (xb360d->state == 0x08) { if (xb360d->state == 0x08) {
if (xb360d->id_or_type != connected_) { if (xb360d->id_or_type != connected_) {
connected_ = xb360d->id_or_type; // remember it...
connected_ = xb360d->id_or_type; // remember it...
if (connected_) { if (connected_) {
println("XBox360w - Connected type:", connected_, HEX); println("XBox360w - Connected type:", connected_, HEX);
// rx_ep_ should be 1, 3, 5, 7 for the wireless convert to 2-5 on led // rx_ep_ should be 1, 3, 5, 7 for the wireless convert to 2-5 on led
//const uint8_t *pbuffer = (uint8_t*)transfer->buffer; //const uint8_t *pbuffer = (uint8_t*)transfer->buffer;
//for (uint8_t i = 0; i < transfer->length; i++) DBGPrintf("%02x ", pbuffer[i]); //for (uint8_t i = 0; i < transfer->length; i++) DBGPrintf("%02x ", pbuffer[i]);
//DBGPrintf("\n"); //DBGPrintf("\n");
if (buttons != xb360d->buttons) { if (buttons != xb360d->buttons) {
buttons = xb360d->buttons; buttons = xb360d->buttons;
anychange = true; anychange = true;
} }
axis_mask_ = 0x3f;
axis_mask_ = 0x3f;
axis_changed_mask_ = 0; // assume none for now axis_changed_mask_ = 0; // assume none for now


for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
buttons = cur_buttons; buttons = cur_buttons;
anychange = true; anychange = true;
} }
axis_mask_ = 0x3f;
axis_mask_ = 0x3f;
axis_changed_mask_ = 0; // assume none for now axis_changed_mask_ = 0; // assume none for now


for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {


void JoystickController::disconnect() void JoystickController::disconnect()
{ {
axis_mask_ = 0;
axis_mask_ = 0;
axis_changed_mask_ = 0; axis_changed_mask_ = 0;
// TODO: free resources // TODO: free resources
} }


bool JoystickController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
bool JoystickController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
{ {
// If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object // If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object
if (btdevice && (btdevice != (Device_t*)driver)) return false; if (btdevice && (btdevice != (Device_t*)driver)) return false;
if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && ((bluetooth_class & 0x3C) == 0x08)) { if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && ((bluetooth_class & 0x3C) == 0x08)) {
DBGPrintf("JoystickController::claim_bluetooth TRUE\n"); DBGPrintf("JoystickController::claim_bluetooth TRUE\n");
btdriver_ = driver; btdriver_ = driver;
btdevice = (Device_t*)driver; // remember this way
btdevice = (Device_t*)driver; // remember this way
if (remoteName) mapNameToJoystickType(remoteName); if (remoteName) mapNameToJoystickType(remoteName);
return true; return true;
} }
if ((joystickType_ == PS3) || (joystickType_ == PS3_MOTION)) { if ((joystickType_ == PS3) || (joystickType_ == PS3_MOTION)) {
DBGPrintf("JoystickController::claim_bluetooth TRUE PS3 hack...\n"); DBGPrintf("JoystickController::claim_bluetooth TRUE PS3 hack...\n");
btdriver_ = driver; btdriver_ = driver;
btdevice = (Device_t*)driver; // remember this way
special_process_required = SP_PS3_IDS; // PS3 maybe needs different IDS.
btdevice = (Device_t*)driver; // remember this way
special_process_required = SP_PS3_IDS; // PS3 maybe needs different IDS.
return true; return true;
} }
} }
} }




bool JoystickController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
bool JoystickController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
{ {
// Example data from PS4 controller // Example data from PS4 controller
//01 7e 7f 82 84 08 00 00 00 00 //01 7e 7f 82 84 08 00 00 00 00
if (length > TOTAL_AXIS_COUNT) length = TOTAL_AXIS_COUNT; // don't overflow arrays... if (length > TOTAL_AXIS_COUNT) length = TOTAL_AXIS_COUNT; // don't overflow arrays...
DBGPrintf(" Joystick Data: "); DBGPrintf(" Joystick Data: ");
for(uint16_t i =0; i < length; i++) DBGPrintf("%02x ", data[i]); for(uint16_t i =0; i < length; i++) DBGPrintf("%02x ", data[i]);
DBGPrintf("\r\n");
DBGPrintf("\r\n");
if (joystickType_ == PS3) { if (joystickType_ == PS3) {
// Quick and dirty hack to match PS3 HID data // Quick and dirty hack to match PS3 HID data
uint32_t cur_buttons = data[2] | ((uint16_t)data[3] << 8) | ((uint32_t)data[4] << 16);
uint32_t cur_buttons = data[2] | ((uint16_t)data[3] << 8) | ((uint32_t)data[4] << 16);
if (cur_buttons != buttons) { if (cur_buttons != buttons) {
buttons = cur_buttons; buttons = cur_buttons;
joystickEvent = true; // something changed. joystickEvent = true; // something changed.
axis_changed_mask_ |= (1<<5); axis_changed_mask_ |= (1<<5);
axis[5] = data[9]; axis[5] = data[9];
} }
if (axis[3] != data[18]) { if (axis[3] != data[18]) {
axis_changed_mask_ |= (1<<3); axis_changed_mask_ |= (1<<3);
axis[3] = data[18]; axis[3] = data[18];
} }
if (axis[4] != data[19]) { if (axis[4] != data[19]) {
axis_changed_mask_ |= (1<<4); axis_changed_mask_ |= (1<<4);
axis[4] = data[19]; axis[4] = data[19];
} }
// Then rest of data // Then rest of data
mask = 0x1 << 10; // setup for other bits mask = 0x1 << 10; // setup for other bits
for (uint16_t i = 10; i < length; i++ ) { for (uint16_t i = 10; i < length; i++ ) {
axis_mask_ |= mask; axis_mask_ |= mask;
if(data[i] != axis[i]) {
if(data[i] != axis[i]) {
axis_changed_mask_ |= mask; axis_changed_mask_ |= mask;
axis[i] = data[i]; axis[i] = data[i];
}
}
mask <<= 1; // shift down the mask. mask <<= 1; // shift down the mask.
} }
} else if (joystickType_ == PS3_MOTION) { } else if (joystickType_ == PS3_MOTION) {
// Quick and dirty PS3_Motion data. // Quick and dirty PS3_Motion data.
uint32_t cur_buttons = data[1] | ((uint16_t)data[2] << 8) | ((uint32_t)data[3] << 16);
uint32_t cur_buttons = data[1] | ((uint16_t)data[2] << 8) | ((uint32_t)data[3] << 16);
if (cur_buttons != buttons) { if (cur_buttons != buttons) {
buttons = cur_buttons; buttons = cur_buttons;
joystickEvent = true; // something changed. joystickEvent = true; // something changed.
} }


// Hard to know what is best here. for now just copy raw data over...
// Hard to know what is best here. for now just copy raw data over...
// will do this for now... Format of thought to be data. // will do this for now... Format of thought to be data.
// data[1-3] Buttons (mentioned 4 as well but appears to be counter // data[1-3] Buttons (mentioned 4 as well but appears to be counter
// axis[0-1] data[5] Trigger, Previous trigger value // axis[0-1] data[5] Trigger, Previous trigger value
// 8-19 - Accel: XL, XH, YL, YH, ZL, ZH, XL2, XH2, YL2, YH2, ZL2, ZH2 // 8-19 - Accel: XL, XH, YL, YH, ZL, ZH, XL2, XH2, YL2, YH2, ZL2, ZH2
// 20-31 - Gyro: Xl,Xh,Yl,Yh,Zl,Zh,Xl2,Xh2,Yl2,Yh2,Zl2,Zh2 // 20-31 - Gyro: Xl,Xh,Yl,Yh,Zl,Zh,Xl2,Xh2,Yl2,Yh2,Zl2,Zh2
// 32 - Temp High // 32 - Temp High
// 33 - Temp Low (4 bits) Maybe Magneto x High on other??
// 33 - Temp Low (4 bits) Maybe Magneto x High on other??
uint64_t mask = 0x1; uint64_t mask = 0x1;
axis_mask_ = 0; // assume bits 0, 1, 2, 5 axis_mask_ = 0; // assume bits 0, 1, 2, 5
// Then rest of data // Then rest of data
mask = 0x1 << 10; // setup for other bits mask = 0x1 << 10; // setup for other bits
for (uint16_t i = 5; i < length; i++ ) { for (uint16_t i = 5; i < length; i++ ) {
axis_mask_ |= mask; axis_mask_ |= mask;
if(data[i] != axis[i-5]) {
if(data[i] != axis[i-5]) {
axis_changed_mask_ |= mask; axis_changed_mask_ |= mask;
axis[i-5] = data[i]; axis[i-5] = data[i];
}
}
mask <<= 1; // shift down the mask. mask <<= 1; // shift down the mask.
} }




for (uint16_t i = 0; i < length; i++ ) { for (uint16_t i = 0; i < length; i++ ) {
axis_mask_ |= mask; axis_mask_ |= mask;
if(data[i] != axis[i]) {
if(data[i] != axis[i]) {
axis_changed_mask_ |= mask; axis_changed_mask_ |= mask;
axis[i] = data[i]; axis[i] = data[i];
}
}
mask <<= 1; // shift down the mask. mask <<= 1; // shift down the mask.
// DBGPrintf("%02x ", axis[i]); // DBGPrintf("%02x ", axis[i]);
} }
uint64_t mask = 0x1; uint64_t mask = 0x1;
axis_mask_ = 0; axis_mask_ = 0;
axis_changed_mask_ = 0; axis_changed_mask_ = 0;
//This moves data to be equivalent to what we see for //This moves data to be equivalent to what we see for
//data[0] = 0x01 //data[0] = 0x01
uint8_t tmp_data[length-2]; uint8_t tmp_data[length-2];
for (uint16_t i = 0; i < (length-2); i++ ) { for (uint16_t i = 0; i < (length-2); i++ ) {
tmp_data[i] = 0; tmp_data[i] = 0;
tmp_data[i] = data[i+2]; tmp_data[i] = data[i+2];
} }
/* /*
* [1] LX, [2] = LY, [3] = RX, [4] = RY * [1] LX, [2] = LY, [3] = RX, [4] = RY
* [5] combo, tri, cir, x, sqr, D-PAD (4bits, 0-3 * [5] combo, tri, cir, x, sqr, D-PAD (4bits, 0-3
tmp_data[10] = tmp_data[5] & ((1 << 4) - 1); tmp_data[10] = tmp_data[5] & ((1 << 4) - 1);
//set buttons for last 4bits in the axis[5] //set buttons for last 4bits in the axis[5]
tmp_data[5] = tmp_data[5] >> 4; tmp_data[5] = tmp_data[5] >> 4;
// Lets try mapping the DPAD buttons to high bits
// Lets try mapping the DPAD buttons to high bits
// up up/right right R DN DOWN L DN Left LUP // up up/right right R DN DOWN L DN Left LUP
static const uint32_t dpad_to_buttons[] = {0x10000, 0x30000, 0x20000, 0x60000, 0x40000, 0xC0000, 0x80000, 0x90000}; static const uint32_t dpad_to_buttons[] = {0x10000, 0x30000, 0x20000, 0x60000, 0x40000, 0xC0000, 0x80000, 0x90000};
// Quick and dirty hack to match PS4 HID data // Quick and dirty hack to match PS4 HID data
uint32_t cur_buttons = ((uint32_t)tmp_data[7] << 12) | (((uint32_t)tmp_data[6]*0x10)) | ((uint16_t)tmp_data[5] ) ; uint32_t cur_buttons = ((uint32_t)tmp_data[7] << 12) | (((uint32_t)tmp_data[6]*0x10)) | ((uint16_t)tmp_data[5] ) ;


buttons = cur_buttons; buttons = cur_buttons;
joystickEvent = true; // something changed. joystickEvent = true; // something changed.
} }
mask = 0x1; mask = 0x1;
axis_mask_ = 0x27; // assume bits 0, 1, 2, 5 axis_mask_ = 0x27; // assume bits 0, 1, 2, 5
for (uint16_t i = 0; i < 3; i++) { for (uint16_t i = 0; i < 3; i++) {
axis_changed_mask_ |= (1<<5); axis_changed_mask_ |= (1<<5);
axis[5] = tmp_data[4]; axis[5] = tmp_data[4];
} }
if (axis[3] != tmp_data[8]) { if (axis[3] != tmp_data[8]) {
axis_changed_mask_ |= (1<<3); axis_changed_mask_ |= (1<<3);
axis[3] = tmp_data[8]; axis[3] = tmp_data[8];
} }
if (axis[4] != tmp_data[9]) { if (axis[4] != tmp_data[9]) {
axis_changed_mask_ |= (1<<4); axis_changed_mask_ |= (1<<4);
axis[4] = tmp_data[9]; axis[4] = tmp_data[9];
} }
//limit for masking //limit for masking
mask = 0x1; mask = 0x1;
for (uint16_t i = 6; i < (64); i++ ) { for (uint16_t i = 6; i < (64); i++ ) {
axis_mask_ |= mask; axis_mask_ |= mask;
if(tmp_data[i] != axis[i]) {
if(tmp_data[i] != axis[i]) {
axis_changed_mask_ |= mask; axis_changed_mask_ |= mask;
axis[i] = tmp_data[i]; axis[i] = tmp_data[i];
} }
} }




bool JoystickController::remoteNameComplete(const uint8_t *remoteName)
bool JoystickController::remoteNameComplete(const uint8_t *remoteName)
{ {
// Sort of a hack, but try to map the name given from remote to a type... // Sort of a hack, but try to map the name given from remote to a type...
if (mapNameToJoystickType(remoteName)) { if (mapNameToJoystickType(remoteName)) {
case PS4: special_process_required = SP_NEED_CONNECT; break; case PS4: special_process_required = SP_NEED_CONNECT; break;
case PS3: special_process_required = SP_PS3_IDS; break; case PS3: special_process_required = SP_PS3_IDS; break;
case PS3_MOTION: special_process_required = SP_PS3_IDS; break; case PS3_MOTION: special_process_required = SP_PS3_IDS; break;
default:
default:
break; break;
} }
} }
return true; return true;
} }


void JoystickController::connectionComplete()
void JoystickController::connectionComplete()
{ {
DBGPrintf(" JoystickController::connectionComplete %x joystick type %d\n", (uint32_t)this, joystickType_); DBGPrintf(" JoystickController::connectionComplete %x joystick type %d\n", (uint32_t)this, joystickType_);
switch (joystickType_) { switch (joystickType_) {
packet[1] = 0x02; // Report ID packet[1] = 0x02; // Report ID
DBGPrintf("Set PS4 report\n"); DBGPrintf("Set PS4 report\n");
delay(1); delay(1);
btdriver_->sendL2CapCommand(packet, sizeof(packet), 0x40);
btdriver_->sendL2CapCommand(packet, sizeof(packet), 0x40);
} }
break; break;
case PS3: case PS3:
btdriver_->sendL2CapCommand(packet, sizeof(packet), BluetoothController::CONTROL_SCID); btdriver_->sendL2CapCommand(packet, sizeof(packet), BluetoothController::CONTROL_SCID);
} }
break; break;
case PS3_MOTION:
setLEDs(0, 0xff, 0); // Maybe try setting to green?
case PS3_MOTION:
setLEDs(0, 0xff, 0); // Maybe try setting to green?
default: default:
break;
break;
} }
} }


void JoystickController::release_bluetooth()
void JoystickController::release_bluetooth()
{ {
btdevice = nullptr; // remember this way
btdevice = nullptr; // remember this way
btdriver_ = nullptr; btdriver_ = nullptr;
connected_ = false; connected_ = false;
special_process_required = false; special_process_required = false;
txbuf_[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first txbuf_[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first


// bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
return driver_->sendControlPacket(0x21, 9, 0x3f5, 0, 8, txbuf_);
return driver_->sendControlPacket(0x21, 9, 0x3f5, 0, 8, txbuf_);
} else if (joystickType_ == PS3_MOTION) { } else if (joystickType_ == PS3_MOTION) {
// Slightly different than other PS3 units... // Slightly different than other PS3 units...
txbuf_[0] = 0x05; txbuf_[0] = 0x05;
txbuf_[9] = 0x02; txbuf_[9] = 0x02;
txbuf_[10] = 0x12; txbuf_[10] = 0x12;
// bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
return driver_->sendControlPacket(0x21, 9, 0x305, 0, 11, txbuf_);
return driver_->sendControlPacket(0x21, 9, 0x305, 0, 11, txbuf_);
} }
return false; return false;
} }

keyboard.cpp → src/keyboard.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include "keylayouts.h" // from Teensyduino core library
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info
#include "core/keylayouts.h" // from Teensyduino core library


typedef struct { typedef struct {
KEYCODE_TYPE code; KEYCODE_TYPE code;


typedef struct { typedef struct {
uint16_t idVendor; // vendor id of keyboard uint16_t idVendor; // vendor id of keyboard
uint16_t idProduct; // product id - 0 implies all of the ones from vendor;
uint16_t idProduct; // product id - 0 implies all of the ones from vendor;
} keyboard_force_boot_protocol_t; // list of products to force into boot protocol } keyboard_force_boot_protocol_t; // list of products to force into boot protocol


#ifdef M #ifdef M
{M(KEY_LEFT), KEYD_LEFT }, {M(KEY_LEFT), KEYD_LEFT },
{M(KEY_RIGHT), KEYD_RIGHT }, {M(KEY_RIGHT), KEYD_RIGHT },
{M(KEY_INSERT), KEYD_INSERT }, {M(KEY_INSERT), KEYD_INSERT },
{M(KEY_DELETE), KEYD_DELETE },
{M(KEY_DELETE), KEYD_DELETE },
{M(KEY_PAGE_UP), KEYD_PAGE_UP }, {M(KEY_PAGE_UP), KEYD_PAGE_UP },
{M(KEY_PAGE_DOWN), KEYD_PAGE_DOWN },
{M(KEY_PAGE_DOWN), KEYD_PAGE_DOWN },
{M(KEY_HOME), KEYD_HOME }, {M(KEY_HOME), KEYD_HOME },
{M(KEY_END), KEYD_END },
{M(KEY_END), KEYD_END },
{M(KEY_F1), KEYD_F1 }, {M(KEY_F1), KEYD_F1 },
{M(KEY_F2), KEYD_F2 },
{M(KEY_F3), KEYD_F3 },
{M(KEY_F4), KEYD_F4 },
{M(KEY_F5), KEYD_F5 },
{M(KEY_F6), KEYD_F6 },
{M(KEY_F7), KEYD_F7 },
{M(KEY_F8), KEYD_F8 },
{M(KEY_F9), KEYD_F9 },
{M(KEY_F10), KEYD_F10 },
{M(KEY_F11), KEYD_F11 },
{M(KEY_F12), KEYD_F12 }
{M(KEY_F2), KEYD_F2 },
{M(KEY_F3), KEYD_F3 },
{M(KEY_F4), KEYD_F4 },
{M(KEY_F5), KEYD_F5 },
{M(KEY_F6), KEYD_F6 },
{M(KEY_F7), KEYD_F7 },
{M(KEY_F8), KEYD_F8 },
{M(KEY_F9), KEYD_F9 },
{M(KEY_F10), KEYD_F10 },
{M(KEY_F11), KEYD_F11 },
{M(KEY_F12), KEYD_F12 }
}; };


// Some of these mapped to key + shift. // Some of these mapped to key + shift.
uint32_t size = descriptors[22] | (descriptors[23] << 8); uint32_t size = descriptors[22] | (descriptors[23] << 8);
println("packet size = ", size); println("packet size = ", size);
if ((size < 8) || (size > 64)) { if ((size < 8) || (size > 64)) {
return false; // Keyboard Boot Protocol is 8 bytes, but maybe others have longer...
return false; // Keyboard Boot Protocol is 8 bytes, but maybe others have longer...
} }
#ifdef USBHS_KEYBOARD_INTERVAL
#ifdef USBHS_KEYBOARD_INTERVAL
uint32_t interval = USBHS_KEYBOARD_INTERVAL; uint32_t interval = USBHS_KEYBOARD_INTERVAL;
#else #else
uint32_t interval = descriptors[24]; uint32_t interval = descriptors[24];
if (device && !control_queued) { if (device && !control_queued) {
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT
control_queued = true; control_queued = true;
queue_Control_Transfer(device, &setup, NULL, this);
queue_Control_Transfer(device, &setup, NULL, this);
} else { } else {
force_boot_protocol = true; // let system know we want to force this. force_boot_protocol = true; // let system know we want to force this.
} }
} }
} }


// Check for any of our mapped extra keys - Done early as some of these keys are
// Check for any of our mapped extra keys - Done early as some of these keys are
// above and some below the SHIFT_MASK value // above and some below the SHIFT_MASK value
for (uint8_t i = 0; i < (sizeof(keycode_extras)/sizeof(keycode_extras[0])); i++) { for (uint8_t i = 0; i < (sizeof(keycode_extras)/sizeof(keycode_extras[0])); i++) {
if (keycode_extras[i].code == key) { if (keycode_extras[i].code == key) {
mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds
queue_Control_Transfer(device, &setup, &leds_.byte, this); queue_Control_Transfer(device, &setup, &leds_.byte, this);
} else { } else {
// Bluetooth, need to setup back channel to Bluetooth controller.
// Bluetooth, need to setup back channel to Bluetooth controller.
} }
} }


{ {
// Lets try to claim a few specific Keyboard related collection/reports // Lets try to claim a few specific Keyboard related collection/reports
//USBHDBGSerial.printf("KBH Claim %x\n", topusage); //USBHDBGSerial.printf("KBH Claim %x\n", topusage);
if ((topusage != TOPUSAGE_SYS_CONTROL)
if ((topusage != TOPUSAGE_SYS_CONTROL)
&& (topusage != TOPUSAGE_CONSUMER_CONTROL) && (topusage != TOPUSAGE_CONSUMER_CONTROL)
) return CLAIM_NO; ) return CLAIM_NO;
// only claim from one physical device // only claim from one physical device
//USBHDBGSerial.println("KeyboardController claim collection"); //USBHDBGSerial.println("KeyboardController claim collection");
// Lets only claim if this is the same device as claimed Keyboard...
// Lets only claim if this is the same device as claimed Keyboard...
if (dev != device) return CLAIM_NO; if (dev != device) return CLAIM_NO;
if (mydevice != NULL && dev != mydevice) return CLAIM_NO; if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
mydevice = dev; mydevice = dev;
void KeyboardController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax) void KeyboardController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
{ {
//USBHDBGSerial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax); //USBHDBGSerial.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.
topusage_ = topusage; // remember which report we are processing.
hid_input_begin_ = true; hid_input_begin_ = true;
hid_input_data_ = false; hid_input_data_ = false;
} }


void KeyboardController::hid_input_data(uint32_t usage, int32_t value) 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;
// Hack ignore 0xff00 high words as these are user values...
if ((usage & 0xffff0000) == 0xff000000) return;
//USBHDBGSerial.printf("KeyboardController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value); //USBHDBGSerial.printf("KeyboardController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);


// See if the value is in our keys_down list // See if the value is in our keys_down list
//USBHDBGSerial.println("KPC:hid_input_end"); //USBHDBGSerial.println("KPC:hid_input_end");
if (hid_input_begin_) { if (hid_input_begin_) {


// See if we received any data from parser if not, assume all keys released...
// See if we received any data from parser if not, assume all keys released...
if (!hid_input_data_ ) { if (!hid_input_data_ ) {
if (extrasKeyReleasedFunction) { if (extrasKeyReleasedFunction) {
while (count_keys_down_) { while (count_keys_down_) {
} }


hid_input_begin_ = false; hid_input_begin_ = false;
}
}
} }


bool KeyboardController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
bool KeyboardController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
{ {
USBHDBGSerial.printf("Keyboard Controller::claim_bluetooth - Class %x\n", bluetooth_class); USBHDBGSerial.printf("Keyboard Controller::claim_bluetooth - Class %x\n", bluetooth_class);
// If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object // If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object
if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && (bluetooth_class & 0x40)) { if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && (bluetooth_class & 0x40)) {
if (remoteName && (strncmp((const char *)remoteName, "PLAYSTATION(R)3", 15) == 0)) { if (remoteName && (strncmp((const char *)remoteName, "PLAYSTATION(R)3", 15) == 0)) {
USBHDBGSerial.printf("KeyboardController::claim_bluetooth Reject PS3 hack\n"); USBHDBGSerial.printf("KeyboardController::claim_bluetooth Reject PS3 hack\n");
btdevice = nullptr; // remember this way
btdevice = nullptr; // remember this way


return false; return false;
} }
USBHDBGSerial.printf("KeyboardController::claim_bluetooth TRUE\n"); USBHDBGSerial.printf("KeyboardController::claim_bluetooth TRUE\n");
btdevice = (Device_t*)driver; // remember this way
btdevice = (Device_t*)driver; // remember this way
return true; return true;
} }
return false; return false;
} }


bool KeyboardController::remoteNameComplete(const uint8_t *remoteName)
bool KeyboardController::remoteNameComplete(const uint8_t *remoteName)
{ {
// Real Hack some PS3 controllers bluetoot class is keyboard...
// Real Hack some PS3 controllers bluetoot class is keyboard...
if (strncmp((const char *)remoteName, "PLAYSTATION(R)3", 15) == 0) { if (strncmp((const char *)remoteName, "PLAYSTATION(R)3", 15) == 0) {
USBHDBGSerial.printf(" KeyboardController::remoteNameComplete %s - Oops PS3 unclaim\n", remoteName); USBHDBGSerial.printf(" KeyboardController::remoteNameComplete %s - Oops PS3 unclaim\n", remoteName);
return false; return false;






bool KeyboardController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
bool KeyboardController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
{ {
// Example DATA from bluetooth keyboard: // Example DATA from bluetooth keyboard:
// 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7
// LEN D // LEN D
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 4 0 0 0 0 0
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0
// So Len=9 passed in data starting at report ID=1...
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 4 0 0 0 0 0
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0
// So Len=9 passed in data starting at report ID=1...
USBHDBGSerial.printf("KeyboardController::process_bluetooth_HID_data\n"); USBHDBGSerial.printf("KeyboardController::process_bluetooth_HID_data\n");
if (data[0] != 1) return false; if (data[0] != 1) return false;
print(" KB Data: "); print(" KB Data: ");
return true; return true;
} }


void KeyboardController::release_bluetooth()
void KeyboardController::release_bluetooth()
{ {
btdevice = nullptr; btdevice = nullptr;
} }
// Some simple query functions depend on which interface we are using... // Some simple query functions depend on which interface we are using...
//***************************************************************************** //*****************************************************************************


uint16_t KeyboardController::idVendor()
uint16_t KeyboardController::idVendor()
{ {
if (device != nullptr) return device->idVendor; if (device != nullptr) return device->idVendor;
if (mydevice != nullptr) return mydevice->idVendor; if (mydevice != nullptr) return mydevice->idVendor;
return 0; return 0;
} }


uint16_t KeyboardController::idProduct()
uint16_t KeyboardController::idProduct()
{ {
if (device != nullptr) return device->idProduct; if (device != nullptr) return device->idProduct;
if (mydevice != nullptr) return mydevice->idProduct; if (mydevice != nullptr) return mydevice->idProduct;
const uint8_t *KeyboardController::manufacturer() const uint8_t *KeyboardController::manufacturer()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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; return nullptr;
} }


const uint8_t *KeyboardController::product() const uint8_t *KeyboardController::product()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; 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]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
return nullptr; return nullptr;
} }


const uint8_t *KeyboardController::serialNumber() const uint8_t *KeyboardController::serialNumber()
{ {
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; 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]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->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]];
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
return nullptr; return nullptr;
} }



keyboardHIDExtras.cpp → src/keyboardHIDExtras.cpp View File


memory.cpp → src/memory.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info




// Memory allocation for Device_t, Pipe_t and Transfer_t structures. // Memory allocation for Device_t, Pipe_t and Transfer_t structures.
strbuf->iStrings[strbuf_t::STR_ID_PROD] = 0; strbuf->iStrings[strbuf_t::STR_ID_PROD] = 0;
strbuf->iStrings[strbuf_t::STR_ID_SERIAL] = 0; strbuf->iStrings[strbuf_t::STR_ID_SERIAL] = 0;
strbuf->buffer[0] = 0; // have trailing NULL.. strbuf->buffer[0] = 0; // have trailing NULL..
}
}
return strbuf; return strbuf;
} }


void USBHost::free_string_buffer(strbuf_t *strbuf)
void USBHost::free_string_buffer(strbuf_t *strbuf)
{ {
*(strbuf_t **)strbuf = free_strbuf_list; *(strbuf_t **)strbuf = free_strbuf_list;
free_strbuf_list = strbuf; free_strbuf_list = strbuf;

midi.cpp → src/midi.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_

mouse.cpp → src/mouse.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info




void MouseController::init() void MouseController::init()
} }




bool MouseController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
bool MouseController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class, uint8_t *remoteName)
{ {
// How to handle combo devices?
// How to handle combo devices?
USBHDBGSerial.printf("MouseController Controller::claim_bluetooth - Class %x\n", bluetooth_class); USBHDBGSerial.printf("MouseController Controller::claim_bluetooth - Class %x\n", bluetooth_class);
// If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object // If we are already in use than don't grab another one. Likewise don't grab if it is used as USB or HID object
if (btdevice && (btdevice != (Device_t*)driver)) return false; if (btdevice && (btdevice != (Device_t*)driver)) return false;
if (mydevice != NULL) return false; if (mydevice != NULL) return false;
if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && (bluetooth_class & 0x80)) { if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && (bluetooth_class & 0x80)) {
USBHDBGSerial.printf("MouseController::claim_bluetooth TRUE\n"); USBHDBGSerial.printf("MouseController::claim_bluetooth TRUE\n");
btdevice = (Device_t*)driver; // remember this way
btdevice = (Device_t*)driver; // remember this way
return true; return true;
} }
return false; return false;
} }


bool MouseController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
bool MouseController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length)
{ {
// Example DATA from bluetooth keyboard: // Example DATA from bluetooth keyboard:
// 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7
// LEN D // LEN D
//BT rx2_data(14): b 20 a 0 6 0 71 0 a1 2 0 9 fe 0
//BT rx2_data(14): b 20 a 0 6 0 71 0 a1 2 0 8 fd 0
//BT rx2_data(14): b 20 a 0 6 0 71 0 a1 2 0 9 fe 0
//BT rx2_data(14): b 20 a 0 6 0 71 0 a1 2 0 8 fd 0


// So Len=9 passed in data starting at report ID=1...
// So Len=9 passed in data starting at report ID=1...
if (length == 0) return false; if (length == 0) return false;
#ifdef USBHOST_PRINT_DEBUG #ifdef USBHOST_PRINT_DEBUG
USBHDBGSerial.printf("MouseController::process_bluetooth_HID_data %d\n", length); USBHDBGSerial.printf("MouseController::process_bluetooth_HID_data %d\n", length);
USBHDBGSerial.print(' '); USBHDBGSerial.print(' ');
} while (--len); } while (--len);
USBHDBGSerial.println(); USBHDBGSerial.println();
#endif
#endif
// Looks like report 2 is for the mouse info. // Looks like report 2 is for the mouse info.
if (data[0] != 2) return false; if (data[0] != 2) return false;
buttons = data[1]; buttons = data[1];
return true; return true;
} }


void MouseController::release_bluetooth()
void MouseController::release_bluetooth()
{ {
btdevice = nullptr; btdevice = nullptr;
}
}

print.cpp → src/print.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


// Printing of specific data structures. When this is enabled, // Printing of specific data structures. When this is enabled,
// a tremendous amount of debug printing occurs. It's done all // a tremendous amount of debug printing occurs. It's done all

rawhid.cpp → src/rawhid.cpp View File

* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


void RawHIDController::init() void RawHIDController::init()
{ {
USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); USBHost::contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
USBHIDParser::driver_ready_for_hid_collection(this);
USBHIDParser::driver_ready_for_hid_collection(this);
} }


hidclaim_t RawHIDController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage) hidclaim_t RawHIDController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
mydevice = dev; mydevice = dev;
collections_claimed++; collections_claimed++;
usage_ = topusage; usage_ = topusage;
driver_ = driver; // remember the driver.
driver_ = driver; // remember the driver.
return CLAIM_INTERFACE; // We wa return CLAIM_INTERFACE; // We wa
} }


} }
} }


bool RawHIDController::hid_process_in_data(const Transfer_t *transfer)
bool RawHIDController::hid_process_in_data(const Transfer_t *transfer)
{ {
#ifdef USBHOST_PRINT_DEBUG #ifdef USBHOST_PRINT_DEBUG
USBHDBGSerial.printf("RawHIDController::hid_process_in_data: %x\n", usage_); USBHDBGSerial.printf("RawHIDController::hid_process_in_data: %x\n", usage_);
return true; return true;
} }


bool RawHIDController::hid_process_out_data(const Transfer_t *transfer)
bool RawHIDController::hid_process_out_data(const Transfer_t *transfer)
{ {
#ifdef USBHOST_PRINT_DEBUG #ifdef USBHOST_PRINT_DEBUG
USBHDBGSerial.printf("RawHIDController::hid_process_out_data: %x\n", usage_); USBHDBGSerial.printf("RawHIDController::hid_process_out_data: %x\n", usage_);
return true; return true;
} }


bool RawHIDController::sendPacket(const uint8_t *buffer)
bool RawHIDController::sendPacket(const uint8_t *buffer)
{ {
if (!driver_) return false; if (!driver_) return false;
return driver_->sendPacket(buffer); return driver_->sendPacket(buffer);

serial.cpp → src/serial.cpp View File

* Note: special thanks to the Linux kernel for the CH341's method of operation, particularly how the baud rate is encoded. * Note: special thanks to the Linux kernel for the CH341's method of operation, particularly how the baud rate is encoded.
*/ */


#include <Arduino.h>
#include "USBHost_t36.h" // Read this header first for key info
#include <core/Arduino.h>
#include "usbhost/usbhost.h" // Read this header first for key info


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_
// Define mapping VID/PID - to Serial Device type. // Define mapping VID/PID - to Serial Device type.
/************************************************************/ /************************************************************/
USBSerialBase::product_vendor_mapping_t USBSerialBase::pid_vid_mapping[] = { USBSerialBase::product_vendor_mapping_t USBSerialBase::pid_vid_mapping[] = {
// FTDI mappings.
// FTDI mappings.
{0x0403, 0x6001, USBSerialBase::FTDI, 0}, {0x0403, 0x6001, USBSerialBase::FTDI, 0},
{0x0403, 0x8088, USBSerialBase::FTDI, 1}, // 2 devices try to claim at interface level {0x0403, 0x8088, USBSerialBase::FTDI, 1}, // 2 devices try to claim at interface level


// PL2303 // PL2303
{0x67B,0x2303, USBSerialBase::PL2303, 0},
{0x67B,0x2303, USBSerialBase::PL2303, 0},


// CH341 // CH341
{0x4348, 0x5523, USBSerialBase::CH341, 0}, {0x4348, 0x5523, USBSerialBase::CH341, 0},
if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) { if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) {
if (type != 0) return false; if (type != 0) return false;


// It is a communication device see if we can extract the data...
// Try some ttyACM types?
// This code may be similar to MIDI code.
// It is a communication device see if we can extract the data...
// Try some ttyACM types?
// This code may be similar to MIDI code.
// But first pass see if we can simply look at the interface... // But first pass see if we can simply look at the interface...
// Lets walk through end points and see if we
// Lets walk through end points and see if we
// can find an RX and TX bulk transfer end point. // can find an RX and TX bulk transfer end point.
// 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 2 3 4 5 6 7 8 *9 40 1 2 3 4 5 *6 7 8 9 50 1 2
// 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 2 3 4 5 6 7 8 *9 40 1 2 3 4 5 *6 7 8 9 50 1 2
// USB2AX // USB2AX
//09 04 00 00 01 02 02 01 00 05 24 00 10 01 04 24 02 06 05 24 06 00 01 07 05 82 03 08 00 FF 09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01 //09 04 00 00 01 02 02 01 00 05 24 00 10 01 04 24 02 06 05 24 06 00 01 07 05 82 03 08 00 FF 09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01
//09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01
//09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01
// Teensy 3.6 // Teensy 3.6
//09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03 10 00 40 09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00
//09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00
//09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03 10 00 40 09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00
//09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00
const uint8_t *p = descriptors; const uint8_t *p = descriptors;
const uint8_t *end = p + len; const uint8_t *end = p + len;


//println(" bInterfaceClass=", p[5]); //println(" bInterfaceClass=", p[5]);
//println(" bInterfaceSubClass=", p[6]); //println(" bInterfaceSubClass=", p[6]);
if (p[5] != 2) return false; // bInterfaceClass: 2 Communications if (p[5] != 2) return false; // bInterfaceClass: 2 Communications
if (p[6] != 2) return false; // bInterfaceSubClass: 2 serial
if (p[6] != 2) return false; // bInterfaceSubClass: 2 serial
p += 9; p += 9;
println(" Interface is Serial"); println(" Interface is Serial");
uint8_t rx_ep = 0; uint8_t rx_ep = 0;
uint8_t tx_ep = 0; uint8_t tx_ep = 0;
uint16_t rx_size = 0; uint16_t rx_size = 0;
uint16_t tx_size = 0; uint16_t tx_size = 0;
interface = 0; // clear out any interface numbers passed in.
interface = 0; // clear out any interface numbers passed in.


while (p < end) { while (p < end) {
len = *p; len = *p;
if (len < 4) return false;
if (len < 4) return false;
if (p + len > end) return false; // reject if beyond end of data if (p + len > end) return false; // reject if beyond end of data
uint32_t type = p[1]; uint32_t type = p[1];
//println("type: ", type); //println("type: ", type);
interface = p[2]; interface = p[2];
println(" Interface: ", interface); println(" Interface: ", interface);
} }
else if (type == 0x24) { // 0x24 = CS_INTERFACE,
else if (type == 0x24) { // 0x24 = CS_INTERFACE,
uint32_t subtype = p[2]; uint32_t subtype = p[2];
print(" CS_INTERFACE - subtype: ", subtype); print(" CS_INTERFACE - subtype: ", subtype);
if (len >= 4) print(" ", p[3], HEX); if (len >= 4) print(" ", p[3], HEX);
case 2: println(" - Abstract Control Management"); break; case 2: println(" - Abstract Control Management"); break;
case 4: println(" - Telephone Ringer"); break; case 4: println(" - Telephone Ringer"); break;
case 6: println(" - union Functional"); break; case 6: println(" - union Functional"); break;
default: println(" - ??? other"); break;
default: println(" - ??? other"); break;
} }
// First pass ignore... // First pass ignore...
} else if (type == 5) { } else if (type == 5) {
} }
break; break;
} }
}
}
if (sertype == UNKNOWN) { if (sertype == UNKNOWN) {
// Not in our list see if CDCACM type... // Not in our list see if CDCACM type...
// only at the Interface level // only at the Interface level
if (type != 1) return false; if (type != 1) return false;
// TTYACM: <Composit device>
//
// TTYACM: <Composit device>
//
// We first tried to claim a simple ttyACM device like a teensy who is configured // We first tried to claim a simple ttyACM device like a teensy who is configured
// only as Serial at the device level like what was done for midi // only as Serial at the device level like what was done for midi
// //
// However some devices are a compisit of multiple Interfaces, so see if this Interface // However some devices are a compisit of multiple Interfaces, so see if this Interface
// is of the CDC Interface class and 0 for SubClass and protocol // is of the CDC Interface class and 0 for SubClass and protocol
// Todo: some of this can maybe be combined with the Whole device code above.
// Todo: some of this can maybe be combined with the Whole device code above.
if (descriptors[0] != 9 || descriptors[1] != 4) return false; // interface descriptor if (descriptors[0] != 9 || descriptors[1] != 4) return false; // interface descriptor
if (descriptors[4] < 2) return false; // less than 2 end points if (descriptors[4] < 2) return false; // less than 2 end points
if (descriptors[5] != 0xA) return false; // bInterfaceClass, 0xa = CDC data if (descriptors[5] != 0xA) return false; // bInterfaceClass, 0xa = CDC data
if (len < 23) return false; if (len < 23) return false;
if (descriptors[0] != 9) return false; // length 9 if (descriptors[0] != 9) return false; // length 9


// Lets walk through end points and see if we
// Lets walk through end points and see if we
// can find an RX and TX bulk transfer end point. // can find an RX and TX bulk transfer end point.
//Example vid=67B, pid=2303 //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 // 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
//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


// lets see about FTD2232H // lets see about FTD2232H
//09 04 00 00 02 FF FF FF 02 07 05 81 02 00 02 00 07 05 02 02 00 02 00 09 04 01 00 02 FF FF FF 02 07 05 83 02 00 02 00 07 05 04 02 00 02 00
//09 04 01 00 02 FF FF FF 02 07 05 83 02 00 02 00 07 05 04 02 00 02 00
//09 04 00 00 02 FF FF FF 02 07 05 81 02 00 02 00 07 05 02 02 00 02 00 09 04 01 00 02 FF FF FF 02 07 05 83 02 00 02 00 07 05 04 02 00 02 00
//09 04 01 00 02 FF FF FF 02 07 05 83 02 00 02 00 07 05 04 02 00 02 00




uint32_t rxep = 0; uint32_t rxep = 0;
uint32_t txep = 0; uint32_t txep = 0;
uint16_t rx_size = 0; uint16_t rx_size = 0;
uint16_t tx_size = 0; uint16_t tx_size = 0;
uint32_t descriptor_index = 9;
uint32_t descriptor_index = 9;
while (count_end_points-- && ((rxep == 0) || txep == 0)) { while (count_end_points-- && ((rxep == 0) || txep == 0)) {
if (descriptors[descriptor_index] != 7) return false; // length 7 if (descriptors[descriptor_index] != 7) return false; // length 7
if (descriptors[descriptor_index+1] != 5) return false; // ep desc if (descriptors[descriptor_index+1] != 5) return false; // ep desc
uint16_t ep_size = descriptors[descriptor_index+4] + (uint16_t)(descriptors[descriptor_index+5] << 8); uint16_t ep_size = descriptors[descriptor_index+4] + (uint16_t)(descriptors[descriptor_index+5] << 8);
if ((descriptors[descriptor_index+3] == 2)
if ((descriptors[descriptor_index+3] == 2)
&& (ep_size <= _max_rxtx) && (ep_size >= _min_rxtx)) { && (ep_size <= _max_rxtx) && (ep_size >= _min_rxtx)) {
// have a bulk EP size
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) { if (descriptors[descriptor_index+2] & 0x80 ) {
rxep = descriptors[descriptor_index+2]; rxep = descriptors[descriptor_index+2];
rx_size = ep_size; rx_size = ep_size;
} else { } else {
txep = descriptors[descriptor_index+2];
txep = descriptors[descriptor_index+2];
tx_size = ep_size; tx_size = ep_size;
} }
} }
descriptor_index += 7; // setup to look at next one... descriptor_index += 7; // setup to look at next one...
} }
// Try to verify the end points.
// Try to verify the end points.
if (!check_rxtx_ep(rxep, txep)) return false; if (!check_rxtx_ep(rxep, txep)) return false;
print("USBSerial, rxep=", rxep & 15); print("USBSerial, rxep=", rxep & 15);
print("(", rx_size); print("(", rx_size);
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Prolific // Prolific
// TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them // TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them
case PL2303:
case PL2303:
{ {
// First attempt keep it simple...
// First attempt keep it simple...
println("PL2303: readRegister(0x04)"); println("PL2303: readRegister(0x04)");
// Need to setup the data the line coding data // Need to setup the data the line coding data
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(dev, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(dev, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 1; // We are at step one of setup...
setup_state = 1; // We are at step one of setup...
pending_control = 0x3f; pending_control = 0x3f;
return true; return true;
} }
{ {
println("CH341: 0xC0, 0x5f, 0, 0, 8"); println("CH341: 0xC0, 0x5f, 0, 0, 8");
// Need to setup the data the line coding data // 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);
mk_setup(setup, 0xC0, 0x5f, 0, 0, sizeof(setupdata));
queue_Control_Transfer(dev, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0x7f;
setup_state = 1; // We are at step one of setup...
pending_control = 0x7f;
return true; return true;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
{ {
println("CP210X: 0x41, 0x11, 0, 0, 0 - reset port"); println("CP210X: 0x41, 0x11, 0, 0, 0 - reset port");
// Need to setup the data the line coding data // Need to setup the data the line coding data
mk_setup(setup, 0x41, 0x11, 0, 0, 0);
queue_Control_Transfer(dev, &setup, NULL, this);
mk_setup(setup, 0x41, 0x11, 0, 0, 0);
queue_Control_Transfer(dev, &setup, NULL, this);
control_queued = true; control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0xf;
setup_state = 1; // We are at step one of setup...
pending_control = 0xf;
return true; return true;
} }
case CDCACM: case CDCACM:
pending_control = 0x04; // Maybe don't need to do... pending_control = 0x04; // Maybe don't need to do...
control_queued = true; control_queued = true;
return true; return true;
}
}
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// PID:VID - not in our product list.
// PID:VID - not in our product list.
default: default:
break; break;
} }
bool USBSerialBase::init_buffers(uint32_t rsize, uint32_t tsize) bool USBSerialBase::init_buffers(uint32_t rsize, uint32_t tsize)
{ {
// buffer must be able to hold 2 of each packet, plus buffer // buffer must be able to hold 2 of each packet, plus buffer
// space to hold RX and TX data.
// space to hold RX and TX data.
if (_big_buffer_size < (rsize + tsize) * 3 + 2) return false; if (_big_buffer_size < (rsize + tsize) * 3 + 2) return false;
rx1 = (uint8_t *)_bigBuffer; rx1 = (uint8_t *)_bigBuffer;
rx2 = rx1 + rsize; rx2 = rx1 + rsize;
println("control callback (serial) ", pending_control, HEX); println("control callback (serial) ", pending_control, HEX);
control_queued = false; control_queued = false;


// We will split this up by Serial type, maybe different functions?
// We will split this up by Serial type, maybe different functions?


//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// First FTDI // First FTDI
pending_control &= ~4; pending_control &= ~4;
mk_setup(setup, 0x40, 2, 0, 1, 0); mk_setup(setup, 0x40, 2, 0, 1, 0);
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
control_queued = true;
return; return;
} }
// set DTR // set DTR
switch (setup_state) { switch (setup_state) {
case 1: case 1:
println("PL2303: writeRegister(0x04, 0x00)"); println("PL2303: writeRegister(0x04, 0x00)");
mk_setup(setup, 0x40, 1, 0x0404, 0, 0); //
mk_setup(setup, 0x40, 1, 0x0404, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 2;
setup_state = 2;
control_queued = true; control_queued = true;
return; return;
case 2: case 2:
println("PL2303: readRegister(0x04)"); println("PL2303: readRegister(0x04)");
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 3;
setup_state = 3;
return; return;
case 3: case 3:
println("PL2303: v1 = readRegister(0x03)"); println("PL2303: v1 = readRegister(0x03)");
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 4;
setup_state = 4;
return; return;
case 4: case 4:
println("PL2303: readRegister(0x04)"); println("PL2303: readRegister(0x04)");
// Do we need this value long term or we could just leave in setup data?
// Do we need this value long term or we could just leave in setup data?
pl2303_v1 = setupdata[0]; // save the first bye of version pl2303_v1 = setupdata[0]; // save the first bye of version
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 5;
setup_state = 5;
return; return;
case 5: case 5:
println("PL2303: writeRegister(0x04, 0x01)"); println("PL2303: writeRegister(0x04, 0x01)");
mk_setup(setup, 0x40, 1, 0x0404, 1, 0); //
mk_setup(setup, 0x40, 1, 0x0404, 1, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 6;
setup_state = 6;
control_queued = true; control_queued = true;
return; return;
case 6: case 6:
println("PL2303: readRegister(0x04)"); println("PL2303: readRegister(0x04)");
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 7;
setup_state = 7;
return; return;
case 7: case 7:
println("PL2303: v2 = readRegister(0x03)"); println("PL2303: v2 = readRegister(0x03)");
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
setup_state = 8;
setup_state = 8;
return; return;
case 8: case 8:
pl2303_v2 = setupdata[0]; // save the first bye of version pl2303_v2 = setupdata[0]; // save the first bye of version
print(" PL2303 Version ", pl2303_v1, HEX); print(" PL2303 Version ", pl2303_v1, HEX);
println(":", pl2303_v2, HEX); println(":", pl2303_v2, HEX);
println("PL2303: writeRegister(0, 1)"); println("PL2303: writeRegister(0, 1)");
mk_setup(setup, 0x40, 1, 0, 1, 0); //
mk_setup(setup, 0x40, 1, 0, 1, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 9;
setup_state = 9;
control_queued = true; control_queued = true;
return; return;
case 9: case 9:
println("PL2303: writeRegister(1, 0)"); println("PL2303: writeRegister(1, 0)");
mk_setup(setup, 0x40, 1, 1, 0, 0); //
mk_setup(setup, 0x40, 1, 1, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 10;
setup_state = 10;
control_queued = true; control_queued = true;
return; return;
case 10: case 10:
println("PL2303: writeRegister(2, 44)"); println("PL2303: writeRegister(2, 44)");
mk_setup(setup, 0x40, 1, 2, 0x44, 0); //
mk_setup(setup, 0x40, 1, 2, 0x44, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 11;
setup_state = 11;
control_queued = true; control_queued = true;
return; return;
case 11: case 11:
println("PL2303: writeRegister(8, 0)"); println("PL2303: writeRegister(8, 0)");
mk_setup(setup, 0x40, 1, 8, 0, 0); //
mk_setup(setup, 0x40, 1, 8, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 12;
setup_state = 12;
control_queued = true; control_queued = true;
return; return;
case 12: case 12:
println("PL2303: writeRegister(9, 0)"); println("PL2303: writeRegister(9, 0)");
mk_setup(setup, 0x40, 1, 9, 0, 0); //
mk_setup(setup, 0x40, 1, 9, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 13;
setup_state = 13;
control_queued = true; control_queued = true;
return; return;
case 13: case 13:
if (pending_control & 4) { if (pending_control & 4) {
pending_control &= ~4; pending_control &= ~4;
println("PL2303: writeRegister(0, 0)"); println("PL2303: writeRegister(0, 0)");
mk_setup(setup, 0x40, 1, 0, 0, 0); //
mk_setup(setup, 0x40, 1, 0, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return;
return;
} }
if (pending_control & 8) { if (pending_control & 8) {
pending_control &= ~8; pending_control &= ~8;


// This sets the control lines (0x1=DTR, 0x2=RTS) // This sets the control lines (0x1=DTR, 0x2=RTS)
println("PL2303: 0x21, 0x22, 0x3"); println("PL2303: 0x21, 0x22, 0x3");
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
if (pending_control & 0x20) { if (pending_control & 0x20) {
pending_control &= ~0x20; pending_control &= ~0x20;
println("PL2303: 0x21, 0x22, 0x3"); println("PL2303: 0x21, 0x22, 0x3");
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
} }
if (pending_control & 0x80) { if (pending_control & 0x80) {
pending_control &= ~0x80; pending_control &= ~0x80;
println("PL2303: 0x21, 0x22, 0x0"); // Clear DTR/RTS println("PL2303: 0x21, 0x22, 0x0"); // Clear DTR/RTS
mk_setup(setup, 0x21, 0x22, 0, 0, 0); //
mk_setup(setup, 0x21, 0x22, 0, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
} }
print(" Returned: "); print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length); print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, a1, 0, 0, 0"); println("CH341: 40, a1, 0, 0, 0");
mk_setup(setup, 0x40, 0xa1, 0, 0, 0); //
mk_setup(setup, 0x40, 0xa1, 0, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 2;
setup_state = 2;
control_queued = true; control_queued = true;
return; return;
case 2: case 2:
return; return;
case 4: case 4:
println("CH341: c0, 95, 2518, 0, 8"); println("CH341: c0, 95, 2518, 0, 8");
mk_setup(setup, 0xc0, 0x95, 0x2518, 0, sizeof(setup)); //
mk_setup(setup, 0xc0, 0x95, 0x2518, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this); queue_Control_Transfer(device, &setup, setupdata, this);
setup_state = 5;
setup_state = 5;
control_queued = true; control_queued = true;
return; return;
case 5: case 5:
print(" Returned: "); print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length); print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, 0x9a, 0x2518, 0x0050, 0"); println("CH341: 40, 0x9a, 0x2518, 0x0050, 0");
mk_setup(setup, 0x40, 0x9a, 0x2518, 0x0050, 0); //
mk_setup(setup, 0x40, 0x9a, 0x2518, 0x0050, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 6;
setup_state = 6;
control_queued = true; control_queued = true;
return; return;
case 6: case 6:
println("CH341: c0, 95, 0x706, 0, 8 - get status"); println("CH341: c0, 95, 0x706, 0, 8 - get status");
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this); queue_Control_Transfer(device, &setup, setupdata, this);
setup_state = 7;
setup_state = 7;
control_queued = true; control_queued = true;
return; return;
case 7: case 7:
print(" Returned: "); print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length); print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 40, 0xa1, 0x501f, 0xd90a, 0"); println("CH341: 40, 0xa1, 0x501f, 0xd90a, 0");
mk_setup(setup, 0x40, 0xa1, 0x501f, 0xd90a, 0); //
mk_setup(setup, 0x40, 0xa1, 0x501f, 0xd90a, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
setup_state = 8;
setup_state = 8;
control_queued = true; control_queued = true;
break; break;
} }
uint16_t ch341_format; uint16_t ch341_format;
switch (format_) { switch (format_) {
default: default:
// These values were observed when used on PC... Need to flush out others.
// These values were observed when used on PC... Need to flush out others.
case USBHOST_SERIAL_8N1: ch341_format = 0xc3; break; case USBHOST_SERIAL_8N1: ch341_format = 0xc3; break;
case USBHOST_SERIAL_7E1: ch341_format = 0xda; break; case USBHOST_SERIAL_7E1: ch341_format = 0xda; break;
case USBHOST_SERIAL_7O1: ch341_format = 0xca; break; case USBHOST_SERIAL_7O1: ch341_format = 0xca; break;
case USBHOST_SERIAL_8N2: ch341_format = 0xc7; break; case USBHOST_SERIAL_8N2: ch341_format = 0xc7; break;
} }
println("CH341: 40, 0x9a, 0x2518: ", ch341_format, HEX); println("CH341: 40, 0x9a, 0x2518: ", ch341_format, HEX);
mk_setup(setup, 0x40, 0x9a, 0x2518, ch341_format, 0); //
mk_setup(setup, 0x40, 0x9a, 0x2518, ch341_format, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
if (pending_control & 0x10) { if (pending_control & 0x10) {
pending_control &= ~0x10; pending_control &= ~0x10;
// This is setting handshake need to figure out what... // This is setting handshake need to figure out what...
// 0x20=DTR, 0x40=RTS send ~ of values.
// 0x20=DTR, 0x40=RTS send ~ of values.
println("CH341: 0x40, 0xa4, 0xff9f, 0, 0 - Handshake"); println("CH341: 0x40, 0xa4, 0xff9f, 0, 0 - Handshake");
mk_setup(setup, 0x40, 0xa4, 0xff9f, 0, 0); //
mk_setup(setup, 0x40, 0xa4, 0xff9f, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
pending_control &= ~0x20; pending_control &= ~0x20;
// This is setting handshake need to figure out what... // This is setting handshake need to figure out what...
println("CH341: c0, 95, 0x706, 0, 8 - get status"); println("CH341: c0, 95, 0x706, 0, 8 - get status");
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); //
queue_Control_Transfer(device, &setup, setupdata, this); queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
return; return;
print(" Returned: "); print(" Returned: ");
print_hexbytes(transfer->buffer, transfer->length); print_hexbytes(transfer->buffer, transfer->length);
println("CH341: 0x40, 0x9a, 0x2727, 0, 0"); println("CH341: 0x40, 0x9a, 0x2727, 0, 0");
mk_setup(setup, 0x40, 0x9a, 0x2727, 0, 0); //
mk_setup(setup, 0x40, 0x9a, 0x2727, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);


return; return;
if (pending_control & 0x80) { if (pending_control & 0x80) {
pending_control &= ~0x80; pending_control &= ~0x80;
println("CH341: 0x40, 0xa4, 0xffff, 0, 0 - Handshake"); println("CH341: 0x40, 0xa4, 0xffff, 0, 0 - Handshake");
mk_setup(setup, 0x40, 0xa4, 0xffff, 0, 0); //
mk_setup(setup, 0x40, 0xa4, 0xffff, 0, 0); //
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; return;
println("CP210x 0x41, 0, 1"); println("CP210x 0x41, 0, 1");
mk_setup(setup, 0x41, 0, 1, 0, 0); mk_setup(setup, 0x41, 0, 1, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true;
control_queued = true;
return; return;
} }






println("CH341: 40, 0x9a, 0x1312... (Baud word 0):", factor, HEX); println("CH341: 40, 0x9a, 0x1312... (Baud word 0):", factor, HEX);
mk_setup(setup, 0x40, 0x9a, 0x1312, factor, 0); //
mk_setup(setup, 0x40, 0x9a, 0x1312, factor, 0); //
} else { } else {
// Second packet use the byte we saved away during the calculation above // Second packet use the byte we saved away during the calculation above
println("CH341: 40, 0x9a, 0x0f2c... (Baud word 1):", setupdata[0], HEX); println("CH341: 40, 0x9a, 0x0f2c... (Baud word 1):", setupdata[0], HEX);
mk_setup(setup, 0x40, 0x9a, 0x0f2c, setupdata[0], 0); //
mk_setup(setup, 0x40, 0x9a, 0x0f2c, setupdata[0], 0); //
} }
queue_Control_Transfer(device, &setup, setupdata, this); queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; control_queued = true;
NVIC_DISABLE_IRQ(IRQ_USBHS); NVIC_DISABLE_IRQ(IRQ_USBHS);
txtimer.stop(); // Stop longer timer. txtimer.stop(); // Stop longer timer.
txtimer.start(100); // Start a mimimal timeout txtimer.start(100); // Start a mimimal timeout
// timer_event(nullptr); // Try calling direct - fails to work
// timer_event(nullptr); // Try calling direct - fails to work
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);
while (txstate & 3) ; // wait for all of the USB packets to be sent.
while (txstate & 3) ; // wait for all of the USB packets to be sent.
println(" completed"); println(" completed");
debugDigitalWrite(32, LOW); debugDigitalWrite(32, LOW);
} }
p = tx2; p = tx2;
txstate |= 0x02; txstate |= 0x02;
} else { } else {
txstate |= 4; // Tell the TX code to do flush code.
txstate |= 4; // Tell the TX code to do flush code.
println(" *** No buffers ***"); println(" *** No buffers ***");
debugDigitalWrite(7, LOW); debugDigitalWrite(7, LOW);
return; // no outgoing buffers available, try again later return; // no outgoing buffers available, try again later


uint32_t packetsize = tx2 - tx1; uint32_t packetsize = tx2 - tx1;


// Possible for remaining ? packet size and not have both?
// Possible for remaining ? packet size and not have both?
if (count > packetsize) { if (count > packetsize) {
txstate |= 4; // One of the active transfers will handle the remaining parts txstate |= 4; // One of the active transfers will handle the remaining parts
count = packetsize; count = packetsize;
NVIC_DISABLE_IRQ(IRQ_USBHS); NVIC_DISABLE_IRQ(IRQ_USBHS);
baudrate = baud; baudrate = baud;
bool format_changed = format != format_; bool format_changed = format != format_;
format_ = format;
format_ = format;
switch (sertype) { switch (sertype) {
default: default:
case CDCACM: pending_control |= 0x6; break; case CDCACM: pending_control |= 0x6; break;
} }
if (!control_queued) control(NULL); if (!control_queued) control(NULL);
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);
// Wait until all packets have been queued before we return to caller.
// Wait until all packets have been queued before we return to caller.
while (pending_control) { while (pending_control) {
yield(); // not sure if we want to yield or what?
yield(); // not sure if we want to yield or what?
} }
} }


if (!control_queued) control(NULL); if (!control_queued) control(NULL);
NVIC_ENABLE_IRQ(IRQ_USBHS); NVIC_ENABLE_IRQ(IRQ_USBHS);


// Wait until all packets have been queued before we return to caller.
// Wait until all packets have been queued before we return to caller.
while (pending_control) { while (pending_control) {
yield(); // not sure if we want to yield or what?
yield(); // not sure if we want to yield or what?
} }
} }



Loading…
Cancel
Save