Merge branch 'xxxajk' into arm

Conflicts:
	Usb.cpp
	Usb.h
	XBOXRECV.cpp
	adk.h
	avrpins.h
	cdcacm.h
	cdcprolific.h
	hid.h
	hidboot.h
	hidescriptorparser.cpp
	hidescriptorparser.h
	masstorage.h
	message.cpp
	parsetools.h
	usbhub.h
This commit is contained in:
Kristian Sloth Lauszus 2013-10-05 01:11:51 +02:00
commit 84bab09221
113 changed files with 6111 additions and 2909 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
*.bak
*.zip
*.rar
build/

12
.gitmodules vendored Normal file
View file

@ -0,0 +1,12 @@
[submodule "examples/testusbhostFAT/generic_storage"]
path = examples/testusbhostFAT/generic_storage
url = https://github.com/xxxajk/generic_storage
[submodule "examples/testusbhostFAT/xmem2"]
path = examples/testusbhostFAT/xmem2
url = https://github.com/xxxajk/xmem2
[submodule "examples/testusbhostFAT/Arduino_Makefile_master"]
path = examples/testusbhostFAT/Arduino_Makefile_master
url = https://github.com/xxxajk/Arduino_Makefile_master
[submodule "examples/testusbhostFAT/RTClib"]
path = examples/testusbhostFAT/RTClib
url = https://github.com/xxxajk/RTClib

197
BTD.cpp
View file

@ -16,7 +16,7 @@
*/
#include "BTD.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
const uint8_t BTD::BTD_CONTROL_PIPE = 0;
@ -25,18 +25,24 @@ const uint8_t BTD::BTD_DATAIN_PIPE = 2;
const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
BTD::BTD(USB *p) :
connectToWii(false),
pairWithWii(false),
pUsb(p), // Pointer to USB class instance - mandatory
bAddress(0), // Device address - mandatory
bNumEP(1), // If config descriptor needs to be parsed
qNextPollTime(0), // Reset NextPollTime
pollInterval(0),
bPollEnable(false) // Don't start polling before dongle is connected
{
for (uint8_t i = 0; i < BTD_MAX_ENDPOINTS; i++) {
uint8_t i;
for (i = 0; i < BTD_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
for (i = 0; i < BTD_NUMSERVICES; i++)
btService[i] = NULL;
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
@ -58,7 +64,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
@ -68,14 +74,14 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
@ -110,19 +116,18 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nsetAddr: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
#endif
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
goto Fail;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
D_PrintHex<uint8_t > (bAddress, 0x80);
#endif
delay(300); // Spec says you should wait at least 200ms
p->lowspeed = false;
//get pointer to assigned address record
@ -145,7 +150,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (rcode)
goto FailSetConfDescr;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
if (PID == PS3_PID)
Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
@ -156,25 +161,25 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
#endif
if (my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
#ifdef DEBUG
Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\n\rOr set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
#endif
} else {
if (PID == PS3_PID || PID == PS3NAVIGATION_PID)
setBdaddr(my_bdaddr); // Set internal Bluetooth address
else
setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Notify(PSTR(":"), 0x80);
}
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
}
rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
pUsb->setAddr(bAddress, 0, 0); // Reset address
Release(); // Release device
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; // Return
@ -185,9 +190,14 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
// And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
for (uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (rcode)
if (VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) {
ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Needed for the IOGEAR GBU521
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
} else {
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
}
if (rcode) // Check error code
goto FailGetConfDescr;
if (bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
break;
@ -214,7 +224,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
watingForConnection = false;
bPollEnable = true;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
#endif
}
@ -222,30 +232,40 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
#endif
goto Fail;
FailUnknownDevice:
NotifyFailUnknownDevice(VID,PID);
#ifdef DEBUG_USB_HOST
NotifyFailUnknownDevice(VID, PID);
#endif
pUsb->setAddr(bAddress, 0, 0); // Reset address
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
#endif
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -262,10 +282,10 @@ void BTD::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto
bConfNum = conf;
uint8_t index;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Interrupt In endpoint found
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
index = BTD_EVENT_PIPE;
else {
epInfo[index].bmNakPower = USB_NAK_NOWAIT;
} else {
if ((pep->bmAttributes & 0x02) == 2) // Bulk endpoint found
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
else
@ -287,17 +307,17 @@ void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
#endif
}
@ -330,7 +350,7 @@ void BTD::HCI_event_task() {
/* check the event pipe*/
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &MAX_BUFFER_SIZE, hcibuf); // input on endpoint 1
if (!rcode) // Check for errors
if (!rcode || rcode == hrNAK) // Check for errors
{
switch (hcibuf[0]) //switch on event type
{
@ -350,13 +370,13 @@ void BTD::HCI_event_task() {
case EV_COMMAND_STATUS:
if (hcibuf[2]) { // show status on serial if not OK
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
PrintHex<uint8_t > (hcibuf[2], 0x80);
D_PrintHex<uint8_t > (hcibuf[2], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[4], 0x80);
D_PrintHex<uint8_t > (hcibuf[4], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[5], 0x80);
D_PrintHex<uint8_t > (hcibuf[5], 0x80);
#endif
}
break;
@ -364,7 +384,7 @@ void BTD::HCI_event_task() {
case EV_INQUIRY_COMPLETE:
if (inquiry_counter >= 5) {
inquiry_counter = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
#endif
connectToWii = false;
@ -398,11 +418,11 @@ void BTD::HCI_event_task() {
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nClass of device: "), 0x80);
PrintHex<uint8_t > (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80);
D_PrintHex<uint8_t > (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80);
D_PrintHex<uint8_t > (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80);
D_PrintHex<uint8_t > (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80);
}
#endif
}
@ -432,7 +452,7 @@ void BTD::HCI_event_task() {
case EV_REMOTE_NAME_COMPLETE:
if (!hcibuf[2]) { // check if reading is OK
for (uint8_t i = 0; i < min(sizeof(remote_name),sizeof(hcibuf)-9); i++)
for (uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++)
remote_name[i] = hcibuf[9 + i];
hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE;
}
@ -447,29 +467,29 @@ void BTD::HCI_event_task() {
disc_bdaddr[5] = hcibuf[7];
#ifdef EXTRADEBUG
Notify(PSTR("\r\nClass of device: "), 0x80);
PrintHex<uint8_t > (hcibuf[10], 0x80);
D_PrintHex<uint8_t > (hcibuf[10], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[9], 0x80);
D_PrintHex<uint8_t > (hcibuf[9], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (hcibuf[8], 0x80);
D_PrintHex<uint8_t > (hcibuf[8], 0x80);
#endif
hci_event_flag |= HCI_FLAG_INCOMING_REQUEST;
break;
case EV_PIN_CODE_REQUEST:
if (pairWithWii) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPairing with wiimote"), 0x80);
#endif
hci_pin_code_request_reply();
} else if (btdPin != NULL) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
NotifyStr(btdPin, 0x80);
#endif
hci_pin_code_request_reply();
} else {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nNo pin was set"), 0x80);
#endif
hci_pin_code_negative_request_reply();
@ -477,7 +497,7 @@ void BTD::HCI_event_task() {
break;
case EV_LINK_KEY_REQUEST:
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived Key Request"), 0x80);
#endif
hci_link_key_request_negative_reply();
@ -485,7 +505,7 @@ void BTD::HCI_event_task() {
case EV_AUTHENTICATION_COMPLETE:
if (pairWithWii && !connectToWii) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPairing successful"), 0x80);
#endif
connectToWii = true; // Only send the ACL data to the Wii service
@ -508,16 +528,16 @@ void BTD::HCI_event_task() {
default:
if (hcibuf[0] != 0x00) {
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
PrintHex<uint8_t > (hcibuf[0], 0x80);
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
}
break;
#endif
} // switch
}
#ifdef EXTRADEBUG
else if (rcode != hrNAK) {
else {
Notify(PSTR("\r\nHCI event error: "), 0x80);
PrintHex<uint8_t > (rcode, 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
}
#endif
HCI_task();
@ -539,7 +559,7 @@ void BTD::HCI_task() {
hci_counter++;
if (hci_cmd_complete) {
hci_counter = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHCI Reset complete"), 0x80);
#endif
hci_state = HCI_CLASS_STATE;
@ -548,7 +568,7 @@ void BTD::HCI_task() {
hci_num_reset_loops *= 10;
if (hci_num_reset_loops > 2000)
hci_num_reset_loops = 2000;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
#endif
hci_state = HCI_INIT_STATE;
@ -558,7 +578,7 @@ void BTD::HCI_task() {
case HCI_CLASS_STATE:
if (hci_cmd_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWrite class of device"), 0x80);
#endif
hci_state = HCI_BDADDR_STATE;
@ -568,13 +588,13 @@ void BTD::HCI_task() {
case HCI_BDADDR_STATE:
if (hci_read_bdaddr_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Notify(PSTR(":"), 0x80);
}
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
hci_read_local_version_information();
hci_state = HCI_LOCAL_VERSION_STATE;
@ -593,7 +613,7 @@ void BTD::HCI_task() {
case HCI_SET_NAME_STATE:
if (hci_cmd_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nThe name is set to: "), 0x80);
NotifyStr(btdName, 0x80);
#endif
@ -603,7 +623,7 @@ void BTD::HCI_task() {
case HCI_CHECK_WII_SERVICE:
if (pairWithWii) { // Check if it should try to connect to a wiimote
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press sync if you are using a Wii U Pro Controller"), 0x80);
#endif
hci_inquiry();
@ -615,7 +635,7 @@ void BTD::HCI_task() {
case HCI_INQUIRY_STATE:
if (hci_wii_found) {
hci_inquiry_cancel(); // Stop inquiry
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWiimote found"), 0x80);
Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
@ -631,7 +651,7 @@ void BTD::HCI_task() {
case HCI_CONNECT_WII_STATE:
if (hci_cmd_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
#endif
hci_connect();
@ -642,13 +662,13 @@ void BTD::HCI_task() {
case HCI_CONNECTED_WII_STATE:
if (hci_connect_event) {
if (hci_connect_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
#endif
hci_authentication_request(); // This will start the pairing with the wiimote
hci_state = HCI_SCANNING_STATE;
} else {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
#endif
hci_connect(); // Try to connect one more time
@ -658,7 +678,7 @@ void BTD::HCI_task() {
case HCI_SCANNING_STATE:
if (!connectToWii && !pairWithWii) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
#endif
hci_write_scan_enable();
@ -670,7 +690,7 @@ void BTD::HCI_task() {
case HCI_CONNECT_IN_STATE:
if (hci_incoming_connect_request) {
watingForConnection = false;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
#endif
hci_remote_name();
@ -681,7 +701,7 @@ void BTD::HCI_task() {
case HCI_REMOTE_NAME_STATE:
if (hci_remote_name_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRemote Name: "), 0x80);
for (uint8_t i = 0; i < 30; i++) {
if (remote_name[i] == NULL)
@ -691,16 +711,16 @@ void BTD::HCI_task() {
#endif
if (strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
incomingWii = true;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWiimote is connecting"), 0x80);
#endif
if (strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR(" with Motion Plus Inside"), 0x80);
#endif
motionPlusInside = true;
} else if (strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR(" - Wii U Pro Controller"), 0x80);
#endif
motionPlusInside = true;
@ -721,13 +741,13 @@ void BTD::HCI_task() {
case HCI_CONNECTED_STATE:
if (hci_connect_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nConnected to Device: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
Notify(PSTR(":"), 0x80);
}
PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
#endif
// Clear these flags for a new connection
l2capConnectionClaimed = false;
@ -749,7 +769,7 @@ void BTD::HCI_task() {
case HCI_DISCONNECT_STATE:
if (hci_disconnect_complete) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
#endif
hci_event_flag = 0; // Clear all flags
@ -779,7 +799,7 @@ void BTD::ACL_event_task() {
#ifdef EXTRADEBUG
else if (rcode != hrNAK) {
Notify(PSTR("\r\nACL data in error: "), 0x80);
PrintHex<uint8_t > (rcode, 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
}
#endif
for (uint8_t i = 0; i < BTD_NUMSERVICES; i++)
@ -946,15 +966,14 @@ void BTD::hci_pin_code_request_reply() {
hcibuf[8] = disc_bdaddr[5];
if (pairWithWii) {
hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
if(wiiUProController) {
#ifdef DEBUG
if (wiiUProController) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nParing with Wii U Pro Controller"), 0x80);
#endif
for(uint8_t i = 0; i < 6; i++)
for (uint8_t i = 0; i < 6; i++)
hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
}
else {
for(uint8_t i = 0; i < 6; i++)
} else {
for (uint8_t i = 0; i < 6; i++)
hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
}
for (uint8_t i = 16; i < 26; i++)
@ -1074,13 +1093,13 @@ void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
if (rcode) {
delay(100); // This small delay prevents it from overflowing if it fails
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
PrintHex<uint8_t > (rcode, 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR(" - Channel ID: "), 0x80);
PrintHex<uint8_t > (channelHigh, 0x80);
D_PrintHex<uint8_t > (channelHigh, 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (channelLow, 0x80);
D_PrintHex<uint8_t > (channelLow, 0x80);
#endif
}
}

35
BTD.h
View file

@ -19,16 +19,18 @@
#define _btd_h_
#include "Usb.h"
#include "confdescparser.h"
//PID and VID of the Sony PS3 devices
#define PS3_VID 0x054C // Sony Corporation
#define PS3_PID 0x0268 // PS3 Controller DualShock 3
#define PS3NAVIGATION_PID 0x042F // Navigation controller
#define PS3MOVE_PID 0x03D5 // Motion controller
#define PS3_VID 0x054C // Sony Corporation
#define PS3_PID 0x0268 // PS3 Controller DualShock 3
#define PS3NAVIGATION_PID 0x042F // Navigation controller
#define PS3MOVE_PID 0x03D5 // Motion controller
#define IOGEAR_GBU521_VID 0x0A5C // The IOGEAR GBU521 dongle does not presents itself correctly, so we have to check for it manually
#define IOGEAR_GBU521_PID 0x21E8
/* Bluetooth dongle data taken from descriptors */
#define BULK_MAXPKTSIZE 64 // max size for ACL data
#define BULK_MAXPKTSIZE 64 // max size for ACL data
// Used in control endpoint header for HCI Commands
#define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
@ -129,7 +131,7 @@
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
#define BTD_MAX_ENDPOINTS 4
#define BTD_NUMSERVICES 4 // Max number of Bluetooth services
#define BTD_NUMSERVICES 4 // Max number of Bluetooth services - if you need more than four simply increase this number
/** All Bluetooth services should include this class. */
class BluetoothService {
@ -194,6 +196,23 @@ public:
virtual bool isReady() {
return bPollEnable;
};
/**
* Used by the USB core to check what this driver support.
* @param klass The device's USB class.
* @return Returns true if the device's USB class matches this driver.
*/
virtual boolean DEVCLASSOK(uint8_t klass) { return (klass == USB_CLASS_WIRELESS_CTRL); }
/**
* Used by the USB core to check what this driver support.
* Used to set the Bluetooth address into the PS3 controllers.
* @param vid The device's VID.
* @param pid The device's PID.
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return ((vid == PS3_VID || vid == IOGEAR_GBU521_VID) && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID || pid == IOGEAR_GBU521_PID));
};
/**@}*/
/** @name UsbConfigXtracter implementation */
@ -450,7 +469,7 @@ private:
uint8_t hcibuf[BULK_MAXPKTSIZE]; //General purpose buffer for hci data
uint8_t l2capinbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap in data
uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap out data
uint8_t l2capoutbuf[14]; //General purpose buffer for l2cap out data
/* State machines */
void HCI_event_task(); // Poll the HCI event pipe

View file

@ -16,7 +16,7 @@
*/
#include "PS3BT.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
@ -255,7 +255,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
l2cap_state = L2CAP_WAIT;
for (uint8_t i = 0; i < 30; i++)
remote_name[i] = pBtd->remote_name[i]; // Store the remote name for the connection
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
if (pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
Notify(pBtd->hci_version, 0x80);
@ -270,32 +270,32 @@ void PS3BT::ACLData(uint8_t* ACLData) {
l2capinbuf[i] = ACLData[i];
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" Data: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
#endif
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" SCID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
Notify(PSTR(" Identifier: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
#endif
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
identifier = l2capinbuf[9];
@ -330,14 +330,14 @@ void PS3BT::ACLData(uint8_t* ACLData) {
}
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
#endif
identifier = l2capinbuf[9];
pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
Reset();
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
#endif
identifier = l2capinbuf[9];
@ -358,7 +358,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
}
#endif
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
@ -381,7 +381,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
for (uint8_t i = 10; i < 58; i++) {
PrintHex<uint8_t > (l2capinbuf[i], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
@ -397,7 +397,7 @@ void PS3BT::L2CAP_task() {
switch (l2cap_state) {
case L2CAP_WAIT:
if (l2cap_connection_request_control_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
@ -411,7 +411,7 @@ void PS3BT::L2CAP_task() {
break;
case L2CAP_CONTROL_REQUEST:
if (l2cap_config_request_control_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle, identifier, control_scid);
@ -421,7 +421,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_CONTROL_SUCCESS:
if (l2cap_config_success_control_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
#endif
l2cap_state = L2CAP_INTERRUPT_SETUP;
@ -429,7 +429,7 @@ void PS3BT::L2CAP_task() {
break;
case L2CAP_INTERRUPT_SETUP:
if (l2cap_connection_request_interrupt_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
@ -444,7 +444,7 @@ void PS3BT::L2CAP_task() {
break;
case L2CAP_INTERRUPT_REQUEST:
if (l2cap_config_request_interrupt_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle, identifier, interrupt_scid);
@ -453,15 +453,12 @@ void PS3BT::L2CAP_task() {
break;
case L2CAP_INTERRUPT_SUCCESS:
if (l2cap_config_success_interrupt_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
#endif
if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
l2capinbuf[i] = 0;
ButtonState = 0;
OldButtonState = 0;
l2cap_state = L2CAP_HID_PS3_LED;
} else
l2cap_state = L2CAP_HID_ENABLE_SIXAXIS;
@ -473,7 +470,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_INTERRUPT_DISCONNECT:
if (l2cap_disconnect_response_interrupt_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
#endif
identifier++;
@ -484,7 +481,7 @@ void PS3BT::L2CAP_task() {
case L2CAP_CONTROL_DISCONNECT:
if (l2cap_disconnect_response_control_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
#endif
pBtd->hci_disconnect(hci_handle);
@ -502,12 +499,9 @@ void PS3BT::Run() {
if (millis() - timer > 1000) { // loop 1 second before sending the command
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
l2capinbuf[i] = 0;
ButtonState = 0;
OldButtonState = 0;
enable_sixaxis();
for (uint8_t i = 15; i < 19; i++)
l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
enable_sixaxis();
l2cap_state = L2CAP_HID_PS3_LED;
timer = millis();
}
@ -516,25 +510,27 @@ void PS3BT::Run() {
case L2CAP_HID_PS3_LED:
if (millis() - timer > 1000) { // loop 1 second before sending the command
if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
setLedOn(LED1);
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
#endif
PS3Connected = true;
} else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N')
setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
#endif
PS3NavigationConnected = true;
} else if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
moveSetBulb(Red);
timerBulbRumble = millis();
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
#endif
PS3MoveConnected = true;
}
ButtonState = 0; // Clear all values
OldButtonState = 0;
ButtonClickState = 0;
onInit(); // Turn on the LED on the controller
l2cap_state = L2CAP_DONE;
}
break;
@ -650,7 +646,7 @@ void PS3BT::moveSetBulb(Colors color) { //Use this to set the Color using the pr
}
void PS3BT::moveSetRumble(uint8_t rumble) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
#endif
@ -659,3 +655,14 @@ void PS3BT::moveSetRumble(uint8_t rumble) {
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
}
void PS3BT::onInit() {
if (pFuncOnInit)
pFuncOnInit(); // Call the user function
else {
if (PS3MoveConnected)
moveSetBulb(Red);
else // Dualshock 3 or Navigation controller
setLedOn(LED1);
}
}

26
PS3BT.h
View file

@ -207,19 +207,35 @@ public:
* @param rumble The desired value in the range from 64-255.
*/
void moveSetRumble(uint8_t rumble);
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/** Variable used to indicate if the normal playstation controller is successfully connected. */
/** Variable used to indicate if the normal Playstation controller is successfully connected. */
bool PS3Connected;
/** Variable used to indicate if the move controller is successfully connected. */
/** Variable used to indicate if the Move controller is successfully connected. */
bool PS3MoveConnected;
/** Variable used to indicate if the navigation controller is successfully connected. */
/** Variable used to indicate if the Navigation controller is successfully connected. */
bool PS3NavigationConnected;
private:
/* mandatory members */
/* Mandatory members */
BTD *pBtd;
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
*/
void onInit();
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
void L2CAP_task(); // L2CAP state machine
/* Variables filled from HCI event management */
@ -229,7 +245,7 @@ private:
/* variables used by high level L2CAP task */
uint8_t l2cap_state;
uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events
uint16_t l2cap_event_flag; // L2CAP flags of received Bluetooth events
unsigned long timer;

View file

@ -16,7 +16,7 @@
*/
#include "PS3USB.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
@ -58,7 +58,7 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
@ -68,14 +68,14 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
@ -118,16 +118,18 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nsetAddr: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
#endif
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
D_PrintHex<uint8_t > (bAddress, 0x80);
#endif
delay(300); // Spec says you should wait at least 200ms
p->lowspeed = false;
//get pointer to assigned address record
@ -173,20 +175,17 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
if (PID == PS3_PID) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
#endif
PS3Connected = true;
} else { // must be a navigation controller
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
#endif
PS3NavigationConnected = true;
}
/* Set internal bluetooth address and request for data */
setBdaddr(my_bdaddr);
enable_sixaxis();
setLedOn(LED1);
enable_sixaxis(); // The PS3 controller needs a special command before it starts sending data
// Needed for PS3 Dualshock and Navigation commands to work
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
@ -195,24 +194,28 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
for (uint8_t i = 6; i < 10; i++)
readBuf[i] = 0x7F; // Set the analog joystick values to center position
} else { // must be a Motion controller
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
#endif
PS3MoveConnected = true;
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
moveSetBulb(Red);
writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work
}
if (my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) {
if (PS3MoveConnected)
setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
else
setBdaddr(my_bdaddr); // Set internal Bluetooth address
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Notify(PSTR(":"), 0x80);
}
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
for (int8_t i = 5; i > 0; i--) {
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
Notify(PSTR(":"), 0x80);
}
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
}
onInit();
bPollEnable = true;
Notify(PSTR("\r\n"), 0x80);
@ -221,25 +224,32 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
#endif
goto Fail;
FailUnknownDevice:
NotifyFailUnknownDevice(VID,PID);
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
#ifdef DEBUG_USB_HOST
NotifyFailUnknownDevice(VID, PID);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -298,7 +308,7 @@ void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the repo
if (readBuf == NULL)
return;
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
@ -427,7 +437,7 @@ void PS3USB::setRumbleOff() {
void PS3USB::setRumbleOn(Rumble mode) {
if ((mode & 0x30) > 0x00) {
uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
if (mode == RumbleHigh) {
power[0] = 0x00;
power[1] = 0xff;
@ -448,14 +458,17 @@ void PS3USB::setLedRaw(uint8_t value) {
writeBuf[9] = value << 1;
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedOff(LED a) {
writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedOn(LED a) {
writeBuf[9] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedToggle(LED a) {
writeBuf[9] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
@ -503,7 +516,7 @@ void PS3USB::moveSetBulb(Colors color) { //Use this to set the Color using the p
}
void PS3USB::moveSetRumble(uint8_t rumble) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
#endif
@ -528,3 +541,14 @@ void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
}
void PS3USB::onInit() {
if (pFuncOnInit)
pFuncOnInit(); // Call the user function
else {
if (PS3MoveConnected)
moveSetBulb(Red);
else // Dualshock 3 or Navigation controller
setLedOn(LED1);
}
}

View file

@ -18,12 +18,6 @@
#ifndef _ps3usb_h_
#define _ps3usb_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Usb.h"
#include "PS3Enums.h"
@ -104,6 +98,16 @@ public:
virtual bool isReady() {
return bPollEnable;
};
/**
* Used by the USB core to check what this driver support.
* @param vid The device's VID.
* @param pid The device's PID.
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID));
};
/**@}*/
/**
@ -224,6 +228,14 @@ public:
* @param rumble The desired value in the range from 64-255.
*/
void moveSetRumble(uint8_t rumble);
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/** Variable used to indicate if the normal playstation controller is successfully connected. */
@ -242,6 +254,14 @@ protected:
EpInfo epInfo[PS3_MAX_ENDPOINTS];
private:
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
*/
void onInit();
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
bool bPollEnable;
uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values

View file

@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
* Developer of the BTD, SPP, PS3, Wii, and Xbox libraries
* Developer of the [BTD](#bluetooth-libraries), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries
* __Andrew Kroll__ - <xxxajk@gmail.com>
* Major contributor to mass storage code
@ -53,23 +53,41 @@ For more information visit the following site: <http://arduino.cc/en/Guide/Libra
Documentation for the library can be found at the following link: <http://felis.github.com/USB_Host_Shield_2.0/>.
### Arduino ADK
To use this library with the official [Arduino ADK](http://arduino.cc/en/Main/ArduinoBoardADK) uncomment the following line in [avrpins.h](https://github.com/felis/USB_Host_Shield_2.0/blob/master/avrpins.h):
### Enable debugging
<code>
\#define BOARD\_MEGA_ADK
</code>
By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
### [Bluetooth libraries](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp)
```
#define ENABLE_UHS_DEBUGGING 1
```
The [BTD library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
### Boards
Currently the following boards are supported by the library:
* All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
* Teensy (Teensy 1.0, Teensy 2.0 and Teensy++ 2.0)
* Balanduino
* Sanguino
* Black Widdow
The following boards need to be activated manually in [settings.h](settings.h):
* Arduino Mega ADK
* Black Widdow
Simply set the corresponding value to 1 instead of 0.
### [Bluetooth libraries](BTD.cpp)
The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth.
Some different examples can be found in the [example directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Bluetooth).
Some different examples can be found in the [example directory](examples/Bluetooth).
The BTD library will also make it possible to use multiple services at once, the following example sketch is an example of this:
<https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/Bluetooth/PS3SPP/PS3SPP.ino>
### [SPP library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/SPP.cpp)
### [SPP library](SPP.cpp)
SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth.
It has been tested successfully on Windows, Mac OS X, Linux, and Android.
@ -84,7 +102,7 @@ It enables me to see the Bluetooth communication between my Mac and any device.
### PS3 Library
These libraries consist of the [PS3BT](https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3BT.cpp) and [PS3USB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
In order to use your Playstation controller via Bluetooth you have to set the Bluetooth address of the dongle internally to your PS3 Controller. This can be achieved by plugging the controller in via USB and letting the library set it automatically.
@ -110,15 +128,30 @@ Also a big thanks all the people behind these sites about the Motion controller:
* <https://github.com/thp/psmoveapi>
* <http://code.google.com/p/moveonpc/>
### Xbox 360 Library
### Xbox Libraries
The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly.
#### Xbox library
The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox controller via USB.
All the information are from the following sites:
* <https://github.com/torvalds/linux/blob/master/Documentation/input/xpad.txt>
* <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
* <http://euc.jp/periphs/xbox-controller.ja.html>
* <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL#L15>
#### Xbox 360 Library
The library support one Xbox 360 via USB or up to four Xbox 360 controllers wirelessly by using a [Xbox 360 wireless receiver](http://blog.tkjelectronics.dk/wp-content/uploads/xbox360-wireless-receiver.jpg).
To use it via USB use the [XBOXUSB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXRECV.cpp) library.
To use it via USB use the [XBOXUSB](XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](XBOXRECV.cpp) library.
__Note that a Wireless controller can NOT be used via USB!__
Examples code can be found in the [examples directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Xbox).
Examples code can be found in the [examples directory](examples/Xbox).
Also see the following blog posts:
@ -132,23 +165,23 @@ All the information regarding the Xbox 360 controller protocol are form these si
* <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/WirelessUsbInfo>
* <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL>
### [Wii library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp)
### [Wii library](Wii.cpp)
The [Wii](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth.
The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth.
First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
<code>
```
WII Wii(&Btd,PAIR);
</code>
```
And then press 1 & 2 at once on the Wiimote or press sync if you are using a Wii U Pro Controller.
After that you can simply create the instance like so:
<code>
```
WII Wii(&Btd);
</code>
```
Then just press any button any button on the Wiimote and it will connect to the dongle.

113
SPP.cpp
View file

@ -16,7 +16,7 @@
*/
#include "SPP.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report sent to the Arduino
@ -64,6 +64,7 @@ void SPP::Reset() {
connected = false;
RFCOMMConnected = false;
SDPConnected = false;
waitForLastCommand = false;
l2cap_sdp_state = L2CAP_SDP_WAIT;
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
l2cap_event_flag = 0;
@ -99,32 +100,32 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { // acl_handle_ok
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" Data: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
#endif
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
Notify(PSTR(" SCID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
Notify(PSTR(" Identifier: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
#endif
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
identifier = l2capinbuf[9];
@ -178,7 +179,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE;
}
} else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nInformation request"), 0x80);
#endif
identifier = l2capinbuf[9];
@ -187,7 +188,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
}
#endif
} else if (l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
@ -217,18 +218,24 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
else // Short UUID
uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
PrintHex<uint16_t> (uuid, 0x80);
D_PrintHex<uint16_t> (uuid, 0x80);
Notify(PSTR("\r\nLength: "), 0x80);
uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
PrintHex<uint16_t> (length, 0x80);
D_PrintHex<uint16_t> (length, 0x80);
Notify(PSTR("\r\nData: "), 0x80);
for (uint8_t i = 0; i < length; i++) {
PrintHex<uint8_t> (l2capinbuf[13+i], 0x80);
D_PrintHex<uint8_t> (l2capinbuf[13+i], 0x80);
Notify(PSTR(" "), 0x80);
}
#endif
}
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nUnknown PDU: "), 0x80);
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
}
#endif
} else if (l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
rfcommChannel = l2capinbuf[8] & 0xF8;
rfcommDirection = l2capinbuf[8] & 0x04;
@ -241,20 +248,20 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
Notify(PSTR(" Direction: "), 0x80);
PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
Notify(PSTR(" CommandResponse: "), 0x80);
PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
Notify(PSTR(" ChannelType: "), 0x80);
PrintHex<uint8_t > (rfcommChannelType, 0x80);
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
Notify(PSTR(" PF_BIT: "), 0x80);
PrintHex<uint8_t > (rfcommPfBit, 0x80);
D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
#endif
if (rfcommChannelType == RFCOMM_DISC) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
#endif
connected = false;
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
@ -274,7 +281,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
Notify(rfcommAvailable, 0x80);
if (offset) {
Notify(PSTR(" - Credit: 0x"), 0x80);
PrintHex<uint8_t > (l2capinbuf[11], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
}
#endif
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
@ -282,7 +289,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
Notifyc(l2capinbuf[i + 11 + offset], 0x80);
#endif
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
@ -297,7 +304,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
@ -308,12 +315,12 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
}
} else {
if (rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived SABM Command"), 0x80);
#endif
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
@ -328,7 +335,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[9] = 0x00; // Number of Frames
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
@ -338,7 +345,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
delay(1);
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
@ -349,7 +356,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
if (!creditSent) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
#endif
sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
@ -358,11 +365,11 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
waitForLastCommand = true;
}
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
#endif
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
#endif
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
@ -376,7 +383,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
#endif
waitForLastCommand = false;
@ -384,12 +391,12 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
connected = true; // The RFCOMM channel is now established
sppIndex = 0;
}
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
else if (rfcommChannelType != RFCOMM_DISC) {
Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
PrintHex<uint8_t > (rfcommChannelType, 0x80);
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
Notify(PSTR(" Command: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[11], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
}
#endif
}
@ -397,9 +404,9 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
PrintHex<uint8_t > (l2capinbuf[7], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
Notify(PSTR(" "), 0x80);
PrintHex<uint8_t > (l2capinbuf[6], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
}
#endif
SDP_task();
@ -409,7 +416,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
void SPP::Run() {
if (waitForLastCommand && (millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
#endif
creditSent = false;
@ -425,7 +432,7 @@ void SPP::SDP_task() {
case L2CAP_SDP_WAIT:
if (l2cap_connection_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_SDP_REQUEST; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
@ -440,7 +447,7 @@ void SPP::SDP_task() {
case L2CAP_SDP_REQUEST:
if (l2cap_config_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_REQUEST; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle, identifier, sdp_scid);
@ -450,7 +457,7 @@ void SPP::SDP_task() {
case L2CAP_SDP_SUCCESS:
if (l2cap_config_success_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_SUCCESS; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
#endif
firstMessage = true; // Reset bool
@ -462,7 +469,7 @@ void SPP::SDP_task() {
if (l2cap_disconnect_request_sdp_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_SDP_REQUEST; // Clear flag
SDPConnected = false;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
#endif
pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
@ -472,7 +479,7 @@ void SPP::SDP_task() {
break;
case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
if (l2cap_disconnect_response_flag) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
#endif
RFCOMMConnected = false;
@ -492,7 +499,7 @@ void SPP::RFCOMM_task() {
case L2CAP_RFCOMM_WAIT:
if (l2cap_connection_request_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
#endif
pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
@ -507,7 +514,7 @@ void SPP::RFCOMM_task() {
case L2CAP_RFCOMM_REQUEST:
if (l2cap_config_request_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
#endif
pBtd->l2cap_config_response(hci_handle, identifier, rfcomm_scid);
@ -517,7 +524,7 @@ void SPP::RFCOMM_task() {
case L2CAP_RFCOMM_SUCCESS:
if (l2cap_config_success_rfcomm_flag) {
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; // Clear flag
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
#endif
rfcommAvailable = 0; // Reset number of bytes available
@ -531,7 +538,7 @@ void SPP::RFCOMM_task() {
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; // Clear flag
RFCOMMConnected = false;
connected = false;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
#endif
pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
@ -692,7 +699,7 @@ void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t cha
#ifdef EXTRADEBUG
Notify(PSTR(" - RFCOMM Data: "), 0x80);
for (i = 0; i < length + 4; i++) {
PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
#endif
@ -708,7 +715,7 @@ void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8
#ifdef EXTRADEBUG
Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
for (uint8_t i = 0; i < 5; i++) {
PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
#endif

274
Usb.cpp
View file

@ -16,15 +16,6 @@ e-mail : support@circuitsathome.com
*/
/* USB functions */
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "Usb.h"
static uint8_t usb_error = 0;
@ -38,7 +29,7 @@ USB::USB() : bmHubPre(0) {
/* Initialize data structures */
void USB::init() {
devConfigIndex = 0;
//devConfigIndex = 0;
bmHubPre = 0;
}
@ -113,6 +104,13 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_l
uint8_t mode = regRd(rMODE);
//Serial.print("\r\nMode: ");
//Serial.println( mode, HEX);
//Serial.print("\r\nLS: ");
//Serial.println(p->lowspeed, HEX);
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
@ -132,7 +130,7 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
SETUP_PKT setup_pkt;
EpInfo *pep = NULL;
uint16_t nak_limit;
uint16_t nak_limit = 0;
rcode = SetAddress(addr, ep, &pep, nak_limit);
@ -170,11 +168,16 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
//uint16_t read = (left<nbytes) ? left : nbytes;
rcode = InTransfer(pep, nak_limit, &read, dataptr);
if (rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
continue;
}
if (rcode)
return rcode;
// Invoke callback function if inTransfer completed successfuly and callback function pointer is specified
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
if (!rcode && p)
((USBReadParser*)p)->Parse(read, dataptr, total - left);
@ -227,21 +230,33 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
while (1) // use a 'return' to exit this loop
{
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if (rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
continue;
}
if (rcode) {
//printf("Problem! %i\r\n", rcode);
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
break; //should be 0, indicating ACK. Else return error code.
}
/* check for RCVDAVIRQ and generate error if not present */
/* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
//printf("Problem! NO RCVDAVIRQ!\r\n");
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xf0; //receive error
break;
}
pktsize = regRd(rRCVBC); //number of received bytes
//printf("Got %i bytes ", pktsize);
//printf("Got %i bytes \r\n", pktsize);
// This would be OK, but...
//assert(pktsize <= nbytes);
if (pktsize > nbytes) {
// This can happen. Use of assert on Arduino locks up the Arduino.
// So I will trim the value, and hope for the best.
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
pktsize = nbytes;
}
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
@ -274,7 +289,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
EpInfo *pep = NULL;
uint16_t nak_limit;
uint16_t nak_limit = 0;
uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
@ -315,15 +330,22 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
case hrNAK:
nak_count++;
if (nak_limit && (nak_count == nak_limit))
return ( rcode);
goto breakout;
//return ( rcode);
break;
case hrTIMEOUT:
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
return ( rcode);
goto breakout;
//return ( rcode);
break;
case hrTOGERR:
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
break;
default:
return ( rcode);
goto breakout;
}//switch( rcode
/* process NAK according to Host out NAK bug */
@ -338,10 +360,12 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
}//while( bytes_left...
breakout:
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode); //should be 0 in all cases
}
/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
/* If NAK, tries to re-send up to nak_limit times */
/* If nak_limit == 0, do not count NAKs, exit after timeout */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
@ -358,7 +382,7 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
regWr(rHXFR, (token | ep)); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
while (millis() < timeout) //wait for transfer completion
while (timeout > millis()) //wait for transfer completion
{
tmpdata = regRd(rHIRQ);
@ -370,8 +394,8 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
}//while ( millis() < timeout
if (rcode != 0x00) //exit if timeout
return ( rcode);
//if (rcode != 0x00) //exit if timeout
// return ( rcode);
rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
@ -379,15 +403,15 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
case hrNAK:
nak_count++;
if (nak_limit && (nak_count == nak_limit))
return ( rcode);
return (rcode);
break;
case hrTIMEOUT:
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
return ( rcode);
return (rcode);
break;
default:
return ( rcode);
return (rcode);
}//switch( rcode
}//while( timeout > millis()
@ -419,7 +443,9 @@ void USB::Task(void) //USB state machine
lowspeed = false;
break;
case LSHOST:
lowspeed = true;
//intentional fallthrough
case FSHOST: //attached
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
delay = millis() + USB_SETTLE_DELAY;
@ -459,17 +485,28 @@ void USB::Task(void) //USB state machine
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
regWr(rMODE, tmpdata);
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
delay = millis() + 20; //20ms wait after reset per USB spec
//delay = millis() + 20; //20ms wait after reset per USB spec
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
if (regRd(rHIRQ) & bmFRAMEIRQ) //when first SOF received we can continue
{
if (regRd(rHIRQ) & bmFRAMEIRQ) {
//when first SOF received _and_ 20ms has passed we can continue
/*
if (delay < millis()) //20ms passed
usb_task_state = USB_STATE_CONFIGURING;
*/
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
delay = millis() + 20;
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
if (delay < millis()) usb_task_state = USB_STATE_CONFIGURING;
break;
case USB_STATE_CONFIGURING:
//Serial.print("\r\nConf.LS: ");
//Serial.println(lowspeed, HEX);
rcode = Configuring(0, 0, lowspeed);
if (rcode) {
@ -483,6 +520,7 @@ void USB::Task(void) //USB state machine
case USB_STATE_RUNNING:
break;
case USB_STATE_ERROR:
//MAX3421E::Init();
break;
} // switch( usb_task_state )
}
@ -527,33 +565,166 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
return 0;
};
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
//static uint8_t dev_index = 0;
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t rcode = 0;
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex])
continue;
rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);
if (!rcode) {
devConfigIndex = 0;
return 0;
rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
if (parent == 0) {
// Send a bus reset on the root interface.
regWr(rHCTL, bmBUSRST); //issue bus reset
delay(102); // delay 102ms, compensate for clock inaccuracy.
} else {
// reset parent port
devConfig[parent]->ResetHubPort(port);
}
}
rcode = devConfig[driver]->Init(parent, port, lowspeed);
if(rcode) {
// Issue a bus reset, because the device may be in a limbo state
if (parent == 0) {
// Send a bus reset on the root interface.
regWr(rHCTL, bmBUSRST); //issue bus reset
delay(102); // delay 102ms, compensate for clock inaccuracy.
} else {
// reset parent port
devConfig[parent]->ResetHubPort(port);
}
}
return rcode;
}
/*
* This is broken. We need to enumerate differently.
* It causes major problems with several devices if detected in an unexpected order.
*
*
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
* i.e.(delays are not indicated for brevity):
* 1. reset
* 2. GetDevDescr();
* 3a. If ACK, continue with allocating address, addressing, etc.
* 3b. Else reset again, count resets, stop at some number (5?).
* 4. When max.number of resets is reached, toggle power/fail
* If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
* it doesn't need to be reset again
* New steps proposal:
* 1: get address pool instance. exit on fail
* 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
* 3: bus reset, 100ms delay
* 4: set address
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
* 6: while (configurations) {
* for(each configuration) {
* for (each driver) {
* 6a: Ask device if it likes configuration. Returns 0 on OK.
* If successful, the driver configured device.
* The driver now owns the endpoints, and takes over managing them.
* The following will need codes:
* Everything went well, instance consumed, exit with success.
* Instance already in use, ignore it, try next driver.
* Not a supported device, ignore it, try next driver.
* Not a supported configuration for this device, ignore it, try next driver.
* Could not configure device, fatal, exit with fail.
* }
* }
* }
* 7: for(each driver) {
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
* 8: if we get here, no driver likes the device plugged in, so exit failure.
*
*/
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
//uint8_t bAddress = 0;
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
uint8_t devConfigIndex;
uint8_t rcode = 0;
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
EpInfo epInfo;
epInfo.epAddr = 0;
epInfo.maxPktSize = 8;
epInfo.epAttribs = 0;
epInfo.bmNakPower = USB_NAK_MAX_POWER;
delay(2000);
AddressPool &addrPool = GetAddressPool();
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to
// avoid toggle inconsistence
p->epinfo = &epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if (rcode) {
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
return rcode;
}
// to-do?
// Allocate new address according to device class
//bAddress = addrPool.AllocAddress(parent, false, port);
//if (!bAddress)
// return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
uint16_t vid = (uint16_t)((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
uint16_t pid = (uint16_t)((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
uint8_t klass = ((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass;
// Attempt to configure if VID/PID or device class matches with a driver
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex]) continue; // no driver
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) {
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
break;
}
}
if (devConfigIndex < USB_NUMDEVICES) {
return rcode;
}
// blindly attempt to configure
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex]) continue;
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
devConfigIndex = 0;
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
// devConfigIndex = 0;
return rcode;
}
}
// if we get here that means that the device class is not supported by any of registered classes
devConfigIndex = 0;
rcode = DefaultAddressing(parent, port, lowspeed);
return rcode;
@ -563,10 +734,11 @@ uint8_t USB::ReleaseDevice(uint8_t addr) {
if (!addr)
return 0;
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) continue;
if (devConfig[i]->GetAddress() == addr)
return devConfig[i]->Release();
}
return 0;
}
@ -582,11 +754,13 @@ uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t con
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
}
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
const uint8_t bufSize = 64;
uint8_t buf[bufSize];
uint8_t ret = getConfDescr(addr, ep, 8, conf, buf);
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
if (ret)
return ret;

272
Usb.h
View file

@ -18,265 +18,23 @@ e-mail : support@circuitsathome.com
#ifndef _usb_h_
#define _usb_h_
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
//#define BOARD_BLACK_WIDDOW
#define USB_METHODS_INLINE
// WARNING: Do not change the order of includes, or stuff will break!
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "address.h"
// None of these should ever be included by a driver, or a user's sketch.
#include "settings.h"
#include "printhex.h"
#include "message.h"
/* shield pins. First parameter - SS pin, second parameter - INT pin */
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define BOARD_TEENSY_PLUS_PLUS
#endif
#ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(BOARD_TEENSY_PLUS_PLUS)
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(BOARD_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.)
#endif
//Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s)))
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
/* Common setup data constant combinations */
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
// USB Device Classes
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
// Additional Error Codes
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
#define USB_ERROR_EPINFO_IS_NULL 0xD7
#define USB_ERROR_INVALID_ARGUMENT 0xD8
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
class USBDeviceConfig {
public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0;
virtual uint8_t Release() = 0;
virtual uint8_t Poll() = 0;
virtual uint8_t GetAddress() = 0;
};
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
#define USB_NUMDEVICES 16 //number of USB devices
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
/* USB state machine states */
#define USB_STATE_MASK 0xf0
#define USB_STATE_DETACHED 0x10
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
#define USB_STATE_ADDRESSING 0x70
#define USB_STATE_CONFIGURING 0x80
#define USB_STATE_RUNNING 0x90
#define USB_STATE_ERROR 0xa0
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type
struct {
uint8_t recipient : 5; // Recipient of the request
uint8_t type : 2; // Type of request
uint8_t direction : 1; // Direction of data X-fer
} __attribute__((packed));
} ReqType_u;
uint8_t bRequest; // 1 Request
union {
uint16_t wValue; // 2 Depends on bRequest
struct {
uint8_t wValueLo;
uint8_t wValueHi;
} __attribute__((packed));
} wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
// Base class for incomming data parser
class USBReadParser {
public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
};
class USB : public MAX3421E {
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t devConfigIndex;
uint8_t bmHubPre;
public:
USB(void);
void SetHubPreMask() {
bmHubPre |= bmHUBPRE;
};
void ResetHubPreMask() {
bmHubPre &= (~bmHUBPRE);
};
AddressPool& GetAddressPool() {
return(AddressPool&) addrPool;
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState(void);
void setUsbTaskState(uint8_t state);
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
//uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
/* Control requests */
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
/**/
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void Task(void);
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t ReleaseDevice(uint8_t addr);
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
private:
void init();
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
};
#if 0 //defined(USB_METHODS_INLINE)
//get device descriptor
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
}
//get configuration descriptor
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
}
//get string descriptor
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
}
//set address
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
}
//set configuration
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
}
#endif // defined(USB_METHODS_INLINE)
#include "hexdump.h"
#include "max3421e.h"
#include "address.h"
#include "avrpins.h"
#include "usb_ch9.h"
#include "usbhost.h"
#include "UsbCore.h"
#include "parsetools.h"
#include "confdescparser.h"
#endif //_usb_h_

254
UsbCore.h Normal file
View file

@ -0,0 +1,254 @@
/*
* File: UsbCore.h
* Author: xxxajk
*
* Created on September 29, 2013, 9:25 PM
*/
#if !defined(_usb_h_) || defined(USBCORE_H)
#error "Never include UsbCore.h directly; include Usb.h instead"
#else
#define USBCORE_H
// Not used anymore? If anyone uses this, please let us know so that this may be
// moved to the proper place, settings.h.
//#define USB_METHODS_INLINE
/* shield pins. First parameter - SS pin, second parameter - INT pin */
#ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(ARDUINO_AVR_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.)
#endif
/* Common setup data constant combinations */
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
// USB Device Classes
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
// Additional Error Codes
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
#define USB_ERROR_EPINFO_IS_NULL 0xD7
#define USB_ERROR_INVALID_ARGUMENT 0xD8
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0
#define USB_ERROR_FailGetDevDescr 0xE1
#define USB_ERROR_FailSetDevTblEntry 0xE2
#define USB_ERROR_FailGetConfDescr 0xE3
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
#define USB_XFER_TIMEOUT 10000 //30000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
#define USB_NUMDEVICES 16 //number of USB devices
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
/* USB state machine states */
#define USB_STATE_MASK 0xf0
#define USB_STATE_DETACHED 0x10
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
#define USB_STATE_ADDRESSING 0x70
#define USB_STATE_CONFIGURING 0x80
#define USB_STATE_RUNNING 0x90
#define USB_STATE_ERROR 0xa0
class USBDeviceConfig {
public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) { return 0; }
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {return 0; }
virtual uint8_t Release() { return 0; }
virtual uint8_t Poll() { return 0; }
virtual uint8_t GetAddress() { return 0; }
virtual void ResetHubPort(uint8_t port) { return; } // Note used for hubs only!
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { return false; }
virtual boolean DEVCLASSOK(uint8_t klass) { return false; }
};
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type
struct {
uint8_t recipient : 5; // Recipient of the request
uint8_t type : 2; // Type of request
uint8_t direction : 1; // Direction of data X-fer
} __attribute__((packed));
} ReqType_u;
uint8_t bRequest; // 1 Request
union {
uint16_t wValue; // 2 Depends on bRequest
struct {
uint8_t wValueLo;
uint8_t wValueHi;
} __attribute__((packed));
} wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
// Base class for incoming data parser
class USBReadParser {
public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
};
class USB : public MAX3421E {
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t bmHubPre;
public:
USB(void);
void SetHubPreMask() {
bmHubPre |= bmHUBPRE;
};
void ResetHubPreMask() {
bmHubPre &= (~bmHUBPRE);
};
AddressPool& GetAddressPool() {
return(AddressPool&) addrPool;
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState(void);
void setUsbTaskState(uint8_t state);
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
/* Control requests */
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
/**/
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void Task(void);
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t ReleaseDevice(uint8_t addr);
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
private:
void init();
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed);
};
#if 0 //defined(USB_METHODS_INLINE)
//get device descriptor
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
}
//get configuration descriptor
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
}
//get string descriptor
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
}
//set address
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
}
//set configuration
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
}
#endif // defined(USB_METHODS_INLINE)
#endif /* USBCORE_H */

705
Wii.cpp

File diff suppressed because it is too large Load diff

41
Wii.h
View file

@ -14,9 +14,7 @@
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
IR camera support added by:
Allan Glover
adglover9.81@gmail.com
IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus
*/
#ifndef _wii_h_
@ -215,17 +213,11 @@ public:
*/
void setLedStatus();
/**
* Call this to update battery level and Wiimote state
*/
void statusRequest();
/**
* Return the battery level of the Wiimote.
* @return The battery level in the range 0-255.
*/
uint8_t getBatteryLevel() {
return batteryLevel;
};
uint8_t getBatteryLevel();
/**
* Return the Wiimote state.
* @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status.
@ -233,6 +225,14 @@ public:
uint8_t getWiiState() {
return wiiState;
};
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/**@{*/
@ -418,8 +418,15 @@ public:
#endif
private:
/* Mandatory members */
BTD *pBtd;
BTD *pBtd; // Pointer to BTD instance
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
*/
void onInit();
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
void L2CAP_task(); // L2CAP state machine
@ -427,9 +434,9 @@ private:
uint16_t hci_handle;
bool activeConnection; // Used to indicate if it's already has established a connection
/* variables used by high level L2CAP task */
/* Variables used by high level L2CAP task */
uint8_t l2cap_state;
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
uint16_t l2cap_event_flag; // l2cap flags of received Bluetooth events
uint32_t ButtonState;
uint32_t OldButtonState;
@ -441,6 +448,8 @@ private:
uint16_t stateCounter;
bool unknownExtensionConnected;
bool extensionConnected;
bool checkExtension; // Set to false when getBatteryLevel() is called otherwise if should be true
bool motionPlusInside; // True if it's a new Wiimote with the Motion Plus extension build into it
/* L2CAP Channels */
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
@ -457,6 +466,8 @@ private:
void initExtension1();
void initExtension2();
void statusRequest(); // Used to update the Wiimote state and battery level
void readData(uint32_t offset, uint16_t size, bool EEPROM);
void readExtensionType();
void readCalData();
@ -476,7 +487,7 @@ private:
uint8_t batteryLevel;
#ifdef WIICAMERA
/* Private function and variables for the readings from teh IR Camera */
/* Private function and variables for the readings from the IR Camera */
void enableIRCamera1(); // Sets bit 2 of output report 13
void enableIRCamera2(); // Sets bit 2 of output report 1A
void writeSensitivityBlock1();

334
XBOXOLD.cpp Normal file
View file

@ -0,0 +1,334 @@
/* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#include "XBOXOLD.h"
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox controller
/** Buttons on the controllers */
const uint8_t XBOXOLDBUTTONS[] PROGMEM = {
0x01, // UP
0x08, // RIGHT
0x02, // DOWN
0x04, // LEFT
0x20, // BACK
0x10, // START
0x40, // L3
0x80, // R3
// A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
4, // BLACK
5, // WHTIE
6, // L1
7, // R1
1, // B
0, // A
2, // X
3, // Y
};
XBOXOLD::XBOXOLD(USB *p) :
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) { // don't start polling before dongle is connected
for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint16_t PID;
uint16_t VID;
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if (rcode)
goto FailGetDevDescr;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_OLD_PID1 && PID != XBOX_OLD_PID2 && PID != XBOX_OLD_PID3 && PID != XBOX_OLD_PID4)) // Check if VID and PID match
goto FailUnknownDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nsetAddr: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
#endif
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "), 0x80);
D_PrintHex<uint8_t > (bAddress, 0x80);
#endif
delay(300); // Spec says you should wait at least 200ms
p->lowspeed = false;
//get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode)
goto FailSetDevTblEntry;
/* The application will work in reduced host mode, so we can save program and data
memory space. After verifying the VID we will use known values for the
configuration values for device, interface, endpoints and HID for the XBOX controllers */
/* Initialize data structures for endpoints of device */
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX report endpoint
epInfo[ XBOX_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX output endpoint
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if (rcode)
goto FailSetDevTblEntry;
delay(200); // Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
if (rcode)
goto FailSetConfDescr;
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80);
#endif
if (pFuncOnInit)
pFuncOnInit(); // Call the user function
XboxConnected = true;
bPollEnable = true;
return 0; // Successful configuration
/* Diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailUnknownDevice:
#ifdef DEBUG_USB_HOST
NotifyFailUnknownDevice(VID, PID);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80);
NotifyFail(rcode);
#endif
Release();
return rcode;
}
/* Performs a cleanup after failed Init() attempt */
uint8_t XBOXOLD::Release() {
XboxConnected = false;
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bPollEnable = false;
return 0;
}
uint8_t XBOXOLD::Poll() {
if (!bPollEnable)
return 0;
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
readReport();
#ifdef PRINTREPORT
printReport(BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
#endif
return 0;
}
void XBOXOLD::readReport() {
ButtonState = readBuf[2];
for (uint8_t i = 0; i < sizeof(buttonValues); i++)
buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1
hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[12] << 8) | readBuf[13]);
hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[14] << 8) | readBuf[15]);
hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[16] << 8) | readBuf[17]);
hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[18] << 8) | readBuf[19]);
//Notify(PSTR("\r\nButtonState"), 0x80);
//PrintHex<uint8_t>(ButtonState, 0x80);
if (ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof(buttonValues)) != 0) {
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
OldButtonState = ButtonState;
for (uint8_t i = 0; i < sizeof(buttonValues); i++) {
if (oldButtonValues[i] == 0 && buttonValues[i] != 0)
buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state
oldButtonValues[i] = buttonValues[i];
}
}
}
void XBOXOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
#ifdef PRINTREPORT
if (readBuf == NULL)
return;
for (uint8_t i = 0; i < length; i++) {
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
#endif
}
uint8_t XBOXOLD::getButtonPress(Button b) {
if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
return buttonValues[pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])]; // Analog buttons
return (ButtonState & pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])); // Digital buttons
}
bool XBOXOLD::getButtonClick(Button b) {
uint8_t button;
if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]);
if (buttonClicked[button])
buttonClicked[button] = false;
return buttonClicked[button];
}
button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); // Digital buttons
bool click = (ButtonClickState & button);
ButtonClickState &= ~button; // clear "click" event
return click;
}
int16_t XBOXOLD::getAnalogHat(AnalogHat a) {
return hatValue[a];
}
/* Xbox Controller commands */
void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) {
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
}
void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) {
uint8_t writeBuf[6];
writeBuf[0] = 0x00;
writeBuf[1] = 0x06;
writeBuf[2] = 0x00;
writeBuf[3] = rValue; // small weight
writeBuf[4] = 0x00;
writeBuf[5] = lValue; // big weight
XboxCommand(writeBuf, 6);
}

192
XBOXOLD.h Normal file
View file

@ -0,0 +1,192 @@
/* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#ifndef _xboxold_h_
#define _xboxold_h_
#include "Usb.h"
#include "controllerEnums.h"
/* Data Xbox taken from descriptors */
#define EP_MAXPKTSIZE 32 // Max size for data via USB
/* Endpoint types */
#define EP_INTERRUPT 0x03
/* Names we give to the 3 Xbox pipes */
#define XBOX_CONTROL_PIPE 0
#define XBOX_INPUT_PIPE 1
#define XBOX_OUTPUT_PIPE 2
// PID and VID of the different devices
#define XBOX_VID 0x045E // Microsoft Corporation
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
#define XBOX_OLD_PID1 0x0202 // Original Microsoft Xbox controller (US)
#define XBOX_OLD_PID2 0x0285 // Original Microsoft Xbox controller (Japan)
#define XBOX_OLD_PID3 0x0287 // Microsoft Microsoft Xbox Controller S
#define XBOX_OLD_PID4 0x0289 // Smaller Microsoft Xbox controller (US)
// Used in control endpoint header for HID Commands
#define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQUEST_SET_REPORT 0x09
#define XBOX_MAX_ENDPOINTS 3
/** This class implements support for a the original Xbox controller via USB. */
class XBOXOLD : public USBDeviceConfig {
public:
/**
* Constructor for the XBOXOLD class.
* @param pUsb Pointer to USB class instance.
*/
XBOXOLD(USB *pUsb);
/** @name USBDeviceConfig implementation */
/**
* Initialize the Xbox Controller.
* @param parent Hub number.
* @param port Port number on the hub.
* @param lowspeed Speed of the device.
* @return 0 on success.
*/
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
/**
* Release the USB device.
* @return 0 on success.
*/
virtual uint8_t Release();
/**
* Poll the USB Input endpoins and run the state machines.
* @return 0 on success.
*/
virtual uint8_t Poll();
/**
* Get the device address.
* @return The device address.
*/
virtual uint8_t GetAddress() {
return bAddress;
};
/**
* Used to check if the controller has been initialized.
* @return True if it's ready.
*/
virtual bool isReady() {
return bPollEnable;
};
/**
* Used by the USB core to check what this driver support.
* @param vid The device's VID.
* @param pid The device's PID.
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_OLD_PID1 || pid == XBOX_OLD_PID2 || pid == XBOX_OLD_PID3 || pid == XBOX_OLD_PID4));
};
/**@}*/
/** @name Xbox Controller functions */
/**
* getButtonPress(Button b) will return true as long as the button is held down.
*
* While getButtonClick(Button b) will only return it once.
*
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
* but if you need to drive a robot forward you would use getButtonPress(Button b).
* @param b ::Button to read.
* @return getButtonClick(Button b) will return a bool, but getButtonPress(Button b)
* will return a byte if reading ::L2 or ::R2.
*/
uint8_t getButtonPress(Button b);
bool getButtonClick(Button b);
/**@}*/
/** @name Xbox Controller functions */
/**
* Return the analog value from the joysticks on the controller.
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
* @return Returns a signed 16-bit integer.
*/
int16_t getAnalogHat(AnalogHat a);
/** Turn rumble off the controller. */
void setRumbleOff() {
setRumbleOn(0, 0);
};
/**
* Turn rumble on.
* @param lValue Left motor (big weight) inside the controller.
* @param rValue Right motor (small weight) inside the controller.
*/
void setRumbleOn(uint8_t lValue, uint8_t rValue);
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/** True if a Xbox controller is connected. */
bool XboxConnected;
protected:
/** Pointer to USB class instance. */
USB *pUsb;
/** Device address. */
uint8_t bAddress;
/** Endpoint info structure. */
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
private:
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
*/
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
bool bPollEnable;
/* Variables to store the digital buttons */
uint8_t ButtonState;
uint8_t OldButtonState;
uint8_t ButtonClickState;
/* Variables to store the analog buttons */
uint8_t buttonValues[8]; // A, B, X, Y, BLACK, WHITE, L1, and R1
uint8_t oldButtonValues[8];
bool buttonClicked[8];
int16_t hatValue[4]; // Joystick values
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
void readReport(); // Read incoming data
void printReport(uint16_t length); // Print incoming date
/* Private commands */
void XboxCommand(uint8_t* data, uint16_t nbytes);
};
#endif

View file

@ -18,7 +18,7 @@
*/
#include "XBOXRECV.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
@ -52,7 +52,7 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
@ -62,14 +62,14 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
@ -94,10 +94,10 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a xbox receiver using the Vendor ID
if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a Xbox receiver using the Vendor ID
goto FailUnknownDevice;
else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
#ifdef DEBUG
else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { // Check the PID as well
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80);
#endif
goto FailUnknownDevice;
@ -118,16 +118,18 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nsetAddr: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
#endif
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
D_PrintHex<uint8_t > (bAddress, 0x80);
#endif
delay(300); // Spec says you should wait at least 200ms
p->lowspeed = false;
//get pointer to assigned address record
@ -209,7 +211,7 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (rcode)
goto FailSetConfDescr;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80);
#endif
XboxReceiverConnected = true;
@ -218,26 +220,34 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG_USB_HOST
NotifyFailUnknownDevice(VID,PID);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
#endif
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -278,7 +288,7 @@ uint8_t XBOXRECV::Poll() {
if (bufferSize > 0) { // The number of received bytes
#ifdef EXTRADEBUG
Notify(PSTR("Bytes Received: "), 0x80);
PrintHex<uint16_t > (bufferSize, 0x80);
D_PrintHex<uint16_t > (bufferSize, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
readReport(i);
@ -296,12 +306,12 @@ void XBOXRECV::readReport(uint8_t controller) {
// This report is send when a controller is connected and disconnected
if (readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
Xbox360Connected[controller] = readBuf[1];
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("Controller "), 0x80);
Notify(controller, 0x80);
#endif
if (Xbox360Connected[controller]) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
const char* str = 0;
switch (readBuf[1]) {
case 0x80: str = PSTR(" as controller\r\n");
@ -314,20 +324,9 @@ void XBOXRECV::readReport(uint8_t controller) {
Notify(PSTR(": connected"), 0x80);
Notify(str, 0x80);
#endif
LED led;
switch (controller) {
case 0: led = LED1;
break;
case 1: led = LED2;
break;
case 2: led = LED3;
break;
case 3: led = LED4;
break;
}
setLedOn(led, controller);
onInit(controller);
}
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
else
Notify(PSTR(": disconnected\r\n"), 0x80);
#endif
@ -374,7 +373,7 @@ void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#d
Notify(controller, 0x80);
Notify(PSTR(": "), 0x80);
for (uint8_t i = 0; i < nBytes; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
@ -521,3 +520,20 @@ void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) {
XboxCommand(controller, writeBuf, 7);
}
void XBOXRECV::onInit(uint8_t controller) {
if (pFuncOnInit)
pFuncOnInit(); // Call the user function
else {
LED led;
if (controller == 0)
led = LED1;
else if (controller == 1)
led = LED2;
else if (controller == 2)
led = LED3;
else
led = LED4;
setLedOn(led, controller);
}
}

View file

@ -20,12 +20,6 @@
#ifndef _xboxrecv_h_
#define _xboxrecv_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Usb.h"
#include "xboxEnums.h"
@ -48,11 +42,12 @@
// PID and VID of the different devices
#define XBOX_VID 0x045E // Microsoft Corporation
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers
#define XBOX_MAX_ENDPOINTS 9
/**
@ -103,6 +98,16 @@ public:
virtual bool isReady() {
return bPollEnable;
};
/**
* Used by the USB core to check what this driver support.
* @param vid The device's VID.
* @param pid The device's PID.
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_WIRELESS_RECEIVER_PID || pid == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID));
};
/**@}*/
/** @name Xbox Controller functions */
@ -200,6 +205,14 @@ public:
* @return True if a button has changed.
*/
bool buttonChanged(uint8_t controller = 0);
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/** True if a wireless receiver is connected. */
@ -216,6 +229,15 @@ protected:
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
private:
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
* @param controller The initialized controller.
*/
void onInit(uint8_t controller);
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
bool bPollEnable;
/* Variables to store the buttons */
@ -232,7 +254,7 @@ private:
unsigned long timer; // Timing for checkStatus() signals
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
uint8_t writeBuf[7]; // General purpose buffer for output data
void readReport(uint8_t controller); // read incoming data
void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging

View file

@ -16,7 +16,7 @@
*/
#include "XBOXUSB.h"
#define DEBUG // Uncomment to print data for debugging
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
@ -50,7 +50,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress in use"), 0x80);
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
@ -60,14 +60,14 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
return USB_ERROR_EPINFO_IS_NULL;
@ -92,19 +92,20 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // We just check if it's a xbox controller using the Vendor ID
if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID && VID != GAMESTOP_VID) // Check VID
goto FailUnknownDevice;
if (PID == XBOX_WIRELESS_PID) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80);
#endif
goto FailUnknownDevice;
} else if (PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
#endif
goto FailUnknownDevice;
}
} else if (PID != XBOX_WIRED_PID && PID != GAMESTOP_WIRED_PID) // Check PID
goto FailUnknownDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
@ -121,16 +122,18 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nsetAddr: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
#endif
PrintHex<uint8_t > (rcode, 0x80);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "), 0x80);
PrintHex<uint8_t > (bAddress, 0x80);
D_PrintHex<uint8_t > (bAddress, 0x80);
#endif
delay(300); // Spec says you should wait at least 200ms
p->lowspeed = false;
//get pointer to assigned address record
@ -167,41 +170,49 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (rcode)
goto FailSetDevTblEntry;
delay(200); //Give time for address change
delay(200); // Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
if (rcode)
goto FailSetConfDescr;
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80);
#endif
setLedOn(LED1);
onInit();
Xbox360Connected = true;
bPollEnable = true;
return 0; // successful configuration
return 0; // Successful configuration
/* diagnostic messages */
/* Diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailUnknownDevice:
NotifyFailUnknownDevice(VID,PID);
#ifdef DEBUG_USB_HOST
NotifyFailUnknownDevice(VID, PID);
#endif
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
#endif
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -259,7 +270,7 @@ void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the rep
if (readBuf == NULL)
return;
for (uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
PrintHex<uint8_t > (readBuf[i], 0x80);
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
@ -337,3 +348,10 @@ void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
XboxCommand(writeBuf, 8);
}
void XBOXUSB::onInit() {
if (pFuncOnInit)
pFuncOnInit(); // Call the user function
else
setLedOn(LED1);
}

View file

@ -18,12 +18,6 @@
#ifndef _xboxusb_h_
#define _xboxusb_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Usb.h"
#include "xboxEnums.h"
@ -40,12 +34,15 @@
// PID and VID of the different devices
#define XBOX_VID 0x045E // Microsoft Corporation
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
#define GAMESTOP_VID 0x0E6F // Gamestop controller
#define XBOX_WIRED_PID 0x028E // Microsoft 360 Wired controller
#define XBOX_WIRELESS_PID 0x028F // Wireless controller only support charging
#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
@ -99,6 +96,16 @@ public:
virtual bool isReady() {
return bPollEnable;
};
/**
* Used by the USB core to check what this driver support.
* @param vid The device's VID.
* @param pid The device's PID.
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID || vid == GAMESTOP_VID) && (pid == XBOX_WIRED_PID || pid == GAMESTOP_WIRED_PID));
};
/**@}*/
/** @name Xbox Controller functions */
@ -168,6 +175,14 @@ public:
* @param lm See ::LEDMode.
*/
void setLedMode(LEDMode lm);
/**
* Used to call your own function when the controller is successfully initialized.
* @param funcOnInit Function to call.
*/
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};
/**@}*/
/** True if a Xbox 360 controller is connected. */
@ -182,6 +197,14 @@ protected:
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
private:
/**
* Called when the controller is successfully initialized.
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
* This is useful for instance if you want to set the LEDs in a specific way.
*/
void onInit();
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
bool bPollEnable;
/* Variables to store the buttons */
@ -195,7 +218,7 @@ private:
bool R2Clicked;
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
uint8_t writeBuf[8]; // General purpose buffer for output data
void readReport(); // read incoming data
void printReport(); // print incoming date - Uncomment for debugging

View file

@ -14,12 +14,12 @@ Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__ADDRESS_H__)
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
#error "Never include address.h directly; include Usb.h instead"
#else
#define __ADDRESS_H__
#include <inttypes.h>
#include <stddef.h>
#include "max3421e.h"
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
@ -70,7 +70,7 @@ struct UsbDeviceAddress {
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
@ -194,7 +194,7 @@ public:
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* if (parent != 0 && port == 0)
Serial.println("PRT:0"); */
USB_HOST_SERIAL.println("PRT:0"); */
if(parent > 127 || port > 7)
return 0;
@ -219,6 +219,7 @@ public:
}
UsbDeviceAddress addr;
addr.devAddress = 0; // Ensure all bits are zero
addr.bmParent = ((UsbDeviceAddress*) & parent)->bmAddress;
@ -231,12 +232,12 @@ public:
}
thePool[index].address = *((uint8_t*) & addr);
/*
Serial.print("Addr:");
Serial.print(addr.bmHub, HEX);
Serial.print(".");
Serial.print(addr.bmParent, HEX);
Serial.print(".");
Serial.println(addr.bmAddress, HEX);
USB_HOST_SERIAL.print("Addr:");
USB_HOST_SERIAL.print(addr.bmHub, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.print(addr.bmParent, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
*/
return thePool[index].address;
};

38
adk.cpp
View file

@ -58,14 +58,18 @@ ready(false) {
}
}
uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
return Init(parent, port, lowspeed); // Just call Init. Yes, really!
}
/* Connection initialization of an Android phone */
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
uint8_t num_of_conf; // number of configurations
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
@ -114,7 +118,6 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
@ -126,6 +129,8 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
}//if (rcode...
//USBTRACE2("\r\nAddr:", bAddress);
// Spec says you should wait at least 200ms.
delay(300);
p->lowspeed = false;
@ -222,39 +227,52 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if (rcode) {
goto FailSwAcc; //init fails
}
rcode = -1;
rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
delay(1000); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
goto SwAttempt; //switch to accessory mode attempted
/* diagnostic messages */
FailGetDevDescr:
NotifyFailGetDevDescr();
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
goto Fail;
#endif
FailSetDevTblEntry:
NotifyFailSetDevTblEntry();
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry(rcode);
goto Fail;
#endif
FailGetConfDescr:
NotifyFailGetConfDescr();
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr(rcode);
goto Fail;
#endif
FailSetConfDescr:
NotifyFailSetConfDescr();
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr(rcode);
goto Fail;
#endif
FailGetProto:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\ngetProto:");
goto Fail;
#endif
FailSwAcc:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nswAcc:");
goto Fail;
#endif
SwAttempt:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nAccessory mode switch attempt");
// goto Fail;
//FailOnInit:
#endif
//FailOnInit:
// USBTRACE("OnInit:");
// goto Fail;
//

23
adk.h
View file

@ -20,26 +20,8 @@ e-mail : support@circuitsathome.com
#if !defined(_ADK_H_)
#define _ADK_H_
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#define ADK_VID 0x18D1
#define ADK_PID 0x2D00
#define ADB_PID 0x2D01
@ -110,6 +92,7 @@ public:
// USBDeviceConfig implementation
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
@ -125,6 +108,10 @@ public:
return ready;
};
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == ADK_VID && (pid == ADK_PID || pid == ADB_PID));
};
//UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; //class ADK : public USBDeviceConfig ...

119
avrpins.h
View file

@ -17,7 +17,9 @@ e-mail : support@circuitsathome.com
/* derived from Konstantin Chizhov's AVR port templates */
#ifndef _avrpins_h_
#if !defined(_usb_h_) || defined(_avrpins_h_)
#error "Never include avrpins.h directly; include Usb.h instead"
#else
#define _avrpins_h_
#if defined(__AVR__)
@ -25,19 +27,13 @@ e-mail : support@circuitsathome.com
// pointers are 16 bits on AVR
#define pgm_read_pointer(p) pgm_read_word(p)
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */
//#define BOARD_MEGA_ADK
// Support for these boards needs to be manually activated in settings.h or in a makefile
#if !defined(BOARD_MEGA_ADK) && defined(__AVR_ATmega2560__) && USE_UHS_MEGA_ADK
#define BOARD_MEGA_ADK
#elif !defined(BOARD_BLACK_WIDDOW) && USE_UHS_BLACK_WIDDOW
#define BOARD_BLACK_WIDDOW
#endif
/* Uncomment the following if you are using a Teensy 2.0 */
//#define BOARD_TEENSY
/* Uncomment the following if you are using a Sanguino */
//#define BOARD_SANGUINO
#include <avr/io.h>
#ifdef PORTA
#define USE_PORTA
#endif
@ -453,9 +449,8 @@ public:
//typedef Tp_Tc<Pb3, Tc2a> P11; //Arduino pin 11
/* Arduino pin definitions */
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
// "Mega" Arduino pin numbers
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// "Mega" Arduino pin numbers
#define P0 Pe0
#define P1 Pe1
@ -517,10 +512,10 @@ public:
#define P53 Pb0
#define P54 Pe6 // INT on Arduino ADK
#endif //"Mega" pin numbers
// "Mega" pin numbers
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
//"Classic" Arduino pin numbers
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
// "Classic" Arduino pin numbers
#define P0 Pd0
#define P1 Pd1
@ -545,9 +540,39 @@ public:
#define P18 Pc4
#define P19 Pc5
#endif // "Classic" Arduino pin numbers
// "Classic" Arduino pin numbers
#if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
#elif defined(CORE_TEENSY) && defined(__AVR_ATmega32U4__)
// Teensy 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html
#define P0 Pb0
#define P1 Pb1
#define P2 Pb2
#define P3 Pb3
#define P4 Pb7
#define P5 Pd0
#define P6 Pd1
#define P7 Pd2
#define P8 Pd3
#define P9 Pc6
#define P10 Pc7
#define P11 Pd6
#define P12 Pd7
#define P13 Pb4
#define P14 Pb5
#define P15 Pb6
#define P16 Pf7
#define P17 Pf6
#define P18 Pf5
#define P19 Pf4
#define P20 Pf1
#define P21 Pf0
#define P22 Pd4
#define P23 Pd5
#define P24 Pe6
// Teensy 2.0
#elif defined(__AVR_ATmega32U4__)
// Arduino Leonardo pin numbers
#define P0 Pd2 // D0 - PD2
@ -585,39 +610,9 @@ public:
#define P28 Pb6 // D28 / D10 - A10 - PB6
#define P29 Pd6 // D29 / D12 - A11 - PD6
#endif // Arduino Leonardo pin numbers
// Arduino Leonardo pin numbers
#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
// Teensy 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html
#define P0 Pb0
#define P1 Pb1
#define P2 Pb2
#define P3 Pb3
#define P4 Pb7
#define P5 Pd0
#define P6 Pd1
#define P7 Pd2
#define P8 Pd3
#define P9 Pc6
#define P10 Pc7
#define P11 Pd6
#define P12 Pd7
#define P13 Pb4
#define P14 Pb5
#define P15 Pb6
#define P16 Pf7
#define P17 Pf6
#define P18 Pf5
#define P19 Pf4
#define P20 Pf1
#define P21 Pf0
#define P22 Pd4
#define P23 Pd5
#define P24 Pe6
#endif // Teensy 2.0
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
// Teensy++ 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html
#define P0 Pd0
@ -666,10 +661,9 @@ public:
#define P43 Pf5
#define P44 Pf6
#define P45 Pf7
#endif // Teensy++ 2.0
// Teensy++ 2.0
#if !defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
#define BOARD_BALANDUINO
#elif defined(ARDUINO_AVR_BALANDUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__))
// Balanduino pin numbers
// http://balanduino.net/
#define P0 Pd0 /* 0 - PD0 */
@ -685,8 +679,8 @@ public:
#define P10 Pa3 /* 10 - PA3 */
#define P11 Pa4 /* 11 - PA4 */
#define P12 Pa5 /* 12 - PA5 */
#define P13 Pc0 /* 13 - PC0 */
#define P14 Pc1 /* 14 - PC1 */
#define P13 Pc1 /* 13 - PC1 */
#define P14 Pc0 /* 14 - PC0 */
#define P15 Pd2 /* 15 - PD2 */
#define P16 Pd3 /* 16 - PD3 */
#define P17 Pd4 /* 17 - PD4 */
@ -704,11 +698,12 @@ public:
#define P29 Pb7 /* 29 - PB7 */
#define P30 Pa6 /* 30 - PA6 */
#define P31 Pa7 /* 31 - PA7 */
#endif // Balanduino
// Balanduino
#if defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
// Sanguino pin numbers
// http://sanguino.cc/hardware
// Homepage: http://sanguino.cc/hardware
// Hardware add-on: https://github.com/Lauszus/Sanguino
#define P0 Pb0
#define P1 Pb1
#define P2 Pb2
@ -741,7 +736,9 @@ public:
#define P29 Pa5
#define P30 Pa6
#define P31 Pa7
#endif // Sanguino
// Sanguino
#endif // Arduino pin definitions
#endif // __AVR__

View file

@ -183,26 +183,38 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
Fail:
#ifdef DEBUG_USB_HOST
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -276,7 +288,7 @@ uint8_t ACM::Poll() {
// for (uint8_t i=0; i<read; i++)
// {
// PrintHex<uint8_t>(buf[i]);
// Serial.print(" ");
// USB_HOST_SERIAL.print(" ");
// }
// USBTRACE("\r\n");
//}

View file

@ -17,26 +17,8 @@ e-mail : support@circuitsathome.com
#if !defined(__CDCACM_H__)
#define __CDCACM_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE

View file

@ -178,26 +178,38 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
Fail:
#ifdef DEBUG_USB_HOST
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -247,7 +259,7 @@ uint8_t FTDI::Poll() {
//if (qNextPollTime <= millis())
//{
// Serial.println(bAddress, HEX);
// USB_HOST_SERIAL.println(bAddress, HEX);
// qNextPollTime = millis() + 100;
//}

View file

@ -17,26 +17,8 @@ e-mail : support@circuitsathome.com
#if !defined(__CDCFTDI_H__)
#define __CDCFTDI_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#define bmREQ_FTDI_OUT 0x40
#define bmREQ_FTDI_IN 0xc0

View file

@ -151,30 +151,43 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
USBTRACE("PL configured\r\n");
bPollEnable = true;
//bPollEnable = true;
ready = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
Fail:
#ifdef DEBUG_USB_HOST
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -188,7 +201,7 @@ Fail:
//
// //if (qNextPollTime <= millis())
// //{
// // Serial.println(bAddress, HEX);
// // USB_HOST_SERIAL.println(bAddress, HEX);
//
// // qNextPollTime = millis() + 100;
// //}

View file

@ -17,25 +17,6 @@ e-mail : support@circuitsathome.com
#if !defined(__CDCPROLIFIC_H__)
#define __CDCPROLIFIC_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "cdcacm.h"
#define PL_VID 0x067B

View file

@ -14,16 +14,12 @@ Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CONFDESCPARSER_H__)
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
#error "Never include confdescparser.h directly; include Usb.h instead"
#else
#define __CONFDESCPARSER_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "message.h"
#include "parsetools.h"
//#include "hid.h"
class UsbConfigXtracter {
public:
@ -35,7 +31,7 @@ public:
#define CP_MASK_COMPARE_CLASS 1
#define CP_MASK_COMPARE_SUBCLASS 2
#define CP_MASK_COMPARE_PROTOCOL 4
#define CP_MASK_COMPARE_ALL 7
#define CP_MASK_COMPARE_ALL 7
// Configuration Descriptor Parser Class Template
@ -104,10 +100,10 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
dscrType = *((uint8_t*) theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// This is a sort of hack. Assuming that two bytes are allready in the buffer
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
// the pointer is positioned two bytes ahead in order for the rest of descriptor
// to be read right after the size and the type fields.
// This should be used carefuly. varBuffer should be used directly to handle data
// This should be used carefully. varBuffer should be used directly to handle data
// in the buffer.
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;

View file

@ -100,6 +100,8 @@ enum Button {
Y = 15,
XBOX = 16,
SYNC = 17,
BLACK = 8, // Available on the original Xbox controller
WHITE = 9, // Available on the original Xbox controller
/**@}*/
};

View file

@ -5,7 +5,10 @@
*/
#include <PS3BT.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
PS3BT PS3(&Btd); // This will just create the instance

View file

@ -6,20 +6,21 @@
*/
#include <PS3BT.h>
USB Usb;
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
PS3BT PS3_1(&Btd);
PS3BT PS3_2(&Btd);
//PS3BT PS3_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
#include <usbhub.h>
PS3BT* PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
PS3BT *PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
const uint8_t length = sizeof(PS3)/sizeof(PS3[0]); // Get the lenght of the array
boolean printAngle[length];
boolean oldControllerState[length];
void setup() {
PS3[0] = &PS3_1; // This will point to the first controller
PS3[1] = &PS3_2; // This will point to the second controller
//PS3[2] = &PS3_3; // You only need to uncomment this if you wanted to use another controller
for (uint8_t i=0;i<length;i++) {
PS3[i] = new PS3BT(&Btd); // Create the instances
PS3[i]->attachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like
}
Serial.begin(115200);
if (Usb.Init() == -1) {
@ -32,7 +33,6 @@ void loop() {
Usb.Task();
for(uint8_t i=0;i<length;i++) {
if(!PS3[i]) continue; // Skip if it hasn't been defined
if(PS3[i]->PS3Connected || PS3[i]->PS3NavigationConnected) {
if(PS3[i]->getAnalogHat(LeftHatX) > 137 || PS3[i]->getAnalogHat(LeftHatX) < 117 || PS3[i]->getAnalogHat(LeftHatY) > 137 || PS3[i]->getAnalogHat(LeftHatY) < 117 || PS3[i]->getAnalogHat(RightHatX) > 137 || PS3[i]->getAnalogHat(RightHatX) < 117 || PS3[i]->getAnalogHat(RightHatY) > 137 || PS3[i]->getAnalogHat(RightHatY) < 117) {
Serial.print(F("\r\nLeftHatX: "));
@ -58,6 +58,7 @@ void loop() {
if(PS3[i]->getButtonClick(PS)) {
Serial.print(F("\r\nPS"));
PS3[i]->disconnect();
oldControllerState[i] = false; // Reset value
}
else {
if(PS3[i]->getButtonClick(TRIANGLE))
@ -127,3 +128,12 @@ void loop() {
//else if(PS3[i]->PS3MoveConnected) {
}
}
void onInit() {
for (uint8_t i=0;i<length;i++) {
if ((PS3[i]->PS3Connected || PS3[i]->PS3NavigationConnected) && !oldControllerState[i]) {
oldControllerState[i] = true; // Used to check which is the new controller
PS3[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h"
}
}
}

View file

@ -11,7 +11,10 @@
#include <PS3BT.h>
#include <SPP.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instances of the bluetooth services in two ways */

View file

@ -5,7 +5,10 @@
*/
#include <SPP.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "1234"

View file

@ -5,26 +5,19 @@
*/
#include <SPP.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
// This will set the name to the defaults: "Arduino" and the pin to "1234" for both connections
SPP SPP_1(&Btd); // This will allow you to communicate with two SPP devices simultaneously
SPP SPP_2(&Btd);
//SPP SPP_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
// You can also set the name and pin like so
//SPP SerialBT(&Btd, "Lauszus's Arduino","0000");
SPP* SerialBT[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
SPP* SerialBT[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
const uint8_t length = sizeof(SerialBT)/sizeof(SerialBT[0]); // Get the lenght of the array
boolean firstMessage[length] = { true }; // Set all to true
uint8_t buffer[50];
void setup() {
SerialBT[0] = &SPP_1; // This will point to the first instance
SerialBT[1] = &SPP_2; // This will point to the second instance
//SerialBT[2] = &SPP_3; // You only need to uncomment this if you wanted to use another instance
for(uint8_t i=0;i<length;i++)
SerialBT[i] = new SPP(&Btd); // This will set the name to the default: "Arduino" and the pin to "1234" for all connections
Serial.begin(115200);
if (Usb.Init() == -1) {
@ -51,7 +44,7 @@ void loop() {
if(Serial.available()) {
delay(10); // Wait for the rest of the data to arrive
uint8_t i = 0;
while(Serial.available()) // Read the data
while(Serial.available() && i < sizeof(buffer)) // Read the data
buffer[i++] = Serial.read();
/*
Set the connection you want to send to using the first character

View file

@ -5,7 +5,10 @@
*/
#include <Wii.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once

View file

@ -2,24 +2,28 @@
Example sketch for the Wii libary showing the IR camera functionality. This example
is for the Bluetooth Wii library developed for the USB shield from Circuits@Home
Created by Allan Glover and includes much from what Kristian Lauszus wrote in the existing
Wii example. Contact Kristian: http://blog.tkjelectronics.dk/ or send email at kristianl@tkjelectronics.com.
Created by Allan Glover and Kristian Lauszus.
Contact Kristian: http://blog.tkjelectronics.dk/ or send an email at kristianl@tkjelectronics.com.
Contact Allan at adglover9.81@gmail.com
To test the Wiimote IR camera, you will need access to an IR source. Sunlight will work but is not ideal.
The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system. Otherwise,
wire up a IR LED yourself.
The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system.
Otherwise, wire up a IR LED yourself.
*/
#include <Wii.h>
#include <usbhub.h>
#ifndef WIICAMERA // Used to check if WIICAMERA is defined
#error "Uncomment WIICAMERA in Wii.h to use this example"
#endif
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once
//WII Wii(&Btd); // After the wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote
//WII Wii(&Btd); // After the Wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote
bool printAngle;
uint8_t printObjects;
@ -109,7 +113,7 @@ void loop() {
}
}
}
if(printAngle) { // There is no extension bytes avaliable, so the Motionplus or Nunchuck can't be read
if(printAngle) { // There is no extension bytes available, so the MotionPlus or Nunchuck can't be read
Serial.print(F("\r\nPitch: "));
Serial.print(Wii.getPitch());
Serial.print(F("\tRoll: "));

View file

@ -6,21 +6,21 @@
*/
#include <Wii.h>
USB Usb;
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
//WII Wii(&Btd,PAIR); // You will have to pair each controller with the dongle before you can define the instances like below
WII Wii_1(&Btd);
WII Wii_2(&Btd);
//WII Wii_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
#include <usbhub.h>
WII* Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
WII *Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
const uint8_t length = sizeof(Wii)/sizeof(Wii[0]); // Get the lenght of the array
bool printAngle[length];
boolean printAngle[length];
boolean oldControllerState[length];
void setup() {
Wii[0] = &Wii_1;
Wii[1] = &Wii_2;
//Wii[2] = &Wii_3; // You only need to uncomment this if you wanted to use another controller
for (uint8_t i=0;i<length;i++) {
Wii[i] = new WII(&Btd); // You will have to pair each controller with the dongle before you can define the instances like so, just add PAIR as the second argument
Wii[i]->attachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like
}
Serial.begin(115200);
if (Usb.Init() == -1) {
@ -33,12 +33,11 @@ void loop() {
Usb.Task();
for(uint8_t i=0;i<length;i++) {
if(!Wii[i]) continue; // Skip if it hasn't been defined
if(Wii[i]->wiimoteConnected) {
if(Wii[i]->getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down
Serial.print(F("\r\nHOME"));
Wii[i]->disconnect();
delay(1000); // This delay is needed for some Wiimotes, so it doesn't try to reconnect right away
oldControllerState[i] = false; // Reset value
}
else {
if(Wii[i]->getButtonClick(LEFT)) {
@ -112,3 +111,12 @@ void loop() {
}
}
}
void onInit() {
for (uint8_t i=0;i<length;i++) {
if (Wii[i]->wiimoteConnected && !oldControllerState[i]) {
oldControllerState[i] = true; // Used to check which is the new controller
Wii[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h"
}
}
}

View file

@ -5,7 +5,10 @@
*/
#include <Wii.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once

View file

@ -1,19 +1,5 @@
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hidboot.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
class KbdRptParser : public KeyboardReportParser
{

View file

@ -0,0 +1,30 @@
#
# These are set for a mega 1280 + quadram plus my serial patch.
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
#
# If your board is a mega 2560 uncomment the following two lines
# BOARD = mega2560
# PROGRAMMER = wiring
# ...and then comment out the following two lines
BOARD = mega
PROGRAMMER = arduino
# set your Arduino tty port here
PORT = /dev/ttyUSB0
# uncomment the next line to enable debugging
#EXTRA_FLAGS += -D DEBUG_USB_HOST=1
#
# Advanced debug on Serial3
#
# uncomment the next line to enable debug on Serial3
#EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
# The following are the libraries used.
LIB_DIRS =
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
# And finally, the part that brings everything together for you.
include ../Arduino_Makefile_master/_Makefile.master

View file

@ -0,0 +1,170 @@
#include <hidboot.h>
#include <usbhub.h>
class MouseRptParser : public MouseReportParser
{
protected:
virtual void OnMouseMove (MOUSEINFO *mi);
virtual void OnLeftButtonUp (MOUSEINFO *mi);
virtual void OnLeftButtonDown (MOUSEINFO *mi);
virtual void OnRightButtonUp (MOUSEINFO *mi);
virtual void OnRightButtonDown (MOUSEINFO *mi);
virtual void OnMiddleButtonUp (MOUSEINFO *mi);
virtual void OnMiddleButtonDown (MOUSEINFO *mi);
};
void MouseRptParser::OnMouseMove(MOUSEINFO *mi)
{
Serial.print("dx=");
Serial.print(mi->dX, DEC);
Serial.print(" dy=");
Serial.println(mi->dY, DEC);
};
void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi)
{
Serial.println("L Butt Up");
};
void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi)
{
Serial.println("L Butt Dn");
};
void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)
{
Serial.println("R Butt Up");
};
void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi)
{
Serial.println("R Butt Dn");
};
void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi)
{
Serial.println("M Butt Up");
};
void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi)
{
Serial.println("M Butt Dn");
};
class KbdRptParser : public KeyboardReportParser
{
void PrintKey(uint8_t mod, uint8_t key);
protected:
virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
virtual void OnKeyDown (uint8_t mod, uint8_t key);
virtual void OnKeyUp (uint8_t mod, uint8_t key);
virtual void OnKeyPressed(uint8_t key);
};
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
MODIFIERKEYS mod;
*((uint8_t*)&mod) = m;
Serial.print((mod.bmLeftCtrl == 1) ? "C" : " ");
Serial.print((mod.bmLeftShift == 1) ? "S" : " ");
Serial.print((mod.bmLeftAlt == 1) ? "A" : " ");
Serial.print((mod.bmLeftGUI == 1) ? "G" : " ");
Serial.print(" >");
PrintHex<uint8_t>(key, 0x80);
Serial.print("< ");
Serial.print((mod.bmRightCtrl == 1) ? "C" : " ");
Serial.print((mod.bmRightShift == 1) ? "S" : " ");
Serial.print((mod.bmRightAlt == 1) ? "A" : " ");
Serial.println((mod.bmRightGUI == 1) ? "G" : " ");
};
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
{
Serial.print("DN ");
PrintKey(mod, key);
uint8_t c = OemToAscii(mod, key);
if (c)
OnKeyPressed(c);
}
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
MODIFIERKEYS beforeMod;
*((uint8_t*)&beforeMod) = before;
MODIFIERKEYS afterMod;
*((uint8_t*)&afterMod) = after;
if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
Serial.println("LeftCtrl changed");
}
if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
Serial.println("LeftShift changed");
}
if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
Serial.println("LeftAlt changed");
}
if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
Serial.println("LeftGUI changed");
}
if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
Serial.println("RightCtrl changed");
}
if (beforeMod.bmRightShift != afterMod.bmRightShift) {
Serial.println("RightShift changed");
}
if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
Serial.println("RightAlt changed");
}
if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
Serial.println("RightGUI changed");
}
}
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)
{
Serial.print("UP ");
PrintKey(mod, key);
}
void KbdRptParser::OnKeyPressed(uint8_t key)
{
Serial.print("ASCII: ");
Serial.println((char)key);
};
USB Usb;
USBHub Hub(&Usb);
HIDBoot<HID_PROTOCOL_KEYBOARD | HID_PROTOCOL_MOUSE> HidComposite(&Usb);
HIDBoot<HID_PROTOCOL_KEYBOARD> HidKeyboard(&Usb);
HIDBoot<HID_PROTOCOL_MOUSE> HidMouse(&Usb);
//uint32_t next_time;
KbdRptParser KbdPrs;
MouseRptParser MousePrs;
void setup()
{
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
//next_time = millis() + 5000;
HidComposite.SetReportParser(0, (HIDReportParser*)&KbdPrs);
HidComposite.SetReportParser(1,(HIDReportParser*)&MousePrs);
HidKeyboard.SetReportParser(0, (HIDReportParser*)&KbdPrs);
HidMouse.SetReportParser(0,(HIDReportParser*)&MousePrs);
}
void loop()
{
Usb.Task();
}

View file

@ -0,0 +1,75 @@
#!/bin/bash -x
#
# Generated - do not edit!
#
# Macros
TOP=`pwd`
CND_PLATFORM=AVR-Linux-x86
CND_CONF=Default
CND_DISTDIR=dist
CND_BUILDDIR=build
NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
TMPDIRNAME=tmp-packaging
OUTPUT_PATH=MissingOutputInProject
OUTPUT_BASENAME=MissingOutputInProject
PACKAGE_TOP_DIR=USBHIDBootKbdAndMouse/
# Functions
function checkReturnCode
{
rc=$?
if [ $rc != 0 ]
then
exit $rc
fi
}
function makeDirectory
# $1 directory path
# $2 permission (optional)
{
mkdir -p "$1"
checkReturnCode
if [ "$2" != "" ]
then
chmod $2 "$1"
checkReturnCode
fi
}
function copyFileToTmpDir
# $1 from-file path
# $2 to-file path
# $3 permission
{
cp "$1" "$2"
checkReturnCode
if [ "$3" != "" ]
then
chmod $3 "$2"
checkReturnCode
fi
}
# Setup
cd "${TOP}"
mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package
rm -rf ${NBTMPDIR}
mkdir -p ${NBTMPDIR}
# Copy files and create directories and links
cd "${TOP}"
makeDirectory "${NBTMPDIR}/USBHIDBootKbdAndMouse"
copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
# Generate tar file
cd "${TOP}"
rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDBootKbdAndMouse.tar
cd ${NBTMPDIR}
tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDBootKbdAndMouse.tar *
checkReturnCode
# Cleanup
cd "${TOP}"
rm -rf ${NBTMPDIR}

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<configurationDescriptor version="80">
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df name="USBHIDBootKbd" root=".">
<df name="build">
<in>USBHIDBootKbdAndMouse_ino.cpp</in>
</df>
<in>USBHIDBootKbdAndMouse.ino</in>
</df>
<logicalFolder name="ExternalFiles"
displayName="Important Files"
projectFiles="false"
kind="IMPORTANT_FILES_FOLDER">
<itemPath>Makefile</itemPath>
</logicalFolder>
</logicalFolder>
<sourceFolderFilter>^(nbproject)$</sourceFolderFilter>
<sourceRootList>
<Elem>.</Elem>
</sourceRootList>
<projectmakefile>Makefile</projectmakefile>
<confs>
<conf name="Default" type="0">
<toolsSet>
<remote-sources-mode>LOCAL_SOURCES</remote-sources-mode>
<compilerSet>default</compilerSet>
</toolsSet>
<makefileType>
<makeTool>
<buildCommandWorkingDir>.</buildCommandWorkingDir>
<buildCommand>${MAKE} -f Makefile</buildCommand>
<cleanCommand>${MAKE} -f Makefile clean</cleanCommand>
<executablePath></executablePath>
</makeTool>
</makefileType>
</conf>
</confs>
</configurationDescriptor>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.cnd.makeproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/make-project/1">
<name>USBHIDBootKbdAndMouse</name>
<c-extensions/>
<cpp-extensions>cpp,ino</cpp-extensions>
<header-extensions/>
<sourceEncoding>UTF-8</sourceEncoding>
<make-dep-projects/>
<sourceRootList>
<sourceRootElem>.</sourceRootElem>
</sourceRootList>
<confList>
<confElem>
<name>Default</name>
<type>0</type>
</confElem>
</confList>
</data>
</configuration>
</project>

View file

@ -1,17 +1,5 @@
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hidboot.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
class MouseRptParser : public MouseReportParser
{

View file

@ -0,0 +1,30 @@
#
# These are set for a mega 1280 + quadram plus my serial patch.
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
#
# If your board is a mega 2560 uncomment the following two lines
# BOARD = mega2560
# PROGRAMMER = wiring
# ...and then comment out the following two lines
BOARD = mega
PROGRAMMER = arduino
# set your Arduino tty port here
PORT = /dev/ttyUSB0
# uncomment the next line to enable debugging
#EXTRA_FLAGS += -D DEBUG_USB_HOST=1
#
# Advanced debug on Serial3
#
# uncomment the next line to enable debug on Serial3
#EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
# The following are the libraries used.
LIB_DIRS =
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
# And finally, the part that brings everything together for you.
include ../Arduino_Makefile_master/_Makefile.master

View file

@ -1,46 +1,29 @@
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hid.h>
#include <hiduniversal.h>
#include <usbhub.h>
#include "hidjoystickrptparser.h"
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents);
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents);
void setup() {
Serial.begin(115200);
Serial.println("Start");
void setup()
{
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay(200);
delay( 200 );
if (!Hid.SetReportParser(0, &Joy))
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 );
if (!Hid.SetReportParser(0, &Joy))
ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
}
void loop()
{
Usb.Task();
void loop() {
Usb.Task();
}

View file

@ -1,95 +1,84 @@
#include "hidjoystickrptparser.h"
JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
joyEvents(evt),
oldHat(0xDE),
oldButtons(0)
{
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++)
oldPad[i] = 0xD;
joyEvents(evt),
oldHat(0xDE),
oldButtons(0) {
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
oldPad[i] = 0xD;
}
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
bool match = true;
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
bool match = true;
// Checking if there are changes in report since the method was last called
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++)
if (buf[i] != oldPad[i])
{
match = false;
break;
}
// Checking if there are changes in report since the method was last called
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
if (buf[i] != oldPad[i]) {
match = false;
break;
}
// Calling Game Pad event handler
if (!match && joyEvents)
{
joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
// Calling Game Pad event handler
if (!match && joyEvents) {
joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
}
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
}
uint8_t hat = (buf[5] & 0xF);
uint8_t hat = (buf[5] & 0xF);
// Calling Hat Switch event handler
if (hat != oldHat && joyEvents)
{
joyEvents->OnHatSwitch(hat);
oldHat = hat;
}
// Calling Hat Switch event handler
if (hat != oldHat && joyEvents) {
joyEvents->OnHatSwitch(hat);
oldHat = hat;
}
uint16_t buttons = (0x0000 | buf[6]);
buttons <<= 4;
buttons |= (buf[5] >> 4);
uint16_t changes = (buttons ^ oldButtons);
uint16_t buttons = (0x0000 | buf[6]);
buttons <<= 4;
buttons |= (buf[5] >> 4);
uint16_t changes = (buttons ^ oldButtons);
// Calling Button Event Handler for every button changed
if (changes)
{
for (uint8_t i=0; i<0x0C; i++)
{
uint16_t mask = (0x0001 << i);
// Calling Button Event Handler for every button changed
if (changes) {
for (uint8_t i = 0; i < 0x0C; i++) {
uint16_t mask = (0x0001 << i);
if (((mask & changes) > 0) && joyEvents)
if ((buttons & mask) > 0)
joyEvents->OnButtonDn(i+1);
else
joyEvents->OnButtonUp(i+1);
}
oldButtons = buttons;
}
if (((mask & changes) > 0) && joyEvents)
if ((buttons & mask) > 0)
joyEvents->OnButtonDn(i + 1);
else
joyEvents->OnButtonUp(i + 1);
}
oldButtons = buttons;
}
}
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
{
Serial.print("X: ");
PrintHex<uint8_t>(evt->X, 0x80);
Serial.print("\tY: ");
PrintHex<uint8_t>(evt->Y, 0x80);
Serial.print("\tZ: ");
PrintHex<uint8_t>(evt->Z1, 0x80);
Serial.print("\tZ: ");
PrintHex<uint8_t>(evt->Z2, 0x80);
Serial.print("\tRz: ");
PrintHex<uint8_t>(evt->Rz, 0x80);
Serial.println("");
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) {
Serial.print("X1: ");
PrintHex<uint8_t > (evt->X, 0x80);
Serial.print("\tY1: ");
PrintHex<uint8_t > (evt->Y, 0x80);
Serial.print("\tX2: ");
PrintHex<uint8_t > (evt->Z1, 0x80);
Serial.print("\tY2: ");
PrintHex<uint8_t > (evt->Z2, 0x80);
Serial.print("\tRz: ");
PrintHex<uint8_t > (evt->Rz, 0x80);
Serial.println("");
}
void JoystickEvents::OnHatSwitch(uint8_t hat)
{
Serial.print("Hat Switch: ");
PrintHex<uint8_t>(hat, 0x80);
Serial.println("");
void JoystickEvents::OnHatSwitch(uint8_t hat) {
Serial.print("Hat Switch: ");
PrintHex<uint8_t > (hat, 0x80);
Serial.println("");
}
void JoystickEvents::OnButtonUp(uint8_t but_id)
{
Serial.print("Up: ");
Serial.println(but_id, DEC);
void JoystickEvents::OnButtonUp(uint8_t but_id) {
Serial.print("Up: ");
Serial.println(but_id, DEC);
}
void JoystickEvents::OnButtonDn(uint8_t but_id)
{
Serial.print("Dn: ");
Serial.println(but_id, DEC);
void JoystickEvents::OnButtonDn(uint8_t but_id) {
Serial.print("Dn: ");
Serial.println(but_id, DEC);
}

View file

@ -1,54 +1,33 @@
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
#define __HIDJOYSTICKRPTPARSER_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include <hid.h>
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "hid.h"
struct GamePadEventData
{
uint8_t X, Y, Z1, Z2, Rz;
struct GamePadEventData {
uint8_t X, Y, Z1, Z2, Rz;
};
class JoystickEvents
{
class JoystickEvents {
public:
virtual void OnGamePadChanged(const GamePadEventData *evt);
virtual void OnHatSwitch(uint8_t hat);
virtual void OnButtonUp(uint8_t but_id);
virtual void OnButtonDn(uint8_t but_id);
virtual void OnGamePadChanged(const GamePadEventData *evt);
virtual void OnHatSwitch(uint8_t hat);
virtual void OnButtonUp(uint8_t but_id);
virtual void OnButtonDn(uint8_t but_id);
};
#define RPT_GEMEPAD_LEN 5
class JoystickReportParser : public HIDReportParser
{
JoystickEvents *joyEvents;
class JoystickReportParser : public HIDReportParser {
JoystickEvents *joyEvents;
uint8_t oldPad[RPT_GEMEPAD_LEN];
uint8_t oldHat;
uint16_t oldButtons;
uint8_t oldPad[RPT_GEMEPAD_LEN];
uint8_t oldHat;
uint16_t oldButtons;
public:
JoystickReportParser(JoystickEvents *evt);
JoystickReportParser(JoystickEvents *evt);
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
#endif // __HIDJOYSTICKRPTPARSER_H__

View file

@ -0,0 +1,75 @@
#!/bin/bash -x
#
# Generated - do not edit!
#
# Macros
TOP=`pwd`
CND_PLATFORM=AVR-Linux-x86
CND_CONF=Default
CND_DISTDIR=dist
CND_BUILDDIR=build
NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
TMPDIRNAME=tmp-packaging
OUTPUT_PATH=MissingOutputInProject
OUTPUT_BASENAME=MissingOutputInProject
PACKAGE_TOP_DIR=USBHIDJoystick/
# Functions
function checkReturnCode
{
rc=$?
if [ $rc != 0 ]
then
exit $rc
fi
}
function makeDirectory
# $1 directory path
# $2 permission (optional)
{
mkdir -p "$1"
checkReturnCode
if [ "$2" != "" ]
then
chmod $2 "$1"
checkReturnCode
fi
}
function copyFileToTmpDir
# $1 from-file path
# $2 to-file path
# $3 permission
{
cp "$1" "$2"
checkReturnCode
if [ "$3" != "" ]
then
chmod $3 "$2"
checkReturnCode
fi
}
# Setup
cd "${TOP}"
mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package
rm -rf ${NBTMPDIR}
mkdir -p ${NBTMPDIR}
# Copy files and create directories and links
cd "${TOP}"
makeDirectory "${NBTMPDIR}/USBHIDJoystick"
copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
# Generate tar file
cd "${TOP}"
rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDJoystick.tar
cd ${NBTMPDIR}
tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDJoystick.tar *
checkReturnCode
# Cleanup
cd "${TOP}"
rm -rf ${NBTMPDIR}

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<configurationDescriptor version="80">
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df name="USBHIDJoystick" root=".">
<df name="build">
<in>CDC.lst</in>
<in>HID.lst</in>
<in>HardwareSerial.lst</in>
<in>IPAddress.lst</in>
<in>Print.lst</in>
<in>Stream.lst</in>
<in>Tone.lst</in>
<in>USBCore.lst</in>
<in>WInterrupts.lst</in>
<in>WMath.lst</in>
<in>WString.lst</in>
<in>wiring.lst</in>
<in>wiring_analog.lst</in>
<in>wiring_digital.lst</in>
<in>wiring_pulse.lst</in>
<in>wiring_shift.lst</in>
</df>
<in>USBHIDJoystick.ino</in>
<in>hidjoystickrptparser.cpp</in>
<in>hidjoystickrptparser.h</in>
</df>
<logicalFolder name="ExternalFiles"
displayName="Important Files"
projectFiles="false"
kind="IMPORTANT_FILES_FOLDER">
<itemPath>Makefile</itemPath>
</logicalFolder>
</logicalFolder>
<sourceFolderFilter>^(nbproject)$</sourceFolderFilter>
<sourceRootList>
<Elem>.</Elem>
</sourceRootList>
<projectmakefile>Makefile</projectmakefile>
<confs>
<conf name="Default" type="0">
<toolsSet>
<remote-sources-mode>LOCAL_SOURCES</remote-sources-mode>
<compilerSet>default</compilerSet>
</toolsSet>
<makefileType>
<makeTool>
<buildCommandWorkingDir>.</buildCommandWorkingDir>
<buildCommand>${MAKE} -f Makefile</buildCommand>
<cleanCommand>${MAKE} -f Makefile clean</cleanCommand>
<executablePath></executablePath>
</makeTool>
</makefileType>
</conf>
</confs>
</configurationDescriptor>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.cnd.makeproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/make-project/1">
<name>USBHIDJoystick</name>
<c-extensions/>
<cpp-extensions>cpp,ino</cpp-extensions>
<header-extensions>h</header-extensions>
<sourceEncoding>UTF-8</sourceEncoding>
<make-dep-projects/>
<sourceRootList>
<sourceRootElem>.</sourceRootElem>
</sourceRootList>
<confList>
<confElem>
<name>Default</name>
<type>0</type>
</confElem>
</confList>
</data>
</configuration>
</project>

View file

@ -1,21 +1,7 @@
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hid.h>
#include <hiduniversal.h>
#include <hidescriptorparser.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
#include "pgmstrings.h"

View file

@ -1,25 +1,11 @@
/* Simplified Logitech Extreme 3D Pro Joystick Report Parser */
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hid.h>
#include <hiduniversal.h>
#include <usbhub.h>
#include "le3dp_rptparser.h"
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);

View file

@ -1,25 +1,7 @@
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
#define __HIDJOYSTICKRPTPARSER_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "hid.h"
#include <hid.h>
struct GamePadEventData
{

View file

@ -0,0 +1,42 @@
/* Digital Scale Output. Written for Stamps.com Model 510 */
/* 5lb Digital Scale; any HID scale with Usage page 0x8d should work */
#include <hid.h>
#include <hiduniversal.h>
#include <usbhub.h>
#include "scale_rptparser.h"
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
Max_LCD LCD(&Usb);
ScaleEvents ScaleEvents(&LCD);
ScaleReportParser Scale(&ScaleEvents);
void setup()
{
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
// set up the LCD's number of rows and columns:
LCD.begin(16, 2);
LCD.clear();
LCD.home();
LCD.setCursor(0,0);
LCD.write('R');
delay( 200 );
if (!Hid.SetReportParser(0, &Scale))
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 );
}
void loop()
{
Usb.Task();
}

View file

@ -0,0 +1,150 @@
/* Parser for standard HID scale (usage page 0x8d) data input report (ID 3) */
#include "scale_rptparser.h"
const char* UNITS[13] = {
"units", // unknown unit
"mg", // milligram
"g", // gram
"kg", // kilogram
"cd", // carat
"taels", // lian
"gr", // grain
"dwt", // pennyweight
"tonnes", // metric tons
"tons", // avoir ton
"ozt", // troy ounce
"oz", // ounce
"lbs" // pound
};
ScaleReportParser::ScaleReportParser(ScaleEvents *evt) :
scaleEvents(evt)
{}
void ScaleReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
bool match = true;
// Checking if there are changes in report since the method was last called
for (uint8_t i=0; i<RPT_SCALE_LEN; i++) {
if( buf[i] != oldScale[i] ) {
match = false;
break;
}
}
// Calling Game Pad event handler
if (!match && scaleEvents) {
scaleEvents->OnScaleChanged((const ScaleEventData*)buf);
for (uint8_t i=0; i<RPT_SCALE_LEN; i++) oldScale[i] = buf[i];
}
}
ScaleEvents::ScaleEvents( Max_LCD* pLCD ) :
pLcd( pLCD )
{}
void ScaleEvents::LcdPrint( const char* str )
{
while( *str ) {
pLcd->write( *str++ );
}
}
void ScaleEvents::OnScaleChanged(const ScaleEventData *evt)
{
pLcd->clear();
pLcd->home();
pLcd->setCursor(0,0);
if( evt->reportID != 3 ) {
const char inv_report[]="Invalid report!";
Serial.println(inv_report);
LcdPrint(inv_report);
return;
}//if( evt->reportID != 3...
switch( evt->status ) {
case REPORT_FAULT:
Serial.println(F("Report fault"));
break;
case ZEROED:
Serial.println(F("Scale zero set"));
break;
case WEIGHING: {
const char progress[] = "Weighing...";
Serial.println(progress);
LcdPrint(progress);
break;
}
case WEIGHT_VALID: {
char buf[10];
double weight = evt->weight * pow( 10, evt->exp );
Serial.print(F("Weight: "));
Serial.print( weight );
Serial.print(F(" "));
Serial.println( UNITS[ evt->unit ]);
LcdPrint("Weight: ");
dtostrf( weight, 4, 2, buf );
LcdPrint( buf );
LcdPrint( UNITS[ evt->unit ]);
break;
}//case WEIGHT_VALID...
case WEIGHT_NEGATIVE: {
const char negweight[] = "Negative weight";
Serial.println(negweight);
LcdPrint(negweight);
break;
}
case OVERWEIGHT: {
const char overweight[] = "Max.weight reached";
Serial.println(overweight);
LcdPrint( overweight );
break;
}
case CALIBRATE_ME:
Serial.println(F("Scale calibration required"));
break;
case ZERO_ME:
Serial.println(F("Scale zeroing required"));
break;
default:
Serial.print(F("Undefined status code: "));
Serial.println( evt->status );
break;
}//switch( evt->status...
}

View file

@ -0,0 +1,55 @@
#if !defined(__SCALERPTPARSER_H__)
#define __SCALERPTPARSER_H__
#include <Max_LCD.h>
#include <hid.h>
/* Scale status constants */
#define REPORT_FAULT 0x01
#define ZEROED 0x02
#define WEIGHING 0x03
#define WEIGHT_VALID 0x04
#define WEIGHT_NEGATIVE 0x05
#define OVERWEIGHT 0x06
#define CALIBRATE_ME 0x07
#define ZERO_ME 0x08
/* input data report */
struct ScaleEventData
{
uint8_t reportID; //must be 3
uint8_t status;
uint8_t unit;
int8_t exp; //scale factor for the weight
uint16_t weight; //
};
class ScaleEvents
{
Max_LCD* pLcd;
void LcdPrint( const char* str );
public:
ScaleEvents( Max_LCD* pLCD );
virtual void OnScaleChanged(const ScaleEventData *evt);
};
#define RPT_SCALE_LEN sizeof(ScaleEventData)/sizeof(uint8_t)
class ScaleReportParser : public HIDReportParser
{
ScaleEvents *scaleEvents;
uint8_t oldScale[RPT_SCALE_LEN];
public:
ScaleReportParser(ScaleEvents *evt);
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
#endif // __SCALERPTPARSER_H__

View file

@ -5,6 +5,7 @@
*/
#include <PS3USB.h>
USB Usb;
/* You can create the instance of the class in two ways */
PS3USB PS3(&Usb); // This will just create the instance

View file

@ -1,11 +1,4 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include "pgmstrings.h"

View file

@ -0,0 +1,100 @@
/*
Example sketch for the original Xbox library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <XBOXOLD.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb); // The controller has a built in hub, so this instance is needed
XBOXOLD Xbox(&Usb);
void setup() {
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); // halt
}
Serial.print(F("\r\nXBOX Library Started"));
}
void loop() {
Usb.Task();
if(Xbox.XboxConnected) {
if(Xbox.getButtonPress(BLACK) || Xbox.getButtonPress(WHITE)) {
Serial.print("BLACK: ");
Serial.print(Xbox.getButtonPress(BLACK));
Serial.print("\tWHITE: ");
Serial.println(Xbox.getButtonPress(WHITE));
Xbox.setRumbleOn(Xbox.getButtonPress(BLACK),Xbox.getButtonPress(WHITE));
} else
Xbox.setRumbleOn(0,0);
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500 || Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500 || Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500 || Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500) {
Serial.print(F("LeftHatX: "));
Serial.print(Xbox.getAnalogHat(LeftHatX));
Serial.print("\t");
}
if(Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500) {
Serial.print(F("LeftHatY: "));
Serial.print(Xbox.getAnalogHat(LeftHatY));
Serial.print("\t");
}
if(Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500) {
Serial.print(F("RightHatX: "));
Serial.print(Xbox.getAnalogHat(RightHatX));
Serial.print("\t");
}
if(Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
Serial.print(F("RightHatY: "));
Serial.print(Xbox.getAnalogHat(RightHatY));
}
Serial.println();
}
if(Xbox.getButtonClick(UP))
Serial.println(F("Up"));
if(Xbox.getButtonClick(DOWN))
Serial.println(F("Down"));
if(Xbox.getButtonClick(LEFT))
Serial.println(F("Left"));
if(Xbox.getButtonClick(RIGHT))
Serial.println(F("Right"));
if(Xbox.getButtonClick(START))
Serial.println(F("Start"));
if(Xbox.getButtonClick(BACK))
Serial.println(F("Back"));
if(Xbox.getButtonClick(L3))
Serial.println(F("L3"));
if(Xbox.getButtonClick(R3))
Serial.println(F("R3"));
if(Xbox.getButtonPress(A)) {
Serial.print(F("A: "));
Serial.println(Xbox.getButtonPress(A));
}
if(Xbox.getButtonPress(B)) {
Serial.print(F("B: "));
Serial.println(Xbox.getButtonPress(B));
}
if(Xbox.getButtonPress(X)) {
Serial.print(F("X: "));
Serial.println(Xbox.getButtonPress(X));
}
if(Xbox.getButtonPress(Y)) {
Serial.print(F("Y: "));
Serial.println(Xbox.getButtonPress(Y));
}
if(Xbox.getButtonPress(L1)) {
Serial.print(F("L1: "));
Serial.println(Xbox.getButtonPress(L1));
}
if(Xbox.getButtonPress(R1)) {
Serial.print(F("R1: "));
Serial.println(Xbox.getButtonPress(R1));
}
}
delay(1);
}

View file

@ -6,6 +6,7 @@
*/
#include <XBOXRECV.h>
USB Usb;
XBOXRECV Xbox(&Usb);
@ -27,7 +28,7 @@ void loop() {
Serial.print(Xbox.getButtonPress(L2,i));
Serial.print("\tR2: ");
Serial.println(Xbox.getButtonPress(R2,i));
Xbox.setRumbleOn(Xbox.getButtonPress(L2,i),Xbox.getButtonPress(R2,i));
Xbox.setRumbleOn(Xbox.getButtonPress(L2,i),Xbox.getButtonPress(R2,i),i);
}
if(Xbox.getAnalogHat(LeftHatX,i) > 7500 || Xbox.getAnalogHat(LeftHatX,i) < -7500 || Xbox.getAnalogHat(LeftHatY,i) > 7500 || Xbox.getAnalogHat(LeftHatY,i) < -7500 || Xbox.getAnalogHat(RightHatX,i) > 7500 || Xbox.getAnalogHat(RightHatX,i) < -7500 || Xbox.getAnalogHat(RightHatY,i) > 7500 || Xbox.getAnalogHat(RightHatY,i) < -7500) {
if(Xbox.getAnalogHat(LeftHatX,i) > 7500 || Xbox.getAnalogHat(LeftHatX,i) < -7500) {

View file

@ -5,6 +5,7 @@
*/
#include <XBOXUSB.h>
USB Usb;
XBOXUSB Xbox(&Usb);

View file

@ -1,18 +1,5 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <cdcacm.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
#include "pgmstrings.h"

View file

@ -1,7 +1,5 @@
// The source for the Android application can be found at the following link: https://github.com/Lauszus/ArduinoBlinkLED
// The code for the Android application is heavily based on this guide: http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/ by Miguel
#include <Usb.h>
#include <adk.h>
USB Usb;

View file

@ -1,18 +1,9 @@
/**/
/* A sketch demonstrating data exchange between two USB devices - a HID barcode scanner and ADK-compatible Android phone */
/**/
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <adk.h>
#include <hidboot.h>
#include <usbhub.h>
USB Usb;
USBHub Hub1(&Usb);

View file

@ -1,18 +1,5 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <adk.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
USB Usb;
USBHub hub0(&Usb);

View file

@ -1,13 +1,5 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <adk.h>
#include <usbhub.h>
USB Usb;
//USBHub Hub(&Usb);

View file

@ -1,13 +1,5 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <adk.h>
#include <usbhub.h>
USB Usb;

View file

@ -1,16 +1,9 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
/* USB Host Shield 2.0 board quality control routine */
/* To see the output set your terminal speed to 115200 */
/* for GPIO test to pass you need to connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, etc. */
/* otherwise press any key after getting GPIO error to complete the test */
/**/
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
/* variables */
uint8_t rcode;
@ -26,24 +19,24 @@ USB Usb;
void setup()
{
Serial.begin( 115200 );
Notify(PSTR("\r\nCircuits At Home 2011"),0x80);
Notify(PSTR("\r\nUSB Host Shield Quality Control Routine"),0x80);
E_Notify(PSTR("\r\nCircuits At Home 2011"),0x80);
E_Notify(PSTR("\r\nUSB Host Shield Quality Control Routine"),0x80);
/* SPI quick test - check revision register */
Notify(PSTR("\r\nReading REVISION register... Die revision "),0x80);
E_Notify(PSTR("\r\nReading REVISION register... Die revision "),0x80);
{
uint8_t tmpbyte = Usb.regRd( rREVISION );
switch( tmpbyte ) {
case( 0x01): //rev.01
Notify(PSTR("01"),0x80);
E_Notify(PSTR("01"),0x80);
break;
case( 0x12): //rev.02
Notify(PSTR("02"),0x80);
E_Notify(PSTR("02"),0x80);
break;
case( 0x13): //rev.03
Notify(PSTR("03"),0x80);
E_Notify(PSTR("03"),0x80);
break;
default:
Notify(PSTR("invalid. Value returned: "),0x80);
E_Notify(PSTR("invalid. Value returned: "),0x80);
print_hex( tmpbyte, 8 );
halt55();
break;
@ -51,7 +44,7 @@ void setup()
}//check revision register
/* SPI long test */
{
Notify(PSTR("\r\nSPI long test. Transfers 1MB of data. Each dot is 64K"),0x80);
E_Notify(PSTR("\r\nSPI long test. Transfers 1MB of data. Each dot is 64K"),0x80);
uint8_t sample_wr = 0;
uint8_t sample_rd = 0;
uint8_t gpinpol_copy = Usb.regRd( rGPINPOL );
@ -60,73 +53,73 @@ void setup()
Usb.regWr( rGPINPOL, sample_wr );
sample_rd = Usb.regRd( rGPINPOL );
if( sample_rd != sample_wr ) {
Notify(PSTR("\r\nTest failed. "),0x80);
Notify(PSTR("Value written: "),0x80);
E_Notify(PSTR("\r\nTest failed. "),0x80);
E_Notify(PSTR("Value written: "),0x80);
print_hex( sample_wr, 8 );
Notify(PSTR(" read: "),0x80);
E_Notify(PSTR(" read: "),0x80);
print_hex( sample_rd, 8 );
halt55();
}//if( sample_rd != sample_wr..
sample_wr++;
}//for( uint16_t j...
Notify(PSTR("."),0x80);
E_Notify(PSTR("."),0x80);
}//for( uint8_t i...
Usb.regWr( rGPINPOL, gpinpol_copy );
Notify(PSTR(" SPI long test passed"),0x80);
E_Notify(PSTR(" SPI long test passed"),0x80);
}//SPI long test
/* GPIO test */
/* in order to simplify board layout, GPIN pins on text fixture are connected to GPOUT */
/* in reverse order, i.e, GPIN0 is connected to GPOUT7, GPIN1 to GPOUT6, etc. */
{
uint8_t tmpbyte;
Notify(PSTR("\r\nGPIO test. Connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, and so on"),0x80);
E_Notify(PSTR("\r\nGPIO test. Connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, and so on"),0x80);
for( uint8_t sample_gpio = 0; sample_gpio < 255; sample_gpio++ ) {
Usb.gpioWr( sample_gpio );
tmpbyte = Usb.gpioRd();
/* bit reversing code copied vetbatim from http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
tmpbyte = ((tmpbyte * 0x0802LU & 0x22110LU) | (tmpbyte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
if( sample_gpio != tmpbyte ) {
Notify(PSTR("\r\nTest failed. Value written: "),0x80);
E_Notify(PSTR("\r\nTest failed. Value written: "),0x80);
print_hex( sample_gpio, 8 );
Notify(PSTR(" Value read: "),0x80);
E_Notify(PSTR(" Value read: "),0x80);
print_hex( tmpbyte , 8 );
Notify(PSTR(" "),0x80);
E_Notify(PSTR(" "),0x80);
press_any_key();
break;
}//if( sample_gpio != tmpbyte...
}//for( uint8_t sample_gpio...
Notify(PSTR("\r\nGPIO test passed."),0x80);
E_Notify(PSTR("\r\nGPIO test passed."),0x80);
}//GPIO test
/* PLL test. Stops/starts MAX3421E oscillator several times */
{
Notify(PSTR("\r\nPLL test. 100 chip resets will be performed"),0x80);
E_Notify(PSTR("\r\nPLL test. 100 chip resets will be performed"),0x80);
/* check current state of the oscillator */
if(!( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wrong state - should be on
Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
E_Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
press_any_key();
}
/* Restart oscillator */
Notify(PSTR("\r\nResetting oscillator"),0x80);
E_Notify(PSTR("\r\nResetting oscillator"),0x80);
for( uint16_t i = 0; i < 101; i++ ) {
Notify(PSTR("\rReset number "),0x80);
E_Notify(PSTR("\rReset number "),0x80);
Serial.print( i, DEC );
Usb.regWr( rUSBCTL, bmCHIPRES ); //reset
if( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ ) { //wrong state - should be off
Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
E_Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
halt55();
}
Usb.regWr( rUSBCTL, 0x00 ); //release from reset
uint16_t j = 0;
for( j = 0; j < 65535; j++ ) { //tracking off to on time
if( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ ) {
Notify(PSTR(" Time to stabilize - "),0x80);
E_Notify(PSTR(" Time to stabilize - "),0x80);
Serial.print( j, DEC );
Notify(PSTR(" cycles"),0x80);
E_Notify(PSTR(" cycles"),0x80);
break;
}
}//for( uint16_t j = 0; j < 65535; j++
if( j == 0 ) {
Notify(PSTR("PLL failed to stabilize"),0x80);
E_Notify(PSTR("PLL failed to stabilize"),0x80);
press_any_key();
}
}//for( uint8_t i = 0; i < 255; i++
@ -134,10 +127,10 @@ void setup()
}//PLL test
/* initializing USB stack */
if (Usb.Init() == -1) {
Notify(PSTR("\r\nOSCOKIRQ failed to assert"),0x80);
E_Notify(PSTR("\r\nOSCOKIRQ failed to assert"),0x80);
halt55();
}
Notify(PSTR("\r\nChecking USB device communication.\r\n"),0x80);
E_Notify(PSTR("\r\nChecking USB device communication.\r\n"),0x80);
}
void loop()
@ -148,65 +141,65 @@ void loop()
/**/
switch( usbstate ) {
case( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ):
Notify(PSTR("\rWaiting for device ..."),0x80);
E_Notify(PSTR("\rWaiting for device ..."),0x80);
break;
case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ):
Notify(PSTR("\r\nDevice connected. Resetting"),0x80);
E_Notify(PSTR("\r\nDevice connected. Resetting"),0x80);
break;
case( USB_ATTACHED_SUBSTATE_WAIT_SOF ):
Notify(PSTR("\rReset complete. Waiting for the first SOF..."),0x80);
E_Notify(PSTR("\rReset complete. Waiting for the first SOF..."),0x80);
break;
case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ):
Notify(PSTR("\r\nSOF generation started. Enumerating device."),0x80);
E_Notify(PSTR("\r\nSOF generation started. Enumerating device."),0x80);
break;
case( USB_STATE_ADDRESSING ):
Notify(PSTR("\r\nSetting device address"),0x80);
E_Notify(PSTR("\r\nSetting device address"),0x80);
break;
case( USB_STATE_RUNNING ):
Notify(PSTR("\r\nGetting device descriptor"),0x80);
E_Notify(PSTR("\r\nGetting device descriptor"),0x80);
rcode = Usb.getDevDescr( 1, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)&buf );
if( rcode ) {
Notify(PSTR("\rError reading device descriptor. Error code "),0x80);
E_Notify(PSTR("\rError reading device descriptor. Error code "),0x80);
print_hex( rcode, 8 );
}
else {
/**/
Notify(PSTR("\r\nDescriptor Length:\t"),0x80);
E_Notify(PSTR("\r\nDescriptor Length:\t"),0x80);
print_hex( buf.bLength, 8 );
Notify(PSTR("\r\nDescriptor type:\t"),0x80);
E_Notify(PSTR("\r\nDescriptor type:\t"),0x80);
print_hex( buf.bDescriptorType, 8 );
Notify(PSTR("\r\nUSB version:\t\t"),0x80);
E_Notify(PSTR("\r\nUSB version:\t\t"),0x80);
print_hex( buf.bcdUSB, 16 );
Notify(PSTR("\r\nDevice class:\t\t"),0x80);
E_Notify(PSTR("\r\nDevice class:\t\t"),0x80);
print_hex( buf.bDeviceClass, 8 );
Notify(PSTR("\r\nDevice Subclass:\t"),0x80);
E_Notify(PSTR("\r\nDevice Subclass:\t"),0x80);
print_hex( buf.bDeviceSubClass, 8 );
Notify(PSTR("\r\nDevice Protocol:\t"),0x80);
E_Notify(PSTR("\r\nDevice Protocol:\t"),0x80);
print_hex( buf.bDeviceProtocol, 8 );
Notify(PSTR("\r\nMax.packet size:\t"),0x80);
E_Notify(PSTR("\r\nMax.packet size:\t"),0x80);
print_hex( buf.bMaxPacketSize0, 8 );
Notify(PSTR("\r\nVendor ID:\t\t"),0x80);
E_Notify(PSTR("\r\nVendor ID:\t\t"),0x80);
print_hex( buf.idVendor, 16 );
Notify(PSTR("\r\nProduct ID:\t\t"),0x80);
E_Notify(PSTR("\r\nProduct ID:\t\t"),0x80);
print_hex( buf.idProduct, 16 );
Notify(PSTR("\r\nRevision ID:\t\t"),0x80);
E_Notify(PSTR("\r\nRevision ID:\t\t"),0x80);
print_hex( buf.bcdDevice, 16 );
Notify(PSTR("\r\nMfg.string index:\t"),0x80);
E_Notify(PSTR("\r\nMfg.string index:\t"),0x80);
print_hex( buf.iManufacturer, 8 );
Notify(PSTR("\r\nProd.string index:\t"),0x80);
E_Notify(PSTR("\r\nProd.string index:\t"),0x80);
print_hex( buf.iProduct, 8 );
Notify(PSTR("\r\nSerial number index:\t"),0x80);
E_Notify(PSTR("\r\nSerial number index:\t"),0x80);
print_hex( buf.iSerialNumber, 8 );
Notify(PSTR("\r\nNumber of conf.:\t"),0x80);
E_Notify(PSTR("\r\nNumber of conf.:\t"),0x80);
print_hex( buf.bNumConfigurations, 8 );
/**/
Notify(PSTR("\r\n\nAll tests passed. Press RESET to restart test"),0x80);
E_Notify(PSTR("\r\n\nAll tests passed. Press RESET to restart test"),0x80);
while(1);
}
break;
case( USB_STATE_ERROR ):
Notify(PSTR("\rUSB state machine reached error state"),0x80);
E_Notify(PSTR("\rUSB state machine reached error state"),0x80);
break;
default:
@ -219,9 +212,9 @@ void loop()
void halt55()
{
Notify(PSTR("\r\nUnrecoverable error - test halted!!"),0x80);
Notify(PSTR("\r\n0x55 pattern is transmitted via SPI"),0x80);
Notify(PSTR("\r\nPress RESET to restart test"),0x80);
E_Notify(PSTR("\r\nUnrecoverable error - test halted!!"),0x80);
E_Notify(PSTR("\r\n0x55 pattern is transmitted via SPI"),0x80);
E_Notify(PSTR("\r\nPress RESET to restart test"),0x80);
while( 1 ) {
Usb.regWr( 0x55, 0x55 );
@ -249,7 +242,7 @@ void print_hex(int v, int num_places)
/* prints "Press any key" and returns when key is pressed */
void press_any_key()
{
Notify(PSTR("\r\nPress any key to continue..."),0x80);
E_Notify(PSTR("\r\nPress any key to continue..."),0x80);
while( Serial.available() <= 0 ); //wait for input
Serial.read(); //empty input buffer
return;

View file

@ -1,18 +1,5 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <cdcftdi.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <usbhub.h>
#include "pgmstrings.h"

View file

@ -1,11 +1,4 @@
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include "pgmstrings.h"
USB Usb;

View file

@ -1,21 +1,9 @@
/* Arduino terminal for PL2303 USB to serial converter and DealeXtreme GPRS modem. */
/* USB support */
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
/* CDC support */
#include <cdcacm.h>
#include <cdcprolific.h>
/* Debug support */
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
class PLAsyncOper : public CDCAsyncOper
{

View file

@ -1,22 +1,10 @@
/* USB Host to PL2303-based USB GPS unit interface */
/* Navibee GM720 receiver - Sirf Star III */
/* USB support */
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
/* CDC support */
#include <cdcacm.h>
#include <cdcprolific.h>
/* Debug support */
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
class PLAsyncOper : public CDCAsyncOper
{

View file

@ -4,25 +4,12 @@
/* test_with_gps_device library example modified for PL2302 access */
/* USB support */
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
/* CDC support */
#include <cdcacm.h>
#include <cdcprolific.h>
/* Debug support */
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <TinyGPS.h>
/* This sample code demonstrates the normal use of a TinyGPS object.

View file

@ -1,22 +1,10 @@
/* Arduino terminal for PL2303 USB to serial converter and XBee radio. */
/* Inserts linefeed after carriage return in data sent to and received from Xbee */
/* USB support */
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
/* CDC support */
#include <cdcacm.h>
#include <cdcprolific.h>
/* Debug support */
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
class PLAsyncOper : public CDCAsyncOper
{

@ -0,0 +1 @@
Subproject commit 658535d0706aabf2d5a08db065b2b6c6a7a65f38

View file

@ -0,0 +1,54 @@
#
# These are set for a mega 1280 + quadram plus my serial patch.
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
#
# If your board is a mega 2560 uncomment the following two lines
# BOARD = mega2560
# PROGRAMMER = wiring
# ...and then comment out the following two lines
BOARD = mega
PROGRAMMER = arduino
# set your Arduino tty port here
PORT = /dev/ttyUSB0
EXTRA_FLAGS = -D _USE_LFN=3
# change to 0 if you have quadram to take advantage of caching FAT
EXTRA_FLAGS += -D _FS_TINY=1
EXTRA_FLAGS += -D _MAX_SS=512
# Don't worry if you don't have external RAM, xmem2 detects this situation.
# You *WILL* be wanting to get some kind of external ram on your mega in order to
# do anything that is intense.
EXTRA_FLAGS += -D EXT_RAM_STACK=1
EXTRA_FLAGS += -D EXT_RAM_HEAP=1
# These are no longer needed for the demo to work.
# In the event you need more ram, uncomment these 3 lines.
#EXTRA_FLAGS += -D DISABLE_SERIAL1
#EXTRA_FLAGS += -D DISABLE_SERIAL2
#EXTRA_FLAGS += -D DISABLE_SERIAL3
#
# Advanced debug on Serial3
#
# uncomment the next two to enable debug on Serial3
EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
#EXTRA_FLAGS += -D DEBUG_USB_HOST
# The following are the libraries used.
LIB_DIRS =
LIB_DIRS += ../libraries/xmem
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
LIB_DIRS += ../libraries/generic_storage
LIB_DIRS += ../libraries/RTClib
LIB_DIRS += $(ARD_HOME)/libraries/Wire
LIB_DIRS += $(ARD_HOME)/libraries/Wire/utility
# And finally, the part that brings everything together for you.
include ../Arduino_Makefile_master/_Makefile.master

View file

@ -0,0 +1,29 @@
This small sketch tests the USB host shield mass storage library.
__Note:__ This will not run a Arduino Uno due to the limited ram available in the ATmega328p.
The Arduino Mega (ATmega1280) and the Arduino Mega 2560 (ATmega2560) are confirmed to work with this test code.
To compile this example you will need the following libraries as well:
* [xmem2](https://github.com/xxxajk/xmem2)
* [generic_storage FATfs](https://github.com/xxxajk/generic_storage)
* [RTClib](https://github.com/xxxajk/RTClib)
The following shield is recommended for larger projects: <http://ruggedcircuits.com/html/quadram.html>.
You may use the bundled [Makefile](Makefile) to compile the code instead of the Arduino IDE if you have problems or want a smaller binary. The master makefile is bundled as a submodule, but can also be downloaded manually at the following link: <https://github.com/xxxajk/Arduino_Makefile_master>.
To download the USB Host library and all the needed libraries for this test.
Run the following command in a terminal application:
```
git clone --recursive https://github.com/felis/USB_Host_Shield_2.0
```
If you want to update all the submodules run:
```
git submodule foreach --recursive git pull origin master
```

@ -0,0 +1 @@
Subproject commit 3e700203de5e1bdc21e9aa0b329363d588e4bd5d

View file

@ -0,0 +1,6 @@
file build/testusbhostFAT.elf
target remote localhost:4242
set {int}0x802200 = 0xffff
set {int}0x802220 = 0x0000
#graph display `x /3xh 0x802200`

@ -0,0 +1 @@
Subproject commit f09c4417ac1cce29edaf7259efaeccf2325764ba

View file

@ -0,0 +1,615 @@
/*
* Mega + USB storage + optional DS1307 + optional expansion RAM + funky status LED,
* Includes interactive debug level setting, and supports hot-plug.
*
* IMPORTANT! PLEASE USE Arduino 1.0.5 or better!
* Older versions HAVE MAJOR BUGS AND WILL NOT WORK AT ALL!
* Use of gcc-avr and lib-c that is newer than the Arduino version is even better.
* If you experience random crashes, use make.
* The options that the IDE use can generate bad code and cause the AVR to crash.
*
* This sketch requires the following libraries:
* https://github.com/felis/USB_Host_Shield_2.0 Install as 'USB_Host_Shield_2_0'
* https://github.com/xxxajk/xmem2 Install as 'xmem', provides memory services.
* https://github.com/xxxajk/generic_storage provides access to FAT file system.
* https://github.com/xxxajk/RTClib provides access to DS1307, or fake clock.
*
* Optional, to use the Makefile (Recommended! See above!):
* https://github.com/xxxajk/Arduino_Makefile_master
*
*/
// You can set this to 0 if you are not using a USB hub.
// It will save a little bit of flash and RAM.
// Set to 1 if you want to use a hub.
#define WANT_HUB_TEST 0
/////////////////////////////////////////////////////////////
// Please Note: This section is for Arduino IDE ONLY. //
// Use of Make creates a flash image that is 3.3KB smaller //
/////////////////////////////////////////////////////////////
#ifndef USING_MAKEFILE
// Uncomment to enable debugging
//#define DEBUG_USB_HOST
// This is where stderr/USB debugging goes to
#define USB_HOST_SERIAL Serial3
// If you have external memory, setting this to 0 enables FAT table caches.
// The 0 setting is recommended only if you have external memory.
#define _FS_TINY 1
// These you can safely leave alone.
#define _USE_LFN 3
#define EXT_RAM_STACK 1
#define EXT_RAM_HEAP 1
#define _MAX_SS 512
#endif
/////////////////////////////////////////////////////////////
// End of Arduino IDE specific hacks //
/////////////////////////////////////////////////////////////
#include <xmem.h>
#if WANT_HUB_TEST
#include <usbhub.h>
#endif
#include <masstorage.h>
#include <Storage.h>
#include <PCpartition/PCPartition.h>
#include <avr/interrupt.h>
#include <FAT/FAT.h>
#include <Wire.h>
#include <RTClib.h>
static FILE tty_stdio;
static FILE tty_stderr;
USB Usb;
#define LED 13 // the pin that the LED is attached to
volatile int brightness = 0; // how bright the LED is
volatile int fadeAmount = 80; // how many points to fade the LED by
volatile uint8_t current_state = 1;
volatile uint32_t LEDnext_time; // fade timeout
volatile uint8_t last_state = 0;
volatile boolean fatready = false;
volatile boolean partsready = false;
volatile boolean notified = false;
volatile uint32_t HEAPnext_time; // when to print out next heap report
volatile boolean runtest = false;
volatile boolean usbon = false;
volatile uint32_t usbon_time;
volatile boolean change = false;
volatile boolean reportlvl = false;
int cpart = 0;
PCPartition *PT;
#if WANT_HUB_TEST
#define MAX_HUBS 1
USBHub *Hubs[MAX_HUBS];
#endif
static PFAT *Fats[_VOLUMES];
static part_t parts[_VOLUMES];
static storage_t sto[_VOLUMES];
/*make sure this is a power of two. */
#define mbxs 128
static uint8_t My_Buff_x[mbxs]; /* File read buffer */
#define prescale1 ((1 << WGM12) | (1 << CS10))
#define prescale8 ((1 << WGM12) | (1 << CS11))
#define prescale64 ((1 << WGM12) | (1 << CS10) | (1 << CS11))
#define prescale256 ((1 << WGM12) | (1 << CS12))
#define prescale1024 ((1 << WGM12) | (1 << CS12) | (1 << CS10))
extern "C" unsigned int freeHeap();
static int tty_stderr_putc(char c, FILE *t) {
USB_HOST_SERIAL.write(c);
return 0;
}
static int tty_std_putc(char c, FILE *t) {
Serial.write(c);
return 0;
}
static int tty_std_getc(FILE *t) {
while (!Serial.available());
return Serial.read();
}
void setup() {
boolean serr = false;
for (int i = 0; i < _VOLUMES; i++) {
Fats[i] = NULL;
sto[i].private_data = new pvt_t;
((pvt_t *)sto[i].private_data)->B = 255; // impossible
}
// Set this to higher values to enable more debug information
// minimum 0x00, maximum 0xff
UsbDEBUGlvl = 0x51;
// make LED pin as an output:
pinMode(LED, OUTPUT);
pinMode(2, OUTPUT);
// Ensure TX is off
_SFR_BYTE(UCSR0B) &= ~_BV(TXEN0);
// Initialize 'debug' serial port
USB_HOST_SERIAL.begin(115200);
// Do not start primary Serial port if already started.
if (bit_is_clear(UCSR0B, TXEN0)) {
Serial.begin(115200);
serr = true;
}
// Set up stdio/stderr
tty_stdio.put = tty_std_putc;
tty_stdio.get = tty_std_getc;
tty_stdio.flags = _FDEV_SETUP_RW;
tty_stdio.udata = 0;
stdout = &tty_stdio;
stdin = &tty_stdio;
tty_stderr.put = tty_stderr_putc;
tty_stderr.get = NULL;
tty_stderr.flags = _FDEV_SETUP_WRITE;
tty_stderr.udata = 0;
stderr = &tty_stderr;
// Blink LED
delay(500);
analogWrite(LED, 255);
delay(500);
analogWrite(LED, 0);
delay(500);
printf_P(PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
printf_P(PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
printf_P(PSTR("'+' and '-' increase/decrease by 0x01\r\n"));
printf_P(PSTR("'.' and ',' increase/decrease by 0x10\r\n"));
printf_P(PSTR("'t' will run a 10MB write/read test and print out the time it took.\r\n"));
printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n\r\n"));
printf_P(PSTR("Long filename support: "
#if _USE_LFN
"Enabled"
#else
"Disabled"
#endif
"\r\n"));
if (serr) {
fprintf_P(stderr, PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
fprintf_P(stderr, PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
fprintf_P(stderr, PSTR("Long filename support: "
#if _USE_LFN
"Enabled"
#else
"Disabled"
#endif
"\r\n"));
}
analogWrite(LED, 255);
delay(500);
analogWrite(LED, 0);
delay(500);
analogWrite(LED, 255);
delay(500);
analogWrite(LED, 0);
delay(500);
analogWrite(LED, 255);
delay(500);
analogWrite(LED, 0);
delay(500);
LEDnext_time = millis() + 1;
#ifdef EXT_RAM
printf_P(PSTR("Total EXT RAM banks %i\r\n"), xmem::getTotalBanks());
#endif
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
printf_P(PSTR("SP %x\r\n"), (uint8_t *)(SP));
// Even though I'm not going to actually be deleting,
// I want to be able to have slightly more control.
// Besides, it is easier to initialize stuff...
#if WANT_HUB_TEST
for (int i = 0; i < MAX_HUBS; i++) {
Hubs[i] = new USBHub(&Usb);
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
}
#endif
// Initialize generic storage. This must be done before USB starts.
InitStorage();
while (Usb.Init(1000) == -1) {
printf_P(PSTR("No USB HOST Shield?\r\n"));
Notify(PSTR("OSC did not start."), 0x40);
}
// usb VBUS _OFF_
//Usb.gpioWr(0x00);
//digitalWrite(2, 0);
//usbon_time = millis() + 2000;
cli();
TCCR3A = 0;
TCCR3B = 0;
// (0.01/(1/((16 *(10^6)) / 8))) - 1 = 19999
OCR3A = 19999;
TCCR3B |= prescale8;
TIMSK3 |= (1 << OCIE1A);
sei();
HEAPnext_time = millis() + 10000;
}
void serialEvent() {
// Adjust UsbDEBUGlvl level on-the-fly.
// + to increase, - to decrease, * to display current level.
// . to increase by 16, , to decrease by 16
// e to flick VBUS
// * to report debug level
if (Serial.available()) {
int inByte = Serial.read();
switch (inByte) {
case '+':
if (UsbDEBUGlvl < 0xff) UsbDEBUGlvl++;
reportlvl = true;
break;
case '-':
if (UsbDEBUGlvl > 0x00) UsbDEBUGlvl--;
reportlvl = true;
break;
case '.':
if (UsbDEBUGlvl < 0xf0) UsbDEBUGlvl += 16;
reportlvl = true;
break;
case ',':
if (UsbDEBUGlvl > 0x0f) UsbDEBUGlvl -= 16;
reportlvl = true;
break;
case '*':
reportlvl = true;
break;
case 't':
runtest = true;
break;
case 'e':
change = true;
usbon = false;
break;
}
}
}
ISR(TIMER3_COMPA_vect) {
if (millis() >= LEDnext_time) {
LEDnext_time = millis() + 30;
// set the brightness of LED
analogWrite(LED, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0) {
brightness = 0;
fadeAmount = -fadeAmount;
}
if (brightness >= 255) {
brightness = 255;
fadeAmount = -fadeAmount;
}
}
}
bool isfat(uint8_t t) {
return (t == 0x01 || t == 0x04 || t == 0x06 || t == 0x0b || t == 0x0c || t == 0x0e || t == 0x1);
}
void die(FRESULT rc) {
printf_P(PSTR("Failed with rc=%u.\r\n"), rc);
//for (;;);
}
void loop() {
FIL My_File_Object_x; /* File object */
// Print a heap status report about every 10 seconds.
if (millis() >= HEAPnext_time) {
if (UsbDEBUGlvl > 0x50) {
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
}
HEAPnext_time = millis() + 10000;
}
// Horrid! This sort of thing really belongs in an ISR, not here!
// We also will be needing to test each hub port, we don't do this yet!
if (!change && !usbon && millis() >= usbon_time) {
change = true;
usbon = true;
}
if (change) {
change = false;
if (usbon) {
Usb.vbusPower(vbus_on);
printf_P(PSTR("VBUS on\r\n"));
} else {
Usb.vbusPower(vbus_off);
usbon_time = millis() + 2000;
}
}
Usb.Task();
current_state = Usb.getUsbTaskState();
if (current_state != last_state) {
if (UsbDEBUGlvl > 0x50)
printf_P(PSTR("USB state = %x\r\n"), current_state);
if (current_state == USB_STATE_RUNNING) {
fadeAmount = 30;
}
if (current_state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
fadeAmount = 80;
partsready = false;
for (int i = 0; i < cpart; i++) {
if (Fats[i] != NULL)
delete Fats[i];
Fats[i] = NULL;
}
fatready = false;
notified = false;
cpart = 0;
}
last_state = current_state;
}
// only do any of this if usb is on
if (usbon) {
if (partsready && !fatready) {
if (cpart > 0) fatready = true;
}
// This is horrible, and needs to be moved elsewhere!
for (int B = 0; B < MAX_USB_MS_DRIVERS; B++) {
if (!partsready && Bulk[B]->GetAddress() != NULL) {
// Build a list.
int ML = Bulk[B]->GetbMaxLUN();
//printf("MAXLUN = %i\r\n", ML);
ML++;
for (int i = 0; i < ML; i++) {
if (Bulk[B]->LUNIsGood(i)) {
partsready = true;
((pvt_t *)sto[i].private_data)->lun = i;
((pvt_t *)sto[i].private_data)->B = B;
sto[i].Read = *PRead;
sto[i].Write = *PWrite;
sto[i].Reads = *PReads;
sto[i].Writes = *PWrites;
sto[i].Status = *PStatus;
sto[i].TotalSectors = Bulk[B]->GetCapacity(i);
sto[i].SectorSize = Bulk[B]->GetSectorSize(i);
printf_P(PSTR("LUN:\t\t%u\r\n"), i);
printf_P(PSTR("Total Sectors:\t%08lx\t%lu\r\n"), sto[i].TotalSectors, sto[i].TotalSectors);
printf_P(PSTR("Sector Size:\t%04x\t\t%u\r\n"), sto[i].SectorSize, sto[i].SectorSize);
// get the partition data...
PT = new PCPartition;
if (!PT->Init(&sto[i])) {
part_t *apart;
for (int j = 0; j < 4; j++) {
apart = PT->GetPart(j);
if (apart != NULL && apart->type != 0x00) {
memcpy(&(parts[cpart]), apart, sizeof (part_t));
printf_P(PSTR("Partition %u type %#02x\r\n"), j, parts[cpart].type);
// for now
if (isfat(parts[cpart].type)) {
Fats[cpart] = new PFAT(&sto[i], cpart, parts[cpart].firstSector);
//int r = Fats[cpart]->Good();
if (Fats[cpart]->Good()) {
delete Fats[cpart];
Fats[cpart] = NULL;
} else cpart++;
}
}
}
} else {
// try superblock
Fats[cpart] = new PFAT(&sto[i], cpart, 0);
//int r = Fats[cpart]->Good();
if (Fats[cpart]->Good()) {
//printf_P(PSTR("Superblock error %x\r\n"), r);
delete Fats[cpart];
Fats[cpart] = NULL;
} else cpart++;
}
delete PT;
} else {
sto[i].Read = NULL;
sto[i].Write = NULL;
sto[i].Writes = NULL;
sto[i].Reads = NULL;
sto[i].TotalSectors = 0UL;
sto[i].SectorSize = 0;
}
}
}
}
if (fatready) {
if (Fats[0] != NULL) {
struct Pvt * p;
p = ((struct Pvt *)(Fats[0]->storage->private_data));
if (!Bulk[p->B]->LUNIsGood(p->lun)) {
// media change
fadeAmount = 80;
partsready = false;
for (int i = 0; i < cpart; i++) {
if (Fats[i] != NULL)
delete Fats[i];
Fats[cpart] = NULL;
}
fatready = false;
notified = false;
cpart = 0;
}
}
}
if (fatready) {
FRESULT rc; /* Result code */
UINT bw, br, i;
if (!notified) {
fadeAmount = 5;
notified = true;
printf_P(PSTR("\r\nOpen an existing file (message.txt).\r\n"));
rc = f_open(&My_File_Object_x, "0:/MESSAGE.TXT", FA_READ);
if (rc) printf_P(PSTR("Error %i, message.txt not found.\r\n"));
else {
printf_P(PSTR("\r\nType the file content.\r\n"));
for (;;) {
rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &br); /* Read a chunk of file */
if (rc || !br) break; /* Error or end of file */
for (i = 0; i < br; i++) {
/* Type the data */
if (My_Buff_x[i] == '\n')
Serial.write('\r');
if (My_Buff_x[i] != '\r')
Serial.write(My_Buff_x[i]);
Serial.flush();
}
}
if (rc) {
f_close(&My_File_Object_x);
goto out;
}
printf_P(PSTR("\r\nClose the file.\r\n"));
rc = f_close(&My_File_Object_x);
if (rc) goto out;
}
printf_P(PSTR("\r\nCreate a new file (hello.txt).\r\n"));
rc = f_open(&My_File_Object_x, "0:/Hello.TxT", FA_WRITE | FA_CREATE_ALWAYS);
if (rc) {
die(rc);
goto outdir;
}
printf_P(PSTR("\r\nWrite a text data. (Hello world!)\r\n"));
rc = f_write(&My_File_Object_x, "Hello world!\r\n", 14, &bw);
if (rc) {
goto out;
}
printf_P(PSTR("%u bytes written.\r\n"), bw);
printf_P(PSTR("\r\nClose the file.\r\n"));
rc = f_close(&My_File_Object_x);
if (rc) {
die(rc);
goto out;
}
outdir:
{
#if _USE_LFN
char lfn[_MAX_LFN + 1];
FILINFO My_File_Info_Object_x; /* File information object */
My_File_Info_Object_x.lfname = lfn;
#endif
DIR My_Dir_Object_x; /* Directory object */
printf_P(PSTR("\r\nOpen root directory.\r\n"));
rc = f_opendir(&My_Dir_Object_x, "0:/");
if (rc) {
die(rc);
goto out;
}
printf_P(PSTR("\r\nDirectory listing...\r\n"));
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
for (;;) {
#if _USE_LFN
My_File_Info_Object_x.lfsize = _MAX_LFN;
#endif
rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */
if (rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */
if (My_File_Info_Object_x.fattrib & AM_DIR) {
Serial.write('d');
} else {
Serial.write('-');
}
Serial.write('r');
if (My_File_Info_Object_x.fattrib & AM_RDO) {
Serial.write('-');
} else {
Serial.write('w');
}
if (My_File_Info_Object_x.fattrib & AM_HID) {
Serial.write('h');
} else {
Serial.write('-');
}
if (My_File_Info_Object_x.fattrib & AM_SYS) {
Serial.write('s');
} else {
Serial.write('-');
}
if (My_File_Info_Object_x.fattrib & AM_ARC) {
Serial.write('a');
} else {
Serial.write('-');
}
#if _USE_LFN
if (*My_File_Info_Object_x.lfname)
printf_P(PSTR(" %8lu %s (%s)\r\n"), My_File_Info_Object_x.fsize, My_File_Info_Object_x.fname, My_File_Info_Object_x.lfname);
else
#endif
printf_P(PSTR(" %8lu %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0]));
}
}
out:
if (rc) die(rc);
printf_P(PSTR("\r\nTest completed.\r\n"));
}
if (runtest) {
ULONG ii, wt, rt, start, end;
runtest = false;
f_unlink("0:/10MB.bin");
printf_P(PSTR("\r\nCreate a new 10MB test file (10MB.bin).\r\n"));
rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_WRITE | FA_CREATE_ALWAYS);
if (rc) goto failed;
for (bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff;
start = millis();
for (ii = 10485760LU / mbxs; ii > 0LU; ii--) {
rc = f_write(&My_File_Object_x, My_Buff_x, mbxs, &bw);
if (rc || !bw) goto failed;
}
rc = f_close(&My_File_Object_x);
if (rc) goto failed;
end = millis();
wt = end - start;
printf_P(PSTR("Time to write 10485760 bytes: %lu ms (%lu sec) \r\n"), wt, (500 + wt) / 1000UL);
rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_READ);
start = millis();
if (rc) goto failed;
for (;;) {
rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &bw); /* Read a chunk of file */
if (rc || !bw) break; /* Error or end of file */
}
end = millis();
if (rc) goto failed;
rc = f_close(&My_File_Object_x);
if (rc) goto failed;
rt = end - start;
printf_P(PSTR("Time to read 10485760 bytes: %lu ms (%lu sec)\r\nDelete test file\r\n"), rt, (500 + rt) / 1000UL);
failed:
if (rc) die(rc);
printf_P(PSTR("10MB timing test finished.\r\n"));
}
}
}
}

@ -0,0 +1 @@
Subproject commit 24f521e27cea025b38bc9e2615018e96478de1be

View file

@ -14,11 +14,12 @@ Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HEXDUMP_H__)
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
#error "Never include hexdump.h directly; include Usb.h instead"
#else
#define __HEXDUMP_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
extern int UsbDEBUGlvl;
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS {
@ -40,23 +41,21 @@ public:
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
#ifdef DEBUG
if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if(!byteCount) {
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
Notify(PSTR(": "), 0x80);
E_Notify(PSTR(": "), 0x80);
}
PrintHex<uint8_t > (pbuf[j], 0x80);
Notify(PSTR(" "), 0x80);
E_Notify(PSTR(" "), 0x80);
if(byteCount == 15) {
Notify(PSTR("\r\n"), 0x80);
E_Notify(PSTR("\r\n"), 0x80);
byteCount = 0xFF;
}
}
}
#endif
}
#endif // __HEXDUMP_H__

26
hid.cpp
View file

@ -44,39 +44,39 @@ uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
D_PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
D_PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
D_PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
D_PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
D_PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
D_PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
D_PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
}

18
hid.h
View file

@ -17,25 +17,7 @@ e-mail : support@circuitsathome.com
#if !defined(__HID_H__)
#define __HID_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "hidusagestr.h"
#define DATA_SIZE_MASK 0x03

170
hidboot.h
View file

@ -17,27 +17,8 @@ e-mail : support@circuitsathome.com
#if !defined(__HIDBOOT_H__)
#define __HIDBOOT_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "hid.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#define KEY_SPACE 0x2c
#define KEY_ZERO 0x27
#define KEY_ZERO2 0x62
@ -126,9 +107,9 @@ struct KBDLEDS {
uint8_t bmReserved : 3;
};
#define KEY_NUM_LOCK 0x53
#define KEY_CAPS_LOCK 0x39
#define KEY_SCROLL_LOCK 0x47
#define KEY_NUM_LOCK 0x53
#define KEY_CAPS_LOCK 0x39
#define KEY_SCROLL_LOCK 0x47
class KeyboardReportParser : public HIDReportParser {
static const uint8_t numKeys[];
@ -161,26 +142,25 @@ public:
protected:
virtual uint8_t HandleLockingKeys(HID* hid, uint8_t key);
virtual void OnControlKeysChanged(uint8_t before, uint8_t after) {
};
virtual void OnControlKeysChanged(uint8_t before, uint8_t after) {
};
virtual void OnKeyDown(uint8_t mod, uint8_t key) {
virtual void OnKeyDown(uint8_t mod, uint8_t key) {
};
virtual void OnKeyUp(uint8_t mod, uint8_t key) {
};
};
#define totalEndpoints 2
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
#define totalEndpoints (((BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD)? 2 : 0)+((BOOT_PROTOCOL & HID_PROTOCOL_MOUSE)? 1 : 0))
#define epMUL (((BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD)? 1 : 0)+((BOOT_PROTOCOL & HID_PROTOCOL_MOUSE)? 1 : 0))
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
template <const uint8_t BOOT_PROTOCOL>
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
{
EpInfo epInfo[totalEndpoints];
HIDReportParser *pRptParser;
HIDReportParser *pRptParser[epMUL];
uint8_t bConfNum; // configuration number
uint8_t bIfaceNum; // Interface Number
@ -192,14 +172,14 @@ class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
void Initialize();
virtual HIDReportParser* GetReportParser(uint8_t id) {
return pRptParser;
return pRptParser[id];
};
public:
HIDBoot(USB *p);
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {
pRptParser = prs;
pRptParser[id] = prs;
return true;
};
@ -220,10 +200,12 @@ template <const uint8_t BOOT_PROTOCOL>
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
HID(p),
qNextPollTime(0),
bPollEnable(false),
pRptParser(NULL) {
bPollEnable(false) {
Initialize();
for(uint8_t i = 0; i < epMUL; i++) {
pRptParser[i] = NULL;
}
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
@ -250,10 +232,10 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint16_t cd_len = 0;
//uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
@ -344,29 +326,48 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
//USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<
USB_CLASS_HID,
HID_BOOT_INTF_SUBCLASS,
BOOT_PROTOCOL,
CP_MASK_COMPARE_ALL> confDescrParser(this);
// GCC will optimize unused stuff away.
if(BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD) {
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<
USB_CLASS_HID,
HID_BOOT_INTF_SUBCLASS,
HID_PROTOCOL_KEYBOARD,
CP_MASK_COMPARE_ALL> confDescrParserA(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(bNumEP == totalEndpoints)
break;
pUsb->getConfDescr(bAddress, 0, i, &confDescrParserA);
}
}
if(bNumEP > 1)
break;
} // for
// GCC will optimize unused stuff away.
if(BOOT_PROTOCOL & HID_PROTOCOL_MOUSE) {
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<
USB_CLASS_HID,
HID_BOOT_INTF_SUBCLASS,
HID_PROTOCOL_MOUSE,
CP_MASK_COMPARE_ALL> confDescrParserB(this);
if(bNumEP == totalEndpoints)
break;
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
pUsb->getConfDescr(bAddress, 0, i, &confDescrParserB);
}
}
//USBTRACE2("\r\nbAddr:", bAddress);
//USBTRACE2("\r\nbNumEP:", bNumEP);
USBTRACE2("\r\nbAddr:", bAddress);
USBTRACE2("\r\nbNumEP:", bNumEP);
USBTRACE2("\r\ntotalEndpoints:", totalEndpoints);
if(bNumEP != totalEndpoints) {
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
goto Fail;
}
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
//USBTRACE2("\r\nCnf:", bConfNum);
USBTRACE2("\r\nCnf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
@ -374,15 +375,16 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
if(rcode)
goto FailSetConfDescr;
//USBTRACE2("\r\nIf:", bIfaceNum);
USBTRACE2("\r\nIf:", bIfaceNum);
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
if(rcode)
goto FailSetProtocol;
if(BOOT_PROTOCOL == 1) {
rcode = SetIdle(bIfaceNum, 0, 0);
// GCC will optimize unused stuff away.
if(BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD) {
rcode = SetIdle(0/* bIfaceNum*/, 0, 0);
if(rcode)
goto FailSetIdle;
@ -393,57 +395,67 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailSetProtocol:
#ifdef DEBUG_USB_HOST
USBTRACE("SetProto:");
goto Fail;
#endif
FailSetIdle:
#ifdef DEBUG_USB_HOST
USBTRACE("SetIdle:");
goto Fail;
#endif
Fail:
#ifdef DEBUG_USB_HOST
NotifyFail(rcode);
#endif
Release();
return rcode;
}
template <const uint8_t BOOT_PROTOCOL>
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
// If the first configuration satisfies, the others are not concidered.
// If the first configuration satisfies, the others are not considered.
if(bNumEP > 1 && conf != bConfNum)
return;
bConfNum = conf;
bIfaceNum = iface;
uint8_t index;
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
index = epInterruptInIndex;
uint8_t index = bNumEP;//epInterruptInIndex; //+ bNumEP;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
epInfo[index].bmNakPower = USB_NAK_NOWAIT;
bNumEP++;
}
}
@ -470,28 +482,32 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
if(qNextPollTime <= millis()) {
qNextPollTime = millis() + 10;
const uint8_t const_buff_len = 16;
uint8_t buf[const_buff_len];
// To-do: optimize manually, getting rid of the loop
for(uint8_t i = 0; i < epMUL; i++) {
const uint8_t const_buff_len = 16;
uint8_t buf[const_buff_len];
uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
uint16_t read = (uint16_t) epInfo[epInterruptInIndex + i].maxPktSize;
if(rcode) {
if(rcode != hrNAK)
USBTRACE2("Poll:", rcode);
return rcode;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex + i].epAddr, &read, buf);
if(!rcode) {
if(pRptParser[i])
pRptParser[i]->Parse((HID*)this, 0, (uint8_t) read, buf);
//for (uint8_t i=0; i<read; i++)
// PrintHex<uint8_t>(buf[i]);
//if (read)
// USB_HOST_SERIAL.println("");
} else {
if(rcode != hrNAK) {
USBTRACE2("Poll:", rcode);
break;
}
}
}
//for (uint8_t i=0; i<read; i++)
// PrintHex<uint8_t>(buf[i]);
//if (read)
// Serial.println("");
if(pRptParser)
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
}
return rcode;
}
#endif // __HIDBOOTMOUSE_H__

View file

@ -981,9 +981,9 @@ void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const
totalSize = 0;
while (cntdn) {
//Serial.println("");
//USB_HOST_SERIAL.println("");
//PrintHex<uint16_t>(offset + len - cntdn);
//Serial.print(":");
//USB_HOST_SERIAL.print(":");
ParseItem(&p, &cntdn);
@ -994,79 +994,79 @@ void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const
}
void ReportDescParserBase::PrintValue(uint8_t *p, uint8_t len) {
Notify(PSTR("("), 0x80);
E_Notify(PSTR("("), 0x80);
for (; len; p++, len--)
PrintHex<uint8_t > (*p, 0x80);
Notify(PSTR(")"), 0x80);
E_Notify(PSTR(")"), 0x80);
}
void ReportDescParserBase::PrintByteValue(uint8_t data) {
Notify(PSTR("("), 0x80);
E_Notify(PSTR("("), 0x80);
PrintHex<uint8_t > (data, 0x80);
Notify(PSTR(")"), 0x80);
E_Notify(PSTR(")"), 0x80);
}
void ReportDescParserBase::PrintItemTitle(uint8_t prefix) {
switch (prefix & (TYPE_MASK | TAG_MASK)) {
case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
Notify(PSTR("\r\nPush"), 0x80);
E_Notify(PSTR("\r\nPush"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_POP):
Notify(PSTR("\r\nPop"), 0x80);
E_Notify(PSTR("\r\nPop"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
Notify(PSTR("\r\nUsage Page"), 0x80);
E_Notify(PSTR("\r\nUsage Page"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
Notify(PSTR("\r\nLogical Min"), 0x80);
E_Notify(PSTR("\r\nLogical Min"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
Notify(PSTR("\r\nLogical Max"), 0x80);
E_Notify(PSTR("\r\nLogical Max"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
Notify(PSTR("\r\nPhysical Min"), 0x80);
E_Notify(PSTR("\r\nPhysical Min"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
Notify(PSTR("\r\nPhysical Max"), 0x80);
E_Notify(PSTR("\r\nPhysical Max"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
Notify(PSTR("\r\nUnit Exp"), 0x80);
E_Notify(PSTR("\r\nUnit Exp"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
Notify(PSTR("\r\nUnit"), 0x80);
E_Notify(PSTR("\r\nUnit"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
Notify(PSTR("\r\nReport Size"), 0x80);
E_Notify(PSTR("\r\nReport Size"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
Notify(PSTR("\r\nReport Count"), 0x80);
E_Notify(PSTR("\r\nReport Count"), 0x80);
break;
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
Notify(PSTR("\r\nReport Id"), 0x80);
E_Notify(PSTR("\r\nReport Id"), 0x80);
break;
case (TYPE_LOCAL | TAG_LOCAL_USAGE):
Notify(PSTR("\r\nUsage"), 0x80);
E_Notify(PSTR("\r\nUsage"), 0x80);
break;
case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
Notify(PSTR("\r\nUsage Min"), 0x80);
E_Notify(PSTR("\r\nUsage Min"), 0x80);
break;
case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
Notify(PSTR("\r\nUsage Max"), 0x80);
E_Notify(PSTR("\r\nUsage Max"), 0x80);
break;
case (TYPE_MAIN | TAG_MAIN_COLLECTION):
Notify(PSTR("\r\nCollection"), 0x80);
E_Notify(PSTR("\r\nCollection"), 0x80);
break;
case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
Notify(PSTR("\r\nEnd Collection"), 0x80);
E_Notify(PSTR("\r\nEnd Collection"), 0x80);
break;
case (TYPE_MAIN | TAG_MAIN_INPUT):
Notify(PSTR("\r\nInput"), 0x80);
E_Notify(PSTR("\r\nInput"), 0x80);
break;
case (TYPE_MAIN | TAG_MAIN_OUTPUT):
Notify(PSTR("\r\nOutput"), 0x80);
E_Notify(PSTR("\r\nOutput"), 0x80);
break;
case (TYPE_MAIN | TAG_MAIN_FEATURE):
Notify(PSTR("\r\nFeature"), 0x80);
E_Notify(PSTR("\r\nFeature"), 0x80);
break;
} // switch (**pp & (TYPE_MASK | TAG_MASK))
}
@ -1150,30 +1150,30 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
switch (data) {
case 0x00:
Notify(PSTR(" Physical"), 0x80);
E_Notify(PSTR(" Physical"), 0x80);
break;
case 0x01:
Notify(PSTR(" Application"), 0x80);
E_Notify(PSTR(" Application"), 0x80);
break;
case 0x02:
Notify(PSTR(" Logical"), 0x80);
E_Notify(PSTR(" Logical"), 0x80);
break;
case 0x03:
Notify(PSTR(" Report"), 0x80);
E_Notify(PSTR(" Report"), 0x80);
break;
case 0x04:
Notify(PSTR(" Named Array"), 0x80);
E_Notify(PSTR(" Named Array"), 0x80);
break;
case 0x05:
Notify(PSTR(" Usage Switch"), 0x80);
E_Notify(PSTR(" Usage Switch"), 0x80);
break;
case 0x06:
Notify(PSTR(" Usage Modifier"), 0x80);
E_Notify(PSTR(" Usage Modifier"), 0x80);
break;
default:
Notify(PSTR(" Vendor Defined("), 0x80);
E_Notify(PSTR(" Vendor Defined("), 0x80);
PrintHex<uint8_t > (data, 0x80);
Notify(PSTR(")"), 0x80);
E_Notify(PSTR(")"), 0x80);
}
break;
case (TYPE_MAIN | TAG_MAIN_INPUT):
@ -1182,9 +1182,9 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
totalSize += (uint16_t)rptSize * (uint16_t)rptCount;
rptSize = 0;
rptCount = 0;
Notify(PSTR("("), 0x80);
E_Notify(PSTR("("), 0x80);
PrintBin<uint8_t > (data, 0x80);
Notify(PSTR(")"), 0x80);
E_Notify(PSTR(")"), 0x80);
break;
} // switch (**pp & (TYPE_MASK | TAG_MASK))
}
@ -1216,15 +1216,15 @@ void ReportDescParserBase::SetUsagePage(uint16_t page) {
pfUsage = NULL;
if (page > 0x00 && page < 0x11)
pfUsage = /*(UsagePageFunc)pgm_read_word*/(usagePageFunctions[page - 1]);
pfUsage = /*(UsagePageFunc)pgm_read_pointer*/(usagePageFunctions[page - 1]);
//else if (page > 0x7f && page < 0x84)
// Notify(pstrUsagePageMonitor);
// E_Notify(pstrUsagePageMonitor);
//else if (page > 0x83 && page < 0x8c)
// Notify(pstrUsagePagePower);
// E_Notify(pstrUsagePagePower);
//else if (page > 0x8b && page < 0x92)
// Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
// E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
//else if (page > 0xfeff && page <= 0xffff)
// Notify(pstrUsagePageVendorDefined);
// E_Notify(pstrUsagePageVendorDefined);
else
switch (page) {
case 0x14:
@ -1237,232 +1237,232 @@ void ReportDescParserBase::SetUsagePage(uint16_t page) {
}
void ReportDescParserBase::PrintUsagePage(uint16_t page) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (page > 0x00 && page < 0x11)
Notify((char*)pgm_read_pointer(&usagePageTitles0[page - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&usagePageTitles0[page - 1]), 0x80);
else if (page > 0x7f && page < 0x84)
Notify(pstrUsagePageMonitor, 0x80);
E_Notify(pstrUsagePageMonitor, 0x80);
else if (page > 0x83 && page < 0x8c)
Notify(pstrUsagePagePower, 0x80);
E_Notify(pstrUsagePagePower, 0x80);
else if (page > 0x8b && page < 0x92)
Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]), 0x80);
E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]), 0x80);
else if (page > 0xfeff && page <= 0xffff)
Notify(pstrUsagePageVendorDefined, 0x80);
E_Notify(pstrUsagePageVendorDefined, 0x80);
else
switch (page) {
case 0x14:
Notify(pstrUsagePageAlphaNumericDisplay, 0x80);
E_Notify(pstrUsagePageAlphaNumericDisplay, 0x80);
break;
case 0x40:
Notify(pstrUsagePageMedicalInstruments, 0x80);
E_Notify(pstrUsagePageMedicalInstruments, 0x80);
break;
default:
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
}
void ReportDescParserBase::PrintButtonPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
Notify(PSTR("Btn"), 0x80);
E_Notify(pstrSpace, 0x80);
E_Notify(PSTR("Btn"), 0x80);
PrintHex<uint16_t > (usage, 0x80);
Notify(PSTR("\r\n"), 0x80);
//Serial.print(usage, HEX);
E_Notify(PSTR("\r\n"), 0x80);
//USB_HOST_SERIAL.print(usage, HEX);
}
void ReportDescParserBase::PrintOrdinalPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
Notify(PSTR("Inst"), 0x80);
E_Notify(pstrSpace, 0x80);
E_Notify(PSTR("Inst"), 0x80);
// Sorry, HEX for now...
PrintHex<uint16_t > (usage, 0x80);
Notify(PSTR("\r\n"), 0x80);
//Serial.print(usage, DEC);
E_Notify(PSTR("\r\n"), 0x80);
//USB_HOST_SERIAL.print(usage, DEC);
}
void ReportDescParserBase::PrintGenericDesktopPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x0a)
Notify((char*)pgm_read_pointer(&genDesktopTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDesktopTitles0[usage - 1]), 0x80);
else if (usage > 0x2f && usage < 0x49)
Notify((char*)pgm_read_pointer(&genDesktopTitles1[usage - 0x30]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDesktopTitles1[usage - 0x30]), 0x80);
else if (usage > 0x7f && usage < 0x94)
Notify((char*)pgm_read_pointer(&genDesktopTitles2[usage - 0x80]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDesktopTitles2[usage - 0x80]), 0x80);
else if (usage > 0x9f && usage < 0xa9)
Notify((char*)pgm_read_pointer(&genDesktopTitles3[usage - 0xa0]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDesktopTitles3[usage - 0xa0]), 0x80);
else if (usage > 0xaf && usage < 0xb8)
Notify((char*)pgm_read_pointer(&genDesktopTitles4[usage - 0xb0]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDesktopTitles4[usage - 0xb0]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintSimulationControlsPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x0d)
Notify((char*)pgm_read_pointer(&simuTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&simuTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x26)
Notify((char*)pgm_read_pointer(&simuTitles1[usage - 0x20]), 0x80);
E_Notify((char*)pgm_read_pointer(&simuTitles1[usage - 0x20]), 0x80);
else if (usage > 0xaf && usage < 0xd1)
Notify((char*)pgm_read_pointer(&simuTitles2[usage - 0xb0]), 0x80);
E_Notify((char*)pgm_read_pointer(&simuTitles2[usage - 0xb0]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintVRControlsPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x0b)
Notify((char*)pgm_read_pointer(&vrTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&vrTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x22)
Notify((char*)pgm_read_pointer(&vrTitles1[usage - 0x20]), 0x80);
E_Notify((char*)pgm_read_pointer(&vrTitles1[usage - 0x20]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintSportsControlsPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x05)
Notify((char*)pgm_read_pointer(&sportsCtrlTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles0[usage - 1]), 0x80);
else if (usage > 0x2f && usage < 0x3a)
Notify((char*)pgm_read_pointer(&sportsCtrlTitles1[usage - 0x30]), 0x80);
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles1[usage - 0x30]), 0x80);
else if (usage > 0x4f && usage < 0x64)
Notify((char*)pgm_read_pointer(&sportsCtrlTitles2[usage - 0x50]), 0x80);
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles2[usage - 0x50]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintGameControlsPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x04)
Notify((char*)pgm_read_pointer(&gameTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&gameTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x3a)
Notify((char*)pgm_read_pointer(&gameTitles1[usage - 0x20]), 0x80);
E_Notify((char*)pgm_read_pointer(&gameTitles1[usage - 0x20]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintGenericDeviceControlsPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x1f && usage < 0x27)
Notify((char*)pgm_read_pointer(&genDevCtrlTitles[usage - 0x20]), 0x80);
E_Notify((char*)pgm_read_pointer(&genDevCtrlTitles[usage - 0x20]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintLEDPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x4e)
Notify((char*)pgm_read_pointer(&ledTitles[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&ledTitles[usage - 1]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintTelephonyPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x08)
Notify((char*)pgm_read_pointer(&telTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x32)
Notify((char*)pgm_read_pointer(&telTitles1[usage - 0x1f]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles1[usage - 0x1f]), 0x80);
else if (usage > 0x4f && usage < 0x54)
Notify((char*)pgm_read_pointer(&telTitles2[usage - 0x4f]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles2[usage - 0x4f]), 0x80);
else if (usage > 0x6f && usage < 0x75)
Notify((char*)pgm_read_pointer(&telTitles3[usage - 0x6f]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles3[usage - 0x6f]), 0x80);
else if (usage > 0x8f && usage < 0x9f)
Notify((char*)pgm_read_pointer(&telTitles4[usage - 0x8f]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles4[usage - 0x8f]), 0x80);
else if (usage > 0xaf && usage < 0xc0)
Notify((char*)pgm_read_pointer(&telTitles5[usage - 0xaf]), 0x80);
E_Notify((char*)pgm_read_pointer(&telTitles5[usage - 0xaf]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintConsumerPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x07)
Notify((char*)pgm_read_pointer(&consTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x23)
Notify((char*)pgm_read_pointer(&consTitles1[usage - 0x1f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles1[usage - 0x1f]), 0x80);
else if (usage > 0x2f && usage < 0x37)
Notify((char*)pgm_read_pointer(&consTitles2[usage - 0x2f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles2[usage - 0x2f]), 0x80);
else if (usage > 0x3f && usage < 0x49)
Notify((char*)pgm_read_pointer(&consTitles3[usage - 0x3f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles3[usage - 0x3f]), 0x80);
else if (usage > 0x5f && usage < 0x67)
Notify((char*)pgm_read_pointer(&consTitles4[usage - 0x5f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles4[usage - 0x5f]), 0x80);
else if (usage > 0x7f && usage < 0xa5)
Notify((char*)pgm_read_pointer(&consTitles5[usage - 0x7f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles5[usage - 0x7f]), 0x80);
else if (usage > 0xaf && usage < 0xcf)
Notify((char*)pgm_read_pointer(&consTitles6[usage - 0xaf]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles6[usage - 0xaf]), 0x80);
else if (usage > 0xdf && usage < 0xeb)
Notify((char*)pgm_read_pointer(&consTitles7[usage - 0xdf]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles7[usage - 0xdf]), 0x80);
else if (usage > 0xef && usage < 0xf6)
Notify((char*)pgm_read_pointer(&consTitles8[usage - 0xef]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles8[usage - 0xef]), 0x80);
else if (usage > 0xff && usage < 0x10e)
Notify((char*)pgm_read_pointer(&consTitles9[usage - 0xff]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitles9[usage - 0xff]), 0x80);
else if (usage > 0x14f && usage < 0x156)
Notify((char*)pgm_read_pointer(&consTitlesA[usage - 0x14f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitlesA[usage - 0x14f]), 0x80);
else if (usage > 0x15f && usage < 0x16b)
Notify((char*)pgm_read_pointer(&consTitlesB[usage - 0x15f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitlesB[usage - 0x15f]), 0x80);
else if (usage > 0x16f && usage < 0x175)
Notify((char*)pgm_read_pointer(&consTitlesC[usage - 0x16f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitlesC[usage - 0x16f]), 0x80);
else if (usage > 0x17f && usage < 0x1c8)
Notify((char*)pgm_read_pointer(&consTitlesD[usage - 0x17f]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitlesD[usage - 0x17f]), 0x80);
else if (usage > 0x1ff && usage < 0x29d)
Notify((char*)pgm_read_pointer(&consTitlesE[usage - 0x1ff]), 0x80);
E_Notify((char*)pgm_read_pointer(&consTitlesE[usage - 0x1ff]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintDigitizerPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x0e)
Notify((char*)pgm_read_pointer(&digitTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&digitTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x23)
Notify((char*)pgm_read_pointer(&digitTitles1[usage - 0x1f]), 0x80);
E_Notify((char*)pgm_read_pointer(&digitTitles1[usage - 0x1f]), 0x80);
else if (usage > 0x2f && usage < 0x47)
Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x2f]), 0x80);
E_Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x2f]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintAlphanumDisplayPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage > 0x00 && usage < 0x03)
Notify((char*)pgm_read_pointer(&aplphanumTitles0[usage - 1]), 0x80);
E_Notify((char*)pgm_read_pointer(&aplphanumTitles0[usage - 1]), 0x80);
else if (usage > 0x1f && usage < 0x4e)
Notify((char*)pgm_read_pointer(&aplphanumTitles1[usage - 0x1f]), 0x80);
E_Notify((char*)pgm_read_pointer(&aplphanumTitles1[usage - 0x1f]), 0x80);
else if (usage > 0x7f && usage < 0x96)
Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x80]), 0x80);
E_Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x80]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
void ReportDescParserBase::PrintMedicalInstrumentPageUsage(uint16_t usage) {
Notify(pstrSpace, 0x80);
E_Notify(pstrSpace, 0x80);
if (usage == 1)
Notify(pstrUsageMedicalUltrasound, 0x80);
E_Notify(pstrUsageMedicalUltrasound, 0x80);
else if (usage > 0x1f && usage < 0x28)
Notify((char*)pgm_read_pointer(&medInstrTitles0[usage - 0x1f]), 0x80);
E_Notify((char*)pgm_read_pointer(&medInstrTitles0[usage - 0x1f]), 0x80);
else if (usage > 0x3f && usage < 0x45)
Notify((char*)pgm_read_pointer(&medInstrTitles1[usage - 0x40]), 0x80);
E_Notify((char*)pgm_read_pointer(&medInstrTitles1[usage - 0x40]), 0x80);
else if (usage > 0x5f && usage < 0x62)
Notify((char*)pgm_read_pointer(&medInstrTitles2[usage - 0x60]), 0x80);
E_Notify((char*)pgm_read_pointer(&medInstrTitles2[usage - 0x60]), 0x80);
else if (usage == 0x70)
Notify(pstrUsageDepthGainCompensation, 0x80);
E_Notify(pstrUsageDepthGainCompensation, 0x80);
else if (usage > 0x7f && usage < 0x8a)
Notify((char*)pgm_read_pointer(&medInstrTitles3[usage - 0x80]), 0x80);
E_Notify((char*)pgm_read_pointer(&medInstrTitles3[usage - 0x80]), 0x80);
else if (usage > 0x9f && usage < 0xa2)
Notify((char*)pgm_read_pointer(&medInstrTitles4[usage - 0xa0]), 0x80);
E_Notify((char*)pgm_read_pointer(&medInstrTitles4[usage - 0xa0]), 0x80);
else
Notify(pstrUsagePageUndefined, 0x80);
E_Notify(pstrUsagePageUndefined, 0x80);
}
uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
@ -1613,7 +1613,7 @@ void ReportDescParser2::OnInputItem(uint8_t itm) {
}
PrintByteValue(result.dwResult);
}
Notify(PSTR("\r\n"), 0x80);
E_Notify(PSTR("\r\n"), 0x80);
}
void UniversalReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {

View file

@ -17,24 +17,6 @@ e-mail : support@circuitsathome.com
#if !defined(__HIDDESCRIPTORPARSER_H__)
#define __HIDDESCRIPTORPARSER_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "hid.h"
class ReportDescParserBase : public USBReadParser {

View file

@ -147,6 +147,8 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
return rcode;
}
delay( 2 ); //per USB 2.0 sect.9.2.6.3
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
@ -221,27 +223,39 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailSetIdle:
#ifdef DEBUG_USB_HOST
USBTRACE("SetIdle:");
#endif
Fail:
#ifdef DEBUG_USB_HOST
NotifyFail(rcode);
#endif
Release();
return rcode;
}
@ -362,7 +376,7 @@ uint8_t HIDUniversal::Poll() {
Notify(PSTR("\r\nBuf: "), 0x80);
for (uint8_t i = 0; i < read; i++)
PrintHex<uint8_t > (buf[i], 0x80);
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR("\r\n"), 0x80);

View file

@ -7,6 +7,7 @@
####################################################
USB KEYWORD1
USBHub KEYWORD1
####################################################
# Syntax Coloring Map For BTD (Bluetooth) Library
@ -56,10 +57,13 @@ setLedToggle KEYWORD2
moveSetBulb KEYWORD2
moveSetRumble KEYWORD2
attachOnInit KEYWORD2
PS3Connected KEYWORD2
PS3MoveConnected KEYWORD2
PS3NavigationConnected KEYWORD2
isReady KEYWORD2
watingForConnection KEYWORD2
####################################################
@ -161,6 +165,7 @@ RumbleLow LITERAL1
####################################################
XBOXUSB KEYWORD1
XBOXOLD KEYWORD1
XBOXRECV KEYWORD1
####################################################
@ -192,6 +197,9 @@ BACK LITERAL1
XBOX LITERAL1
SYNC LITERAL1
BLACK LITERAL1
WHITE LITERAL1
A LITERAL1
B LITERAL1
X LITERAL1

65
macros.h Normal file
View file

@ -0,0 +1,65 @@
/*
* File: macros.h
* Author: AJK
*
* Created on September 23, 2013, 12:31 AM
*/
#if !defined(_usb_h_) || defined(MACROS_H)
#error "Never include macros.h directly; include Usb.h instead"
#else
#define MACROS_H
////////////////////////////////////////////////////////////////////////////////
// HANDY MACROS
////////////////////////////////////////////////////////////////////////////////
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#ifndef __BYTE_GRABBING_DEFINED__
#define __BYTE_GRABBING_DEFINED__ 1
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
// Note: Use this if your compiler generates horrible assembler!
#define BGRAB0(__usi__) (((uint8_t *)&(__usi__))[0])
#define BGRAB1(__usi__) (((uint8_t *)&(__usi__))[1])
#define BGRAB2(__usi__) (((uint8_t *)&(__usi__))[2])
#define BGRAB3(__usi__) (((uint8_t *)&(__usi__))[3])
#define BGRAB4(__usi__) (((uint8_t *)&(__usi__))[4])
#define BGRAB5(__usi__) (((uint8_t *)&(__usi__))[5])
#define BGRAB6(__usi__) (((uint8_t *)&(__usi__))[6])
#define BGRAB7(__usi__) (((uint8_t *)&(__usi__))[7])
#else
// Note: The cast alone to uint8_t is actually enough.
// GCC throws out the "& 0xff", and the size is no different.
// Some compilers need it.
#define BGRAB0(__usi__) ((uint8_t)((__usi__) & 0xff ))
#define BGRAB1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xff))
#define BGRAB2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xff))
#define BGRAB3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xff))
#define BGRAB4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xff))
#define BGRAB5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xff))
#define BGRAB6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xff))
#define BGRAB7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xff))
#endif
#define BOVER1(__usi__) ((uint16_t)(__usi__) << 8)
#define BOVER2(__usi__) ((uint32_t)(__usi__) << 16)
#define BOVER3(__usi__) ((uint32_t)(__usi__) << 24)
#define BOVER4(__usi__) ((uint64_t)(__usi__) << 32)
#define BOVER5(__usi__) ((uint64_t)(__usi__) << 40)
#define BOVER6(__usi__) ((uint64_t)(__usi__) << 48)
#define BOVER7(__usi__) ((uint64_t)(__usi__) << 56)
// These are the smallest and fastest ways I have found so far in pure C/C++.
#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__)))
#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__)))
#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__)))
#endif
/*
* Debug macros: Strings are stored in progmem (flash) instead of RAM.
*/
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
#endif /* MACROS_H */

File diff suppressed because it is too large Load diff

View file

@ -1,26 +1,13 @@
#if !defined(__MASSTORAGE_H__)
#define __MASSTORAGE_H__
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
// Cruft removal, makes driver smaller, faster.
#ifndef MS_WANT_PARSER
#define MS_WANT_PARSER 0
#endif
#define DEBUG
#include <inttypes.h>
#include "avrpins.h"
#include <avr/pgmspace.h>
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include <confdescparser.h>
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
@ -52,32 +39,98 @@
#define MASS_CBW_SIGNATURE 0x43425355
#define MASS_CSW_SIGNATURE 0x53425355
#define MASS_CMD_DIR_OUT (0 << 7)
#define MASS_CMD_DIR_IN (1 << 7)
#define MASS_CMD_DIR_OUT 0 // (0 << 7)
#define MASS_CMD_DIR_IN 0x80 //(1 << 7)
#define SCSI_CMD_INQUIRY 0x12
#define SCSI_CMD_REPORT_LUNS 0xA0
/*
* Reference documents from T10 (http://www.t10.org)
* SCSI Primary Commands - 3 (SPC-3)
* SCSI Block Commands - 2 (SBC-2)
* Multi-Media Commands - 5 (MMC-5)
*/
/* Group 1 commands (CDB's here are should all be 6-bytes) */
#define SCSI_CMD_TEST_UNIT_READY 0x00
#define SCSI_CMD_REQUEST_SENSE 0x03
#define SCSI_CMD_FORMAT_UNIT 0x04
#define SCSI_CMD_READ_6 0x08
#define SCSI_CMD_READ_10 0x28
#define SCSI_CMD_READ_CAPACITY_10 0x25
#define SCSI_CMD_TEST_UNIT_READY 0x00
#define SCSI_CMD_WRITE_6 0x0A
#define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_INQUIRY 0x12
#define SCSI_CMD_MODE_SELECT_6 0x15
#define SCSI_CMD_MODE_SENSE_6 0x1A
#define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_START_STOP_UNIT 0x1B
#define SCSI_CMD_PREVENT_REMOVAL 0x1E
/* Group 2 Commands (CDB's here are 10-bytes) */
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
#define SCSI_CMD_READ_CAPACITY_10 0x25
#define SCSI_CMD_READ_10 0x28
#define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_SEEK_10 0x2B
#define SCSI_CMD_ERASE_10 0x2C
#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2E
#define SCSI_CMD_VERIFY_10 0x2F
#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35
#define SCSI_CMD_WRITE_BUFFER 0x3B
#define SCSI_CMD_READ_BUFFER 0x3C
#define SCSI_CMD_READ_SUBCHANNEL 0x42
#define SCSI_CMD_READ_TOC 0x43
#define SCSI_CMD_READ_HEADER 0x44
#define SCSI_CMD_PLAY_AUDIO_10 0x45
#define SCSI_CMD_GET_CONFIGURATION 0x46
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47
#define SCSI_CMD_PLAY_AUDIO_TI 0x48
#define SCSI_CMD_PLAY_TRACK_REL_10 0x49
#define SCSI_CMD_GET_EVENT_STATUS 0x4A
#define SCSI_CMD_PAUSE_RESUME 0x4B
#define SCSI_CMD_READ_DISC_INFORMATION 0x51
#define SCSI_CMD_READ_TRACK_INFORMATION 0x52
#define SCSI_CMD_RESERVE_TRACK 0x53
#define SCSI_CMD_SEND_OPC_INFORMATION 0x54
#define SCSI_CMD_MODE_SELECT_10 0x55
#define SCSI_CMD_REPAIR_TRACK 0x58
#define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5B
#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5C
#define SCSI_CMD_SEND_CUE_SHEET 0x5D
/* Group 5 Commands (CDB's here are 12-bytes) */
#define SCSI_CMD_REPORT_LUNS 0xA0
#define SCSI_CMD_BLANK 0xA1
#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2
#define SCSI_CMD_SEND_KEY 0xA3
#define SCSI_CMD_REPORT_KEY 0xA4
#define SCSI_CMD_PLAY_AUDIO_12 0xA5
#define SCSI_CMD_LOAD_UNLOAD 0xA6
#define SCSI_CMD_SET_READ_AHEAD 0xA7
#define SCSI_CMD_READ_12 0xA8
#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9
#define SCSI_CMD_WRITE_12 0xAA
#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xAB
#define SCSI_CMD_GET_PERFORMANCE 0xAC
#define SCSI_CMD_READ_DVD_STRUCTURE 0xAD
#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5
#define SCSI_CMD_SET_STREAMING 0xB6
#define SCSI_CMD_READ_MSF 0xB9
#define SCSI_CMD_SET_SPEED 0xBB
#define SCSI_CMD_MECHANISM_STATUS 0xBD
#define SCSI_CMD_READ_CD 0xBE
#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBF
/* Vendor-unique Commands, included for completeness */
#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4 /* SONY unique */
#define SCSI_CMD_PLAYBACK_CONTROL 0xC9 /* SONY unique */
#define SCSI_CMD_READ_CDDA 0xD8 /* Vendor unique */
#define SCSI_CMD_READ_CDXA 0xDB /* Vendor unique */
#define SCSI_CMD_READ_ALL_SUBCODES 0xDF /* Vendor unique */
/* SCSI error codes */
#define SCSI_S_NOT_READY 0x02
#define SCSI_S_MEDIUM_ERROR 0x03
#define SCSI_S_ILLEGAL_REQUEST 0x05
#define SCSI_S_UNIT_ATTENTION 0x06
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
#define SCSI_ASC_MEDIA_CHANGED 0x28
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
/* USB error codes */
#define MASS_ERR_SUCCESS 0x00
#define MASS_ERR_PHASE_ERROR 0x02
#define MASS_ERR_UNIT_NOT_READY 0x03
@ -87,9 +140,15 @@
#define MASS_ERR_INVALID_CSW 0x07
#define MASS_ERR_NO_MEDIA 0x08
#define MASS_ERR_BAD_LBA 0x09
#define MASS_ERR_MEDIA_CHANGED 0x0A
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
#define MASS_ERR_INVALID_LUN 0x13
#define MASS_ERR_WRITE_STALL 0x14
#define MASS_ERR_READ_NAKS 0x15
#define MASS_ERR_WRITE_NAKS 0x16
#define MASS_ERR_WRITE_PROTECTED 0x17
#define MASS_ERR_NOT_IMPLEMENTED 0xFD
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
@ -98,12 +157,151 @@
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
#define MASS_MAX_ENDPOINTS 3
struct Capacity {
uint8_t data[8];
//uint32_t dwBlockAddress;
//uint32_t dwBlockLength;
} __attribute__((packed));
struct BASICCDB {
uint8_t Opcode;
unsigned unused : 5;
unsigned LUN : 3;
uint8_t info[12];
} __attribute__((packed));
typedef BASICCDB BASICCDB_t;
struct CDB6 {
uint8_t Opcode;
unsigned LBAMSB : 5;
unsigned LUN : 3;
uint8_t LBAHB;
uint8_t LBALB;
uint8_t AllocationLength;
uint8_t Control;
public:
CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
Opcode(_Opcode), LUN(_LUN), LBAMSB(BGRAB2(LBA) & 0x1f), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)),
AllocationLength(_AllocationLength), Control(_Control) {
}
CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
Opcode(_Opcode), LUN(_LUN), LBAMSB(0), LBAHB(0), LBALB(0),
AllocationLength(_AllocationLength), Control(_Control) {
}
} __attribute__((packed));
typedef CDB6 CDB6_t;
struct CDB10 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned LUN : 3;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t Misc2;
uint8_t ALC_MB;
uint8_t ALC_LB;
uint8_t Control;
public:
CDB10(uint8_t _Opcode, uint8_t _LUN) :
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
}
CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)),
Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) {
}
} __attribute__((packed));
typedef CDB10 CDB10_t;
struct CDB12 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned Misc : 3;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Control;
} __attribute__((packed));
typedef CDB12 CDB12_t;
struct CDB_LBA32_16 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned Misc : 3;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t A_M_M_MB;
uint8_t A_M_M_LB;
uint8_t A_M_L_MB;
uint8_t A_M_L_LB;
uint8_t ALC_M_MB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Misc2;
uint8_t Control;
} __attribute__((packed));
struct CDB_LBA64_16 {
uint8_t Opcode;
uint8_t Misc;
uint8_t LBA_M_M_MB;
uint8_t LBA_M_M_LB;
uint8_t LBA_M_L_MB;
uint8_t LBA_M_L_LB;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t ALC_M_MB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Misc2;
uint8_t Control;
} __attribute__((packed));
struct InquiryResponse {
uint8_t DeviceType : 5;
uint8_t PeripheralQualifier : 3;
@ -114,13 +312,29 @@ struct InquiryResponse {
uint8_t Version;
unsigned ResponseDataFormat : 4;
unsigned Reserved2 : 1;
unsigned HISUP : 1;
unsigned NormACA : 1;
unsigned TrmTsk : 1;
unsigned AERC : 1;
uint8_t AdditionalLength;
uint8_t Reserved3[2];
//uint8_t Reserved3[2];
unsigned PROTECT : 1;
unsigned Res : 2;
unsigned ThreePC : 1;
unsigned TPGS : 2;
unsigned ACC : 1;
unsigned SCCS : 1;
unsigned ADDR16 : 1;
unsigned R1 : 1;
unsigned R2 : 1;
unsigned MCHNGR : 1;
unsigned MULTIP : 1;
unsigned VS : 1;
unsigned ENCSERV : 1;
unsigned BQUE : 1;
unsigned SoftReset : 1;
unsigned CmdQue : 1;
@ -141,6 +355,14 @@ struct CommandBlockWrapperBase {
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
public:
CommandBlockWrapperBase() {
}
CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
}
} __attribute__((packed));
struct CommandBlockWrapper : public CommandBlockWrapperBase {
@ -156,6 +378,38 @@ struct CommandBlockWrapper : public CommandBlockWrapperBase {
};
uint8_t CBWCB[16];
public:
// All zeroed.
CommandBlockWrapper() :
CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
}
// Generic Wrap, CDB zeroed.
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
CommandBlockWrapperBase(tag, xflen, flgs),
bmReserved1(0), bmReserved2(0), bmCBWLUN(lu), bmCBWCBLength(cmdlen) {
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
((BASICCDB_t *) CBWCB)->LUN = cmd;
}
// Wrap for CDB of 6
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) :
CommandBlockWrapperBase(tag, xflen, dir),
bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(6) {
memcpy(&CBWCB, cdb, 6);
}
// Wrap for CDB of 10
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) :
CommandBlockWrapperBase(tag, xflen, dir),
bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(10) {
memcpy(&CBWCB, cdb, 10);
}
} __attribute__((packed));
struct CommandStatusWrapper {
@ -184,8 +438,6 @@ struct RequestSenseResponce {
uint8_t SenseKeySpecific[3];
} __attribute__((packed));
#define MASS_MAX_ENDPOINTS 3
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
@ -203,24 +455,22 @@ protected:
EpInfo epInfo[MASS_MAX_ENDPOINTS];
uint32_t dCBWTag; // Tag
uint32_t dCBWDataTransferLength; // Data Transfer Length
//uint32_t dCBWDataTransferLength; // Data Transfer Length
uint8_t bLastUsbError; // Last USB error
uint8_t bMaxLUN; // Max LUN
uint8_t bTheLUN; // Active LUN
protected:
uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
uint8_t ClearEpHalt(uint8_t index);
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
// Additional Initialization Method for Subclasses
virtual uint8_t OnInit() {
return 0;
};
public:
BulkOnly(USB *p);
@ -236,23 +486,21 @@ public:
return bTheLUN; // Active LUN
}
uint8_t Reset();
uint8_t GetMaxLUN(uint8_t *max_lun);
uint8_t SetCurLUN(uint8_t lun);
uint8_t ResetRecovery();
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t TestUnitReady(uint8_t lun);
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
boolean WriteProtected(uint8_t lun);
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
uint8_t LockMedia(uint8_t lun, uint8_t lock);
bool LUNIsGood(uint8_t lun);
uint32_t GetCapacity(uint8_t lun);
uint16_t GetSectorSize(uint8_t lun);
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
@ -263,12 +511,40 @@ public:
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
protected:
// Additional Initialization Method for Subclasses
virtual boolean DEVCLASSOK(uint8_t klass) {
return(klass == USB_CLASS_MASS_STORAGE);
}
uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
private:
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t TestUnitReady(uint8_t lun);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
uint8_t GetMaxLUN(uint8_t *max_lun);
uint8_t SetCurLUN(uint8_t lun);
void Reset();
uint8_t ResetRecovery();
uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
void ClearAllEP();
void CheckMedia();
boolean CheckLUN(uint8_t lun);
uint8_t Page3F(uint8_t lun);
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
uint8_t ClearEpHalt(uint8_t index);
#if MS_WANT_PARSER
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
#endif
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
virtual uint8_t OnInit() {
return 0;
};
};
#endif // __MASSTORAGE_H__

View file

@ -14,11 +14,14 @@ Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* MAX3421E register/bit names and bitmasks */
#if !defined(_usb_h_) || defined(_max3421e_h_)
#error "Never include max3421e.h directly; include Usb.h instead"
#else
#ifndef _max3421e_h_
#define _max3421e_h_
/* MAX3421E register/bit names and bitmasks */
/* Arduino pin definitions */
/* pin numbers to port numbers */
@ -27,9 +30,6 @@ e-mail : support@circuitsathome.com
//#define MAX_GPX 8
#define ON true
#define OFF false
#define SE0 0
#define SE1 1
#define FSHOST 2

Some files were not shown because too many files have changed in this diff Show more