diff --git a/BTD.cpp b/BTD.cpp index e30be250..79a4b6cd 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -20,990 +20,1004 @@ //#define EXTRADEBUG // Uncomment to get even more debugging data const uint8_t BTD::BTD_CONTROL_PIPE = 0; -const uint8_t BTD::BTD_EVENT_PIPE = 1; +const uint8_t BTD::BTD_EVENT_PIPE = 1; const uint8_t BTD::BTD_DATAIN_PIPE = 2; const uint8_t BTD::BTD_DATAOUT_PIPE = 3; -BTD::BTD(USB *p): +BTD::BTD(USB *p) : 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 bPollEnable(false) // Don't start polling before dongle is connected { - for(uint8_t i=0; iRegisterDeviceClass(this); //set devConfig[] entry + for (uint8_t 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; + } + + if (pUsb) // register in USB subsystem + pUsb->RegisterDeviceClass(this); //set devConfig[] entry } uint8_t BTD::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; - uint8_t num_of_conf; // number of configurations - uint16_t PID; - uint16_t VID; - - // get memory address of USB device address pool - AddressPool &addrPool = pUsb->GetAddressPool(); + uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + uint16_t PID; + uint16_t VID; + + // get memory address of USB device address pool + AddressPool &addrPool = pUsb->GetAddressPool(); #ifdef EXTRADEBUG - Notify(PSTR("\r\nBTD Init")); + Notify(PSTR("\r\nBTD Init"), 0x80); #endif - // check if address has already been assigned to an instance - if (bAddress) { + // check if address has already been assigned to an instance + if (bAddress) { #ifdef DEBUG - Notify(PSTR("\r\nAddress in use")); + 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) { + 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 - Notify(PSTR("\r\nAddress not found")); + Notify(PSTR("\r\nAddress not found"), 0x80); #endif - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } - - if (!p->epinfo) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { #ifdef DEBUG - Notify(PSTR("\r\nepinfo is null")); + 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; + + // 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 + Notify(PSTR("\r\nsetAddr: "), 0x80); +#endif + PrintHex (rcode, 0x80); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + PrintHex (bAddress, 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; - - // 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 - Notify(PSTR("\r\nsetAddr: ")); -#endif - PrintHex(rcode); - return rcode; - } -#ifdef EXTRADEBUG - Notify(PSTR("\r\nAddr: ")); - PrintHex(bAddress); -#endif - 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; - VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; - PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; - - if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) { - /* We only need the Control endpoint, so we don't have to initialize the other endpoints of device */ - rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); - if( rcode ) - goto FailSetConf; - - if(PID == PS3_PID || PID == PS3NAVIGATION_PID) { -#ifdef DEBUG - if(PID == PS3_PID) - Notify(PSTR("\r\nDualshock 3 Controller Connected")); - else // must be a navigation controller - Notify(PSTR("\r\nNavigation Controller Connected")); -#endif - /* Set internal bluetooth address */ - setBdaddr(my_bdaddr); - } - else { // must be a Motion controller -#ifdef DEBUG - Notify(PSTR("\r\nMotion Controller Connected")); -#endif - setMoveBdaddr(my_bdaddr); - } - rcode = 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 - } - else { - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - // check if attached device is a Bluetooth dongle and fill endpoint data structure - // 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 confDescrParser(this); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - if(rcode) - goto FailGetConfDescr; - if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted - break; - } - - if (bNumEP < BTD_MAX_ENDPOINTS) - goto FailUnknownDevice; - - // Assign epInfo to epinfo pointer - this time all 3 endpoins - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - if(rcode) - goto FailSetDevTblEntry; - - delay(200); // Give time for address change - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum); - if(rcode) - goto FailSetConf; - - hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command - hci_counter = 0; - hci_state = HCI_INIT_STATE; - watingForConnection = false; - bPollEnable = true; + //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; + VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; + PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; + + if (VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) { + /* We only need the Control endpoint, so we don't have to initialize the other endpoints of device */ + rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); + if (rcode) + goto FailSetConf; + + if (PID == PS3_PID || PID == PS3NAVIGATION_PID) { +#ifdef DEBUG + if (PID == PS3_PID) + Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80); + else // must be a navigation controller + Notify(PSTR("\r\nNavigation Controller Connected"), 0x80); +#endif + /* Set internal bluetooth address */ + setBdaddr(my_bdaddr); + } else { // must be a Motion controller +#ifdef DEBUG + Notify(PSTR("\r\nMotion Controller Connected"), 0x80); +#endif + setMoveBdaddr(my_bdaddr); + } + rcode = 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 + } else { + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // check if attached device is a Bluetooth dongle and fill endpoint data structure + // 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 confDescrParser(this); + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + if (rcode) + goto FailGetConfDescr; + if (bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted + break; + } + + if (bNumEP < BTD_MAX_ENDPOINTS) + goto FailUnknownDevice; + + // Assign epInfo to epinfo pointer - this time all 3 endpoins + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + if (rcode) + goto FailSetDevTblEntry; + + delay(200); // Give time for address change + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum); + if (rcode) + goto FailSetConf; + + hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command + hci_counter = 0; + hci_state = HCI_INIT_STATE; + watingForConnection = false; + bPollEnable = true; #ifdef DEBUG - Notify(PSTR("\r\nBluetooth Dongle Initialized")); + Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80); #endif - } - return 0; // Successful configuration - - /* diagnostic messages */ + } + return 0; // Successful configuration + + /* diagnostic messages */ FailGetDevDescr: #ifdef DEBUG - Notify(PSTR("\r\ngetDevDescr")); + Notify(PSTR("\r\ngetDevDescr"), 0x80); #endif - goto Fail; + goto Fail; FailSetDevTblEntry: #ifdef DEBUG - Notify(PSTR("\r\nsetDevTblEn")); + Notify(PSTR("\r\nsetDevTblEn"), 0x80); #endif - goto Fail; + goto Fail; FailGetConfDescr: #ifdef DEBUG - Notify(PSTR("\r\ngetConf")); + Notify(PSTR("\r\ngetConf"), 0x80); #endif - goto Fail; + goto Fail; FailSetConf: #ifdef DEBUG - Notify(PSTR("\r\nsetConf")); + Notify(PSTR("\r\nsetConf"), 0x80); #endif - goto Fail; + goto Fail; FailUnknownDevice: #ifdef DEBUG - Notify(PSTR("\r\nUnknown Device Connected - VID: ")); - PrintHex(VID); - Notify(PSTR(" PID: ")); - PrintHex(PID); + Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); + PrintHex (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + PrintHex (PID, 0x80); #endif - pUsb->setAddr(bAddress, 0, 0); // Reset address - rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - goto Fail; + pUsb->setAddr(bAddress, 0, 0); // Reset address + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + goto Fail; Fail: #ifdef DEBUG - Notify(PSTR("\r\nBTD Init Failed, error code: ")); - Serial.print(rcode); -#endif - Release(); - return rcode; + Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80); + Serial.print(rcode); +#endif + Release(); + return rcode; } + /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */ void BTD::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { - //ErrorMessage(PSTR("Conf.Val"),conf); - //ErrorMessage(PSTR("Iface Num"),iface); - //ErrorMessage(PSTR("Alt.Set"),alt); - - if(alt) // wrong interface - by BT spec, no alt setting - return; - - bConfNum = conf; - uint8_t index; - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Interrupt In endpoint found - index = BTD_EVENT_PIPE; - - else { - if ((pep->bmAttributes & 0x02) == 2) // bulk endpoint found - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE; - else - return; - } - - // Fill the rest of endpoint data structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + //ErrorMessage(PSTR("Conf.Val"),conf); + //ErrorMessage(PSTR("Iface Num"),iface); + //ErrorMessage(PSTR("Alt.Set"),alt); + + if (alt) // wrong interface - by BT spec, no alt setting + return; + + bConfNum = conf; + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Interrupt In endpoint found + index = BTD_EVENT_PIPE; + + else { + if ((pep->bmAttributes & 0x02) == 2) // bulk endpoint found + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE; + else + return; + } + + // Fill the rest of endpoint data structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; #ifdef EXTRADEBUG - PrintEndpointDescriptor(pep); + PrintEndpointDescriptor(pep); #endif - if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints - pollInterval = pep->bInterval; - bNumEP++; + if (pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints + pollInterval = pep->bInterval; + bNumEP++; } + void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { #ifdef EXTRADEBUG - Notify(PSTR("\r\nEndpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); + Notify(PSTR("\r\nEndpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (ep_ptr->bInterval, 0x80); #endif } /* Performs a cleanup after failed Init() attempt */ uint8_t BTD::Release() { - for (uint8_t i=0; iReset(); // Reset all Bluetooth services - pUsb->GetAddressPool().FreeAddress(bAddress); - bAddress = 0; - bPollEnable = false; - bNumEP = 1; // must have to be reset to 1 - return 0; + for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) + if (btService[i]) + btService[i]->Reset(); // Reset all Bluetooth services + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; + bNumEP = 1; // must have to be reset to 1 + return 0; } + uint8_t BTD::Poll() { - if (!bPollEnable) - return 0; - if (qNextPollTime <= millis()) { // Don't poll if shorter than polling interval - qNextPollTime = millis() + pollInterval; // Set new poll time - HCI_event_task(); // poll the HCI event pipe - ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected - } - return 0; + if (!bPollEnable) + return 0; + if (qNextPollTime <= millis()) { // Don't poll if shorter than polling interval + qNextPollTime = millis() + pollInterval; // Set new poll time + HCI_event_task(); // poll the HCI event pipe + ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected + } + return 0; } 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 || rcode == hrNAK) // Check for errors - { - switch (hcibuf[0]) //switch on event type + /* 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 || rcode == hrNAK) // Check for errors { - case EV_COMMAND_COMPLETE: - if (!hcibuf[5]) { // Check if command succeeded - hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag - if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // parameters from read local version information - hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm - hci_event_flag |= HCI_FLAG_READ_VERSION; - } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // parameters from read local bluetooth address - for (uint8_t i = 0; i < 6; i++) - my_bdaddr[i] = hcibuf[6 + i]; - hci_event_flag |= HCI_FLAG_READ_BDADDR; - } - } - break; - - case EV_COMMAND_STATUS: - if(hcibuf[2]) { // show status on serial if not OK + switch (hcibuf[0]) //switch on event type + { + case EV_COMMAND_COMPLETE: + if (!hcibuf[5]) { // Check if command succeeded + hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag + if ((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // parameters from read local version information + hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm + hci_event_flag |= HCI_FLAG_READ_VERSION; + } else if ((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // parameters from read local bluetooth address + for (uint8_t i = 0; i < 6; i++) + my_bdaddr[i] = hcibuf[6 + i]; + hci_event_flag |= HCI_FLAG_READ_BDADDR; + } + } + break; + + case EV_COMMAND_STATUS: + if (hcibuf[2]) { // show status on serial if not OK #ifdef DEBUG - Notify(PSTR("\r\nHCI Command Failed: ")); - PrintHex(hcibuf[2]); - Notify(PSTR(" ")); - PrintHex(hcibuf[4]); - Notify(PSTR(" ")); - PrintHex(hcibuf[5]); + Notify(PSTR("\r\nHCI Command Failed: "), 0x80); + PrintHex (hcibuf[2], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (hcibuf[4], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (hcibuf[5], 0x80); #endif - } - break; - - case EV_INQUIRY_COMPLETE: - if(inquiry_counter >= 5) { - inquiry_counter = 0; + } + break; + + case EV_INQUIRY_COMPLETE: + if (inquiry_counter >= 5) { + inquiry_counter = 0; #ifdef DEBUG - Notify(PSTR("\r\nCouldn't find Wiimote")); + Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80); #endif - connectToWii = false; - pairWithWii = false; - hci_state = HCI_SCANNING_STATE; - } - inquiry_counter++; - break; - - case EV_INQUIRY_RESULT: - if (hcibuf[2]) { // Check that there is more than zero responses + connectToWii = false; + pairWithWii = false; + hci_state = HCI_SCANNING_STATE; + } + inquiry_counter++; + break; + + case EV_INQUIRY_RESULT: + if (hcibuf[2]) { // Check that there is more than zero responses #ifdef EXTRADEBUG - Notify(PSTR("\r\nNumber of responses: ")); - Serial.print(hcibuf[2]); + Notify(PSTR("\r\nNumber of responses: "), 0x80); + Serial.print(hcibuf[2]); #endif - for(uint8_t i = 0; i < hcibuf[2]; i++) { - if((hcibuf[4+8*hcibuf[2]+3*i] == 0x04 && hcibuf[5+8*hcibuf[2]+3*i] == 0x25 && hcibuf[6+8*hcibuf[2]+3*i] == 0x00) || (hcibuf[4+8*hcibuf[2]+3*i] == 0x08 && hcibuf[5+8*hcibuf[2]+3*i] == 0x05 && hcibuf[6+8*hcibuf[2]+3*i] == 0x00)) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html and http://wiibrew.org/wiki/Wiimote#SDP_information - if(hcibuf[4+8*hcibuf[2]+3*i] == 0x08) // Check if it's the new Wiimote with motion plus inside that was detected - motionPlusInside = true; - else - motionPlusInside = false; - disc_bdaddr[0] = hcibuf[3+6*i]; - disc_bdaddr[1] = hcibuf[4+6*i]; - disc_bdaddr[2] = hcibuf[5+6*i]; - disc_bdaddr[3] = hcibuf[6+6*i]; - disc_bdaddr[4] = hcibuf[7+6*i]; - disc_bdaddr[5] = hcibuf[8+6*i]; - hci_event_flag |= HCI_FLAG_WII_FOUND; - break; - } + for (uint8_t i = 0; i < hcibuf[2]; i++) { + if ((hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x04 && hcibuf[5 + 8 * hcibuf[2] + 3 * i] == 0x25 && hcibuf[6 + 8 * hcibuf[2] + 3 * i] == 0x00) || (hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x08 && hcibuf[5 + 8 * hcibuf[2] + 3 * i] == 0x05 && hcibuf[6 + 8 * hcibuf[2] + 3 * i] == 0x00)) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html and http://wiibrew.org/wiki/Wiimote#SDP_information + if (hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x08) // Check if it's the new Wiimote with motion plus inside that was detected + motionPlusInside = true; + else + motionPlusInside = false; + disc_bdaddr[0] = hcibuf[3 + 6 * i]; + disc_bdaddr[1] = hcibuf[4 + 6 * i]; + disc_bdaddr[2] = hcibuf[5 + 6 * i]; + disc_bdaddr[3] = hcibuf[6 + 6 * i]; + disc_bdaddr[4] = hcibuf[7 + 6 * i]; + disc_bdaddr[5] = hcibuf[8 + 6 * i]; + hci_event_flag |= HCI_FLAG_WII_FOUND; + break; + } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nClass of device: ")); - PrintHex(hcibuf[6+8*hcibuf[2]+3*i]); - Notify(PSTR(" ")); - PrintHex(hcibuf[5+8*hcibuf[2]+3*i]); - Notify(PSTR(" ")); - PrintHex(hcibuf[4+8*hcibuf[2]+3*i]); - } + else { + Notify(PSTR("\r\nClass of device: "), 0x80); + PrintHex (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80); + } #endif - } - } - break; - - case EV_CONNECT_COMPLETE: - hci_event_flag |= HCI_FLAG_CONNECT_EVENT; - if (!hcibuf[2]) { // check if connected OK - hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // store the handle for the ACL connection - hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag - } + } + } + break; + + case EV_CONNECT_COMPLETE: + hci_event_flag |= HCI_FLAG_CONNECT_EVENT; + if (!hcibuf[2]) { // check if connected OK + hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // store the handle for the ACL connection + hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag + } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nConnection Failed")); - } + else { + Notify(PSTR("\r\nConnection Failed"), 0x80); + } #endif - break; - - case EV_DISCONNECT_COMPLETE: - if (!hcibuf[2]) { // check if disconnected OK - hci_event_flag |= HCI_FLAG_DISCONN_COMPLETE; // set disconnect command complete flag - hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; // clear connection complete flag - } - break; - - case EV_REMOTE_NAME_COMPLETE: - if (!hcibuf[2]) { // check if reading is OK - for (uint8_t i = 0; i < 30; i++) - remote_name[i] = hcibuf[9 + i]; //store first 30 bytes - hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE; - } - break; - - case EV_INCOMING_CONNECT: - disc_bdaddr[0] = hcibuf[2]; - disc_bdaddr[1] = hcibuf[3]; - disc_bdaddr[2] = hcibuf[4]; - disc_bdaddr[3] = hcibuf[5]; - disc_bdaddr[4] = hcibuf[6]; - disc_bdaddr[5] = hcibuf[7]; - hci_event_flag |= HCI_FLAG_INCOMING_REQUEST; - break; - - case EV_PIN_CODE_REQUEST: - if(pairWithWii) { + break; + + case EV_DISCONNECT_COMPLETE: + if (!hcibuf[2]) { // check if disconnected OK + hci_event_flag |= HCI_FLAG_DISCONN_COMPLETE; // set disconnect command complete flag + hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; // clear connection complete flag + } + break; + + case EV_REMOTE_NAME_COMPLETE: + if (!hcibuf[2]) { // check if reading is OK + for (uint8_t i = 0; i < 30; i++) + remote_name[i] = hcibuf[9 + i]; //store first 30 bytes + hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE; + } + break; + + case EV_INCOMING_CONNECT: + disc_bdaddr[0] = hcibuf[2]; + disc_bdaddr[1] = hcibuf[3]; + disc_bdaddr[2] = hcibuf[4]; + disc_bdaddr[3] = hcibuf[5]; + disc_bdaddr[4] = hcibuf[6]; + disc_bdaddr[5] = hcibuf[7]; + hci_event_flag |= HCI_FLAG_INCOMING_REQUEST; + break; + + case EV_PIN_CODE_REQUEST: + if (pairWithWii) { #ifdef DEBUG - Notify(PSTR("\r\nPairing with wiimote")); + Notify(PSTR("\r\nPairing with wiimote"), 0x80); #endif - hci_pin_code_request_reply(); - } - else if(btdPin != NULL) { + hci_pin_code_request_reply(); + } else if (btdPin != NULL) { #ifdef DEBUG - Notify(PSTR("\r\nBluetooth pin is set too: ")); - Serial.print(btdPin); + Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80); + Serial.print(btdPin); #endif - hci_pin_code_request_reply(); - } - else { + hci_pin_code_request_reply(); + } else { #ifdef DEBUG - Notify(PSTR("\r\nNo pin was set")); + Notify(PSTR("\r\nNo pin was set"), 0x80); #endif - hci_pin_code_negative_request_reply(); - } - break; - - case EV_LINK_KEY_REQUEST: + hci_pin_code_negative_request_reply(); + } + break; + + case EV_LINK_KEY_REQUEST: #ifdef DEBUG - Notify(PSTR("\r\nReceived Key Request")); + Notify(PSTR("\r\nReceived Key Request"), 0x80); #endif - hci_link_key_request_negative_reply(); - break; - - case EV_AUTHENTICATION_COMPLETE: - if(pairWithWii && !connectToWii) { + hci_link_key_request_negative_reply(); + break; + + case EV_AUTHENTICATION_COMPLETE: + if (pairWithWii && !connectToWii) { #ifdef DEBUG - Notify(PSTR("\r\nPairing successful")); + Notify(PSTR("\r\nPairing successful"), 0x80); #endif - connectToWii = true; // Only send the ACL data to the Wii service - } - break; - /* We will just ignore the following events */ - case EV_NUM_COMPLETE_PKT: - case EV_ROLE_CHANGED: - case EV_PAGE_SCAN_REP_MODE: - case EV_LOOPBACK_COMMAND: - case EV_DATA_BUFFER_OVERFLOW: - case EV_CHANGE_CONNECTION_LINK: - case EV_MAX_SLOTS_CHANGE: - case EV_QOS_SETUP_COMPLETE: - case EV_LINK_KEY_NOTIFICATION: - case EV_ENCRYPTION_CHANGE: - case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: - break; + connectToWii = true; // Only send the ACL data to the Wii service + } + break; + /* We will just ignore the following events */ + case EV_NUM_COMPLETE_PKT: + case EV_ROLE_CHANGED: + case EV_PAGE_SCAN_REP_MODE: + case EV_LOOPBACK_COMMAND: + case EV_DATA_BUFFER_OVERFLOW: + case EV_CHANGE_CONNECTION_LINK: + case EV_MAX_SLOTS_CHANGE: + case EV_QOS_SETUP_COMPLETE: + case EV_LINK_KEY_NOTIFICATION: + case EV_ENCRYPTION_CHANGE: + case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: + break; #ifdef EXTRADEBUG - default: - if(hcibuf[0] != 0x00) { - Notify(PSTR("\r\nUnmanaged HCI Event: ")); - PrintHex(hcibuf[0]); - } - break; + default: + if (hcibuf[0] != 0x00) { + Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80); + PrintHex (hcibuf[0], 0x80); + } + break; #endif - } // switch - HCI_task(); - } + } // switch + HCI_task(); + } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nHCI event error: ")); - PrintHex(rcode); - } + else { + Notify(PSTR("\r\nHCI event error: "), 0x80); + PrintHex (rcode, 0x80); + } #endif } /* Poll Bluetooth and print result */ void BTD::HCI_task() { - switch (hci_state){ - case HCI_INIT_STATE: - hci_counter++; - if (hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events - hci_reset(); - hci_state = HCI_RESET_STATE; - hci_counter = 0; - } - break; - - case HCI_RESET_STATE: - hci_counter++; - if (hci_cmd_complete) { - hci_counter = 0; -#ifdef DEBUG - Notify(PSTR("\r\nHCI Reset complete")); -#endif - hci_state = HCI_CLASS_STATE; - hci_write_class_of_device(); - } - else if (hci_counter > hci_num_reset_loops) { - hci_num_reset_loops *= 10; - if(hci_num_reset_loops > 2000) - hci_num_reset_loops = 2000; -#ifdef DEBUG - Notify(PSTR("\r\nNo response to HCI Reset")); -#endif - hci_state = HCI_INIT_STATE; - hci_counter = 0; - } - break; - - case HCI_CLASS_STATE: - if(hci_cmd_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nWrite class of device")); -#endif - hci_state = HCI_BDADDR_STATE; - hci_read_bdaddr(); - } - break; - - case HCI_BDADDR_STATE: - if (hci_read_bdaddr_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nLocal Bluetooth Address: ")); - for(int8_t i = 5; i > 0;i--) { - PrintHex(my_bdaddr[i]); - Notify(PSTR(":")); - } - PrintHex(my_bdaddr[0]); -#endif - hci_read_local_version_information(); - hci_state = HCI_LOCAL_VERSION_STATE; - } - break; - - case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class - if (hci_read_version_complete) { - if(btdName != NULL) { - hci_set_local_name(btdName); - hci_state = HCI_SET_NAME_STATE; - } else - hci_state = HCI_CHECK_WII_SERVICE; - } - break; - - case HCI_SET_NAME_STATE: - if (hci_cmd_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nThe name is set to: ")); - Serial.print(btdName); -#endif - hci_state = HCI_CHECK_WII_SERVICE; - } - break; - - case HCI_CHECK_WII_SERVICE: - if(pairWithWii) { // Check if it should try to connect to a wiimote -#ifdef DEBUG - 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")); -#endif - hci_inquiry(); - hci_state = HCI_INQUIRY_STATE; - } - else - hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote - break; - - case HCI_INQUIRY_STATE: - if(hci_wii_found) { - hci_inquiry_cancel(); // Stop inquiry -#ifdef DEBUG - Notify(PSTR("\r\nWiimote found")); - Notify(PSTR("\r\nNow just create the instance like so:")); - Notify(PSTR("\r\nWII Wii(&Btd);")); - Notify(PSTR("\r\nAnd then press any button on the Wiimote")); -#endif - if(motionPlusInside) { - hci_remote_name(); // We need to know the name to distinguish between a Wiimote and a Wii U Pro Controller - hci_state = HCI_REMOTE_NAME_STATE; - } else - hci_state = HCI_CONNECT_WII_STATE; - } - break; - - case HCI_CONNECT_WII_STATE: - if(hci_cmd_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nConnecting to Wiimote")); -#endif - hci_connect(); - hci_state = HCI_CONNECTED_WII_STATE; - } - break; - - case HCI_CONNECTED_WII_STATE: - if(hci_connect_event) { - if(hci_connect_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nConnected to Wiimote")); -#endif - hci_authentication_request(); // This will start the pairing with the wiimote - hci_state = HCI_SCANNING_STATE; - } else { -#ifdef DEBUG - Notify(PSTR("\r\nTrying to connect one more time...")); -#endif - hci_connect(); // Try to connect one more time - } - } - break; - - case HCI_SCANNING_STATE: - if(!connectToWii && !pairWithWii) { -#ifdef DEBUG - Notify(PSTR("\r\nWait For Incoming Connection Request")); -#endif - hci_write_scan_enable(); - watingForConnection = true; - hci_state = HCI_CONNECT_IN_STATE; - } - break; - - case HCI_CONNECT_IN_STATE: - if(hci_incoming_connect_request) { - watingForConnection = false; -#ifdef DEBUG - Notify(PSTR("\r\nIncoming Connection Request")); -#endif - hci_remote_name(); - hci_state = HCI_REMOTE_NAME_STATE; - } else if (hci_disconnect_complete) - hci_state = HCI_DISCONNECT_STATE; - break; - - case HCI_REMOTE_NAME_STATE: - if(hci_remote_name_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nRemote Name: ")); - for (uint8_t i = 0; i < 30; i++) { - if(remote_name[i] == NULL) + switch (hci_state) { + case HCI_INIT_STATE: + hci_counter++; + if (hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events + hci_reset(); + hci_state = HCI_RESET_STATE; + hci_counter = 0; + } break; - Serial.write(remote_name[i]); - } -#endif - if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) { -#ifdef DEBUG - Notify(PSTR("\r\nWiimote is connecting")); -#endif - if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) { -#ifdef DEBUG - Notify(PSTR(" with Motion Plus Inside")); -#endif - motionPlusInside = true; - } - else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) { -#ifdef DEBUG - Notify(PSTR(" - Wii U Pro Controller")); -#endif - motionPlusInside = true; - wiiUProController = true; - } else { - motionPlusInside = false; - wiiUProController = false; - } - incomingWii = true; - } - if(pairWithWii && motionPlusInside) - hci_state = HCI_CONNECT_WII_STATE; - else { - hci_accept_connection(); - hci_state = HCI_CONNECTED_STATE; - } - } - break; - - case HCI_CONNECTED_STATE: - if (hci_connect_complete) { -#ifdef DEBUG - Notify(PSTR("\r\nConnected to Device: ")); - for(int8_t i = 5; i>0;i--) { - PrintHex(disc_bdaddr[i]); - Notify(PSTR(":")); - } - PrintHex(disc_bdaddr[0]); -#endif - // Clear these flags for a new connection - l2capConnectionClaimed = false; - sdpConnectionClaimed = false; - rfcommConnectionClaimed = false; - - hci_event_flag = 0; - hci_state = HCI_DONE_STATE; - } - break; - case HCI_DONE_STATE: - hci_counter++; - if (hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started - hci_counter = 0; - hci_state = HCI_SCANNING_STATE; - } - break; - - case HCI_DISCONNECT_STATE: - if (hci_disconnect_complete) { + case HCI_RESET_STATE: + hci_counter++; + if (hci_cmd_complete) { + hci_counter = 0; #ifdef DEBUG - Notify(PSTR("\r\nHCI Disconnected from Device")); + Notify(PSTR("\r\nHCI Reset complete"), 0x80); #endif - hci_event_flag = 0; // Clear all flags - - // Reset all buffers - for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) - hcibuf[i] = 0; - for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) - l2capinbuf[i] = 0; - - hci_state = HCI_SCANNING_STATE; - } - break; - default: - break; - } + hci_state = HCI_CLASS_STATE; + hci_write_class_of_device(); + } else if (hci_counter > hci_num_reset_loops) { + hci_num_reset_loops *= 10; + if (hci_num_reset_loops > 2000) + hci_num_reset_loops = 2000; +#ifdef DEBUG + Notify(PSTR("\r\nNo response to HCI Reset"), 0x80); +#endif + hci_state = HCI_INIT_STATE; + hci_counter = 0; + } + break; + + case HCI_CLASS_STATE: + if (hci_cmd_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nWrite class of device"), 0x80); +#endif + hci_state = HCI_BDADDR_STATE; + hci_read_bdaddr(); + } + break; + + case HCI_BDADDR_STATE: + if (hci_read_bdaddr_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (my_bdaddr[i], 0x80); + Notify(PSTR(":"), 0x80); + } + PrintHex (my_bdaddr[0], 0x80); +#endif + hci_read_local_version_information(); + hci_state = HCI_LOCAL_VERSION_STATE; + } + break; + + case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class + if (hci_read_version_complete) { + if (btdName != NULL) { + hci_set_local_name(btdName); + hci_state = HCI_SET_NAME_STATE; + } else + hci_state = HCI_CHECK_WII_SERVICE; + } + break; + + case HCI_SET_NAME_STATE: + if (hci_cmd_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nThe name is set to: "), 0x80); + Serial.print(btdName); +#endif + hci_state = HCI_CHECK_WII_SERVICE; + } + break; + + case HCI_CHECK_WII_SERVICE: + if (pairWithWii) { // Check if it should try to connect to a wiimote +#ifdef DEBUG + 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(); + hci_state = HCI_INQUIRY_STATE; + } else + hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote + break; + + case HCI_INQUIRY_STATE: + if (hci_wii_found) { + hci_inquiry_cancel(); // Stop inquiry +#ifdef DEBUG + Notify(PSTR("\r\nWiimote found"), 0x80); + Notify(PSTR("\r\nNow just create the instance like so:"), 0x80); + Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80); + Notify(PSTR("\r\nAnd then press any button on the Wiimote"), 0x80); +#endif + if (motionPlusInside) { + hci_remote_name(); // We need to know the name to distinguish between a Wiimote and a Wii U Pro Controller + hci_state = HCI_REMOTE_NAME_STATE; + } else + hci_state = HCI_CONNECT_WII_STATE; + } + break; + + case HCI_CONNECT_WII_STATE: + if (hci_cmd_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nConnecting to Wiimote"), 0x80); +#endif + hci_connect(); + hci_state = HCI_CONNECTED_WII_STATE; + } + break; + + case HCI_CONNECTED_WII_STATE: + if (hci_connect_event) { + if (hci_connect_complete) { +#ifdef DEBUG + 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 + Notify(PSTR("\r\nTrying to connect one more time..."), 0x80); +#endif + hci_connect(); // Try to connect one more time + } + } + break; + + case HCI_SCANNING_STATE: + if (!connectToWii && !pairWithWii) { +#ifdef DEBUG + Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80); +#endif + hci_write_scan_enable(); + watingForConnection = true; + hci_state = HCI_CONNECT_IN_STATE; + } + break; + + case HCI_CONNECT_IN_STATE: + if (hci_incoming_connect_request) { + watingForConnection = false; +#ifdef DEBUG + Notify(PSTR("\r\nIncoming Connection Request"), 0x80); +#endif + hci_remote_name(); + hci_state = HCI_REMOTE_NAME_STATE; + } else if (hci_disconnect_complete) + hci_state = HCI_DISCONNECT_STATE; + break; + + case HCI_REMOTE_NAME_STATE: + if (hci_remote_name_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nRemote Name: "), 0x80); + for (uint8_t i = 0; i < 30; i++) { + if (remote_name[i] == NULL) + break; + Serial.write(remote_name[i]); + } +#endif + if (strncmp((const char*)remote_name, "Nintendo", 8) == 0) { +#ifdef DEBUG + Notify(PSTR("\r\nWiimote is connecting"), 0x80); +#endif + if (strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) { +#ifdef DEBUG + 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 + Notify(PSTR(" - Wii U Pro Controller"), 0x80); +#endif + motionPlusInside = true; + wiiUProController = true; + } else { + motionPlusInside = false; + wiiUProController = false; + } + incomingWii = true; + } + if (pairWithWii && motionPlusInside) + hci_state = HCI_CONNECT_WII_STATE; + else { + hci_accept_connection(); + hci_state = HCI_CONNECTED_STATE; + } + } + break; + + case HCI_CONNECTED_STATE: + if (hci_connect_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nConnected to Device: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (disc_bdaddr[i], 0x80); + Notify(PSTR(":"), 0x80); + } + PrintHex (disc_bdaddr[0], 0x80); +#endif + // Clear these flags for a new connection + l2capConnectionClaimed = false; + sdpConnectionClaimed = false; + rfcommConnectionClaimed = false; + + hci_event_flag = 0; + hci_state = HCI_DONE_STATE; + } + break; + + case HCI_DONE_STATE: + hci_counter++; + if (hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started + hci_counter = 0; + hci_state = HCI_SCANNING_STATE; + } + break; + + case HCI_DISCONNECT_STATE: + if (hci_disconnect_complete) { +#ifdef DEBUG + Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80); +#endif + hci_event_flag = 0; // Clear all flags + + // Reset all buffers + for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) + hcibuf[i] = 0; + for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) + l2capinbuf[i] = 0; + + hci_state = HCI_SCANNING_STATE; + } + break; + default: + break; + } } void BTD::ACL_event_task() { - uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; - uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &MAX_BUFFER_SIZE, l2capinbuf); // input on endpoint 2 - if(!rcode) { // Check for errors - for (uint8_t i=0; iACLData(l2capinbuf); - } + uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; + uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &MAX_BUFFER_SIZE, l2capinbuf); // input on endpoint 2 + if (!rcode) { // Check for errors + for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) + if (btService[i]) + btService[i]->ACLData(l2capinbuf); + } #ifdef EXTRADEBUG - else if (rcode != hrNAK) { - Notify(PSTR("\r\nACL data in error: ")); - PrintHex(rcode); - } + else if (rcode != hrNAK) { + Notify(PSTR("\r\nACL data in error: "), 0x80); + PrintHex (rcode, 0x80); + } #endif - for (uint8_t i=0; iRun(); + for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) + if (btService[i]) + btService[i]->Run(); } /************************************************************/ /* HCI Commands */ + /************************************************************/ void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) { - hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE; - pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00 ,0x00, nbytes, nbytes, data, NULL); + hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE; + pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL); } -void BTD::hci_reset() { - hci_event_flag = 0; // Clear all the flags - hcibuf[0] = 0x03; // HCI OCF = 3 - hcibuf[1] = 0x03 << 2; // HCI OGF = 3 - hcibuf[2] = 0x00; - HCI_Command(hcibuf, 3); -} -void BTD::hci_write_scan_enable() { - hci_event_flag &= ~HCI_FLAG_INCOMING_REQUEST; - hcibuf[0] = 0x1A; // HCI OCF = 1A - hcibuf[1] = 0x03 << 2; // HCI OGF = 3 - hcibuf[2] = 0x01; // parameter length = 1 - if(btdName != NULL) - hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled. - else - hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled. - HCI_Command(hcibuf, 4); -} -void BTD::hci_write_scan_disable() { - hcibuf[0] = 0x1A; // HCI OCF = 1A - hcibuf[1] = 0x03 << 2; // HCI OGF = 3 - hcibuf[2] = 0x01; // parameter length = 1 - hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled. - HCI_Command(hcibuf, 4); -} -void BTD::hci_read_bdaddr() { - hcibuf[0] = 0x09; // HCI OCF = 9 - hcibuf[1] = 0x04 << 2; // HCI OGF = 4 - hcibuf[2] = 0x00; - HCI_Command(hcibuf, 3); -} -void BTD::hci_read_local_version_information() { - hcibuf[0] = 0x01; // HCI OCF = 1 - hcibuf[1] = 0x04 << 2; // HCI OGF = 4 - hcibuf[2] = 0x00; - HCI_Command(hcibuf, 3); -} -void BTD::hci_accept_connection() { - hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; - hcibuf[0] = 0x09; // HCI OCF = 9 - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x07; // parameter length 7 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - hcibuf[9] = 0x00; //switch role to master - - HCI_Command(hcibuf, 10); -} -void BTD::hci_remote_name() { - hci_event_flag &= ~HCI_FLAG_REMOTE_NAME_COMPLETE; - hcibuf[0] = 0x19; // HCI OCF = 19 - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x0A; // parameter length = 10 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - hcibuf[9] = 0x01; //Page Scan Repetition Mode - hcibuf[10] = 0x00; //Reserved - hcibuf[11] = 0x00; //Clock offset - low byte - hcibuf[12] = 0x00; //Clock offset - high byte - - HCI_Command(hcibuf, 13); -} -void BTD::hci_set_local_name(const char* name) { - hcibuf[0] = 0x13; // HCI OCF = 13 - hcibuf[1] = 0x03 << 2; // HCI OGF = 3 - hcibuf[2] = strlen(name)+1; // parameter length = the length of the string + end byte - uint8_t i; - for(i = 0; i < strlen(name); i++) - hcibuf[i+3] = name[i]; - hcibuf[i+3] = 0x00; // End of string - HCI_Command(hcibuf, 4+strlen(name)); +void BTD::hci_reset() { + hci_event_flag = 0; // Clear all the flags + hcibuf[0] = 0x03; // HCI OCF = 3 + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 0x00; + HCI_Command(hcibuf, 3); } -void BTD::hci_inquiry() { - hci_event_flag &= ~HCI_FLAG_WII_FOUND; - hcibuf[0] = 0x01; - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x05; // Parameter Total Length = 5 - hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm - hcibuf[4] = 0x8B; - hcibuf[5] = 0x9E; - hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum) - hcibuf[7] = 0x0A; // 10 number of responses - - HCI_Command(hcibuf, 8); + +void BTD::hci_write_scan_enable() { + hci_event_flag &= ~HCI_FLAG_INCOMING_REQUEST; + hcibuf[0] = 0x1A; // HCI OCF = 1A + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 0x01; // parameter length = 1 + if (btdName != NULL) + hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled. + else + hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled. + HCI_Command(hcibuf, 4); } -void BTD::hci_inquiry_cancel() { - hcibuf[0] = 0x02; - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x0; // Parameter Total Length = 0 - - HCI_Command(hcibuf, 3); + +void BTD::hci_write_scan_disable() { + hcibuf[0] = 0x1A; // HCI OCF = 1A + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 0x01; // parameter length = 1 + hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled. + HCI_Command(hcibuf, 4); } -void BTD::hci_connect() { - hci_event_flag &= ~(HCI_FLAG_CONN_COMPLETE | HCI_FLAG_CONNECT_EVENT); - hcibuf[0] = 0x05; - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x0D; // parameter Total Length = 13 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - hcibuf[9] = 0x18; // DM1 or DH1 may be used - hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used - hcibuf[11] = 0x01; // Page repetition mode R1 - hcibuf[12] = 0x00; // Reserved - hcibuf[13] = 0x00; // Clock offset - hcibuf[14] = 0x00; // Invalid clock offset - hcibuf[15] = 0x00; // Do not allow role switch - - HCI_Command(hcibuf, 16); + +void BTD::hci_read_bdaddr() { + hcibuf[0] = 0x09; // HCI OCF = 9 + hcibuf[1] = 0x04 << 2; // HCI OGF = 4 + hcibuf[2] = 0x00; + HCI_Command(hcibuf, 3); } -void BTD::hci_pin_code_request_reply() { - hcibuf[0] = 0x0D; // HCI OCF = 0D - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x17; // parameter length 23 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - if(pairWithWii && !wiiUProController) { - hcibuf[9] = 6; // Pin length is the length of the bt address - hcibuf[10] = disc_bdaddr[0]; // The pin is the Wiimotes bt address backwards - hcibuf[11] = disc_bdaddr[1]; - hcibuf[12] = disc_bdaddr[2]; - hcibuf[13] = disc_bdaddr[3]; - hcibuf[14] = disc_bdaddr[4]; - hcibuf[15] = disc_bdaddr[5]; - for(uint8_t i = 16; i < 26; i++) - hcibuf[i] = 0x00; // The rest should be 0 - } else if(pairWithWii && wiiUProController) { -#ifdef DEBUG - Notify(PSTR("\r\nParing with Wii U Pro Controller")); -#endif - hcibuf[9] = 6; // Pin length is the length of the bt address - hcibuf[10] = my_bdaddr[0]; // The pin is the Bluetooth dongles bt address backwards - hcibuf[11] = my_bdaddr[1]; - hcibuf[12] = my_bdaddr[2]; - hcibuf[13] = my_bdaddr[3]; - hcibuf[14] = my_bdaddr[4]; - hcibuf[15] = my_bdaddr[5]; - for(uint8_t i = 16; i < 26; i++) - hcibuf[i] = 0x00; // The rest should be 0 - } else { - hcibuf[9] = strlen(btdPin); // Length of pin + +void BTD::hci_read_local_version_information() { + hcibuf[0] = 0x01; // HCI OCF = 1 + hcibuf[1] = 0x04 << 2; // HCI OGF = 4 + hcibuf[2] = 0x00; + HCI_Command(hcibuf, 3); +} + +void BTD::hci_accept_connection() { + hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; + hcibuf[0] = 0x09; // HCI OCF = 9 + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x07; // parameter length 7 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + hcibuf[9] = 0x00; //switch role to master + + HCI_Command(hcibuf, 10); +} + +void BTD::hci_remote_name() { + hci_event_flag &= ~HCI_FLAG_REMOTE_NAME_COMPLETE; + hcibuf[0] = 0x19; // HCI OCF = 19 + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x0A; // parameter length = 10 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + hcibuf[9] = 0x01; //Page Scan Repetition Mode + hcibuf[10] = 0x00; //Reserved + hcibuf[11] = 0x00; //Clock offset - low byte + hcibuf[12] = 0x00; //Clock offset - high byte + + HCI_Command(hcibuf, 13); +} + +void BTD::hci_set_local_name(const char* name) { + hcibuf[0] = 0x13; // HCI OCF = 13 + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte uint8_t i; - for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16 - hcibuf[i+10] = btdPin[i]; - for(;i < 16; i++) - hcibuf[i+10] = 0x00; // The rest should be 0 - } - - HCI_Command(hcibuf, 26); + for (i = 0; i < strlen(name); i++) + hcibuf[i + 3] = name[i]; + hcibuf[i + 3] = 0x00; // End of string + + HCI_Command(hcibuf, 4 + strlen(name)); } + +void BTD::hci_inquiry() { + hci_event_flag &= ~HCI_FLAG_WII_FOUND; + hcibuf[0] = 0x01; + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x05; // Parameter Total Length = 5 + hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm + hcibuf[4] = 0x8B; + hcibuf[5] = 0x9E; + hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum) + hcibuf[7] = 0x0A; // 10 number of responses + + HCI_Command(hcibuf, 8); +} + +void BTD::hci_inquiry_cancel() { + hcibuf[0] = 0x02; + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x0; // Parameter Total Length = 0 + + HCI_Command(hcibuf, 3); +} + +void BTD::hci_connect() { + hci_event_flag &= ~(HCI_FLAG_CONN_COMPLETE | HCI_FLAG_CONNECT_EVENT); + hcibuf[0] = 0x05; + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x0D; // parameter Total Length = 13 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + hcibuf[9] = 0x18; // DM1 or DH1 may be used + hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used + hcibuf[11] = 0x01; // Page repetition mode R1 + hcibuf[12] = 0x00; // Reserved + hcibuf[13] = 0x00; // Clock offset + hcibuf[14] = 0x00; // Invalid clock offset + hcibuf[15] = 0x00; // Do not allow role switch + + HCI_Command(hcibuf, 16); +} + +void BTD::hci_pin_code_request_reply() { + hcibuf[0] = 0x0D; // HCI OCF = 0D + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x17; // parameter length 23 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + if (pairWithWii && !wiiUProController) { + hcibuf[9] = 6; // Pin length is the length of the bt address + hcibuf[10] = disc_bdaddr[0]; // The pin is the Wiimotes bt address backwards + hcibuf[11] = disc_bdaddr[1]; + hcibuf[12] = disc_bdaddr[2]; + hcibuf[13] = disc_bdaddr[3]; + hcibuf[14] = disc_bdaddr[4]; + hcibuf[15] = disc_bdaddr[5]; + for (uint8_t i = 16; i < 26; i++) + hcibuf[i] = 0x00; // The rest should be 0 + } else if (pairWithWii && wiiUProController) { +#ifdef DEBUG + Notify(PSTR("\r\nParing with Wii U Pro Controller"), 0x80); +#endif + hcibuf[9] = 6; // Pin length is the length of the bt address + hcibuf[10] = my_bdaddr[0]; // The pin is the Bluetooth dongles bt address backwards + hcibuf[11] = my_bdaddr[1]; + hcibuf[12] = my_bdaddr[2]; + hcibuf[13] = my_bdaddr[3]; + hcibuf[14] = my_bdaddr[4]; + hcibuf[15] = my_bdaddr[5]; + for (uint8_t i = 16; i < 26; i++) + hcibuf[i] = 0x00; // The rest should be 0 + } else { + hcibuf[9] = strlen(btdPin); // Length of pin + uint8_t i; + for (i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16 + hcibuf[i + 10] = btdPin[i]; + for (; i < 16; i++) + hcibuf[i + 10] = 0x00; // The rest should be 0 + } + + HCI_Command(hcibuf, 26); +} + void BTD::hci_pin_code_negative_request_reply() { - hcibuf[0] = 0x0E; // HCI OCF = 0E - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x06; // parameter length 6 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - - HCI_Command(hcibuf, 9); + hcibuf[0] = 0x0E; // HCI OCF = 0E + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x06; // parameter length 6 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + + HCI_Command(hcibuf, 9); } + void BTD::hci_link_key_request_negative_reply() { - hcibuf[0] = 0x0C; // HCI OCF = 0C - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x06; // parameter length 6 - hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr - hcibuf[4] = disc_bdaddr[1]; - hcibuf[5] = disc_bdaddr[2]; - hcibuf[6] = disc_bdaddr[3]; - hcibuf[7] = disc_bdaddr[4]; - hcibuf[8] = disc_bdaddr[5]; - - HCI_Command(hcibuf, 9); + hcibuf[0] = 0x0C; // HCI OCF = 0C + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x06; // parameter length 6 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + + HCI_Command(hcibuf, 9); } + void BTD::hci_authentication_request() { - hcibuf[0] = 0x11; // HCI OCF = 11 - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x02; // parameter length = 2 - hcibuf[3] = (uint8_t)(hci_handle & 0xFF);//connection handle - low byte - hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F);//connection handle - high byte - - HCI_Command(hcibuf, 5); + hcibuf[0] = 0x11; // HCI OCF = 11 + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x02; // parameter length = 2 + hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte + + HCI_Command(hcibuf, 5); } + void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services - hci_event_flag &= ~HCI_FLAG_DISCONN_COMPLETE; - hcibuf[0] = 0x06; // HCI OCF = 6 - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x03; // parameter length = 3 - hcibuf[3] = (uint8_t)(handle & 0xFF);//connection handle - low byte - hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F);//connection handle - high byte - hcibuf[5] = 0x13; // reason - - HCI_Command(hcibuf, 6); + hci_event_flag &= ~HCI_FLAG_DISCONN_COMPLETE; + hcibuf[0] = 0x06; // HCI OCF = 6 + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x03; // parameter length = 3 + hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte + hcibuf[5] = 0x13; // reason + + HCI_Command(hcibuf, 6); } + void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html - hcibuf[0] = 0x24; // HCI OCF = 3 - hcibuf[1] = 0x03 << 2; // HCI OGF = 3 - hcibuf[2] = 0x03; // parameter length = 3 - hcibuf[3] = 0x04; // Robot - hcibuf[4] = 0x08; // Toy - hcibuf[5] = 0x00; - HCI_Command(hcibuf, 6); + hcibuf[0] = 0x24; // HCI OCF = 3 + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 0x03; // parameter length = 3 + hcibuf[3] = 0x04; // Robot + hcibuf[4] = 0x08; // Toy + hcibuf[5] = 0x00; + HCI_Command(hcibuf, 6); } /******************************************************************* * * @@ -1029,174 +1043,183 @@ void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru */ /************************************************************/ /* L2CAP Commands */ + /************************************************************/ void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) { - uint8_t buf[8+nbytes]; - buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag - buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20); - buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length - buf[3] = (uint8_t)((4 + nbytes) >> 8); - buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length - buf[5] = (uint8_t)(nbytes >> 8); - buf[6] = channelLow; - buf[7] = channelHigh; - - for (uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame - buf[8 + i] = data[i]; - - 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 + uint8_t buf[8 + nbytes]; + buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag + buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20); + buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length + buf[3] = (uint8_t)((4 + nbytes) >> 8); + buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length + buf[5] = (uint8_t)(nbytes >> 8); + buf[6] = channelLow; + buf[7] = channelHigh; + + for (uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame + buf[8 + i] = data[i]; + + 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 - Notify(PSTR("\r\nError sending L2CAP message: 0x")); - PrintHex(rcode); - Notify(PSTR(" - Channel ID: ")); - Serial.print(channelHigh); - Notify(PSTR(" ")); - Serial.print(channelLow); -#endif - } + Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80); + PrintHex (rcode, 0x80); + Notify(PSTR(" - Channel ID: "), 0x80); + Serial.print(channelHigh); + Notify(PSTR(" "), 0x80); + Serial.print(channelLow); +#endif + } } + void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) { - l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x04; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM - l2capoutbuf[5] = (uint8_t)(psm >> 8); - l2capoutbuf[6] = scid[0]; // Source CID - l2capoutbuf[7] = scid[1]; - - L2CAP_Command(handle, l2capoutbuf, 8); + l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x04; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM + l2capoutbuf[5] = (uint8_t)(psm >> 8); + l2capoutbuf[6] = scid[0]; // Source CID + l2capoutbuf[7] = scid[1]; + + L2CAP_Command(handle, l2capoutbuf, 8); } -void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) { - l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x08; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = dcid[0]; // Destination CID - l2capoutbuf[5] = dcid[1]; - l2capoutbuf[6] = scid[0]; // Source CID - l2capoutbuf[7] = scid[1]; - l2capoutbuf[8] = result; // Result: Pending or Success - l2capoutbuf[9] = 0x00; - l2capoutbuf[10] = 0x00; // No further information - l2capoutbuf[11] = 0x00; - - L2CAP_Command(handle, l2capoutbuf, 12); -} + +void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) { + l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x08; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = dcid[0]; // Destination CID + l2capoutbuf[5] = dcid[1]; + l2capoutbuf[6] = scid[0]; // Source CID + l2capoutbuf[7] = scid[1]; + l2capoutbuf[8] = result; // Result: Pending or Success + l2capoutbuf[9] = 0x00; + l2capoutbuf[10] = 0x00; // No further information + l2capoutbuf[11] = 0x00; + + L2CAP_Command(handle, l2capoutbuf, 12); +} + void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) { - l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x08; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = dcid[0]; // Destination CID - l2capoutbuf[5] = dcid[1]; - l2capoutbuf[6] = 0x00; // Flags - l2capoutbuf[7] = 0x00; - l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint - l2capoutbuf[9] = 0x02; // Config Opt: length - l2capoutbuf[10] = 0xFF; // MTU - l2capoutbuf[11] = 0xFF; - - L2CAP_Command(handle, l2capoutbuf, 12); + l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x08; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = dcid[0]; // Destination CID + l2capoutbuf[5] = dcid[1]; + l2capoutbuf[6] = 0x00; // Flags + l2capoutbuf[7] = 0x00; + l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint + l2capoutbuf[9] = 0x02; // Config Opt: length + l2capoutbuf[10] = 0xFF; // MTU + l2capoutbuf[11] = 0xFF; + + L2CAP_Command(handle, l2capoutbuf, 12); } -void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) { - l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x0A; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = scid[0]; // Source CID - l2capoutbuf[5] = scid[1]; - l2capoutbuf[6] = 0x00; // Flag - l2capoutbuf[7] = 0x00; - l2capoutbuf[8] = 0x00; // Result - l2capoutbuf[9] = 0x00; - l2capoutbuf[10] = 0x01; // Config - l2capoutbuf[11] = 0x02; - l2capoutbuf[12] = 0xA0; - l2capoutbuf[13] = 0x02; - - L2CAP_Command(handle, l2capoutbuf, 14); + +void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) { + l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x0A; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = scid[0]; // Source CID + l2capoutbuf[5] = scid[1]; + l2capoutbuf[6] = 0x00; // Flag + l2capoutbuf[7] = 0x00; + l2capoutbuf[8] = 0x00; // Result + l2capoutbuf[9] = 0x00; + l2capoutbuf[10] = 0x01; // Config + l2capoutbuf[11] = 0x02; + l2capoutbuf[12] = 0xA0; + l2capoutbuf[13] = 0x02; + + L2CAP_Command(handle, l2capoutbuf, 14); } + void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) { - l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x04; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = dcid[0]; - l2capoutbuf[5] = dcid[1]; - l2capoutbuf[6] = scid[0]; - l2capoutbuf[7] = scid[1]; - L2CAP_Command(handle, l2capoutbuf, 8); + l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x04; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = dcid[0]; + l2capoutbuf[5] = dcid[1]; + l2capoutbuf[6] = scid[0]; + l2capoutbuf[7] = scid[1]; + L2CAP_Command(handle, l2capoutbuf, 8); } + void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) { - l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x04; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = dcid[0]; - l2capoutbuf[5] = dcid[1]; - l2capoutbuf[6] = scid[0]; - l2capoutbuf[7] = scid[1]; - L2CAP_Command(handle, l2capoutbuf, 8); + l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x04; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = dcid[0]; + l2capoutbuf[5] = dcid[1]; + l2capoutbuf[6] = scid[0]; + l2capoutbuf[7] = scid[1]; + L2CAP_Command(handle, l2capoutbuf, 8); } + void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) { - l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code - l2capoutbuf[1] = rxid; // Identifier - l2capoutbuf[2] = 0x08; // Length - l2capoutbuf[3] = 0x00; - l2capoutbuf[4] = infoTypeLow; - l2capoutbuf[5] = infoTypeHigh; - l2capoutbuf[6] = 0x00; // Result = success - l2capoutbuf[7] = 0x00; // Result = success - l2capoutbuf[8] = 0x00; - l2capoutbuf[9] = 0x00; - l2capoutbuf[10] = 0x00; - l2capoutbuf[11] = 0x00; - L2CAP_Command(handle, l2capoutbuf, 12); + l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code + l2capoutbuf[1] = rxid; // Identifier + l2capoutbuf[2] = 0x08; // Length + l2capoutbuf[3] = 0x00; + l2capoutbuf[4] = infoTypeLow; + l2capoutbuf[5] = infoTypeHigh; + l2capoutbuf[6] = 0x00; // Result = success + l2capoutbuf[7] = 0x00; // Result = success + l2capoutbuf[8] = 0x00; + l2capoutbuf[9] = 0x00; + l2capoutbuf[10] = 0x00; + l2capoutbuf[11] = 0x00; + L2CAP_Command(handle, l2capoutbuf, 12); } /* PS3 Commands - only set Bluetooth address is implemented */ void BTD::setBdaddr(uint8_t* BDADDR) { - /* Set the internal bluetooth address */ - uint8_t buf[8]; - buf[0] = 0x01; - buf[1] = 0x00; - for (uint8_t i = 0; i < 6; i++) - buf[i+2] = BDADDR[5 - i];//Copy into buffer, has to be written reversed - - //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) - pUsb->ctrlReq(bAddress,epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); + /* Set the internal bluetooth address */ + uint8_t buf[8]; + buf[0] = 0x01; + buf[1] = 0x00; + for (uint8_t i = 0; i < 6; i++) + buf[i + 2] = BDADDR[5 - i]; //Copy into buffer, has to be written reversed + + //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) + pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); #ifdef DEBUG - Notify(PSTR("\r\nBluetooth Address was set to: ")); - for(int8_t i = 5; i > 0; i--) { - PrintHex(my_bdaddr[i]); - Notify(PSTR(":")); - } - PrintHex(my_bdaddr[0]); + Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (my_bdaddr[i], 0x80); + Notify(PSTR(":"), 0x80); + } + PrintHex (my_bdaddr[0], 0x80); #endif } + void BTD::setMoveBdaddr(uint8_t* BDADDR) { - /* Set the internal bluetooth address */ - uint8_t buf[11]; - buf[0] = 0x05; - buf[7] = 0x10; - buf[8] = 0x01; - buf[9] = 0x02; - buf[10] = 0x12; - - for (uint8_t i = 0; i < 6; i++) - buf[i + 1] = BDADDR[i]; - - //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[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL); + /* Set the internal bluetooth address */ + uint8_t buf[11]; + buf[0] = 0x05; + buf[7] = 0x10; + buf[8] = 0x01; + buf[9] = 0x02; + buf[10] = 0x12; + + for (uint8_t i = 0; i < 6; i++) + buf[i + 1] = BDADDR[i]; + + //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[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL); #ifdef DEBUG - Notify(PSTR("\r\nBluetooth Address was set to: ")); - for(int8_t i = 5; i > 0; i--) { - PrintHex(my_bdaddr[i]); - Notify(PSTR(":")); - } - PrintHex(my_bdaddr[0]); + Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (my_bdaddr[i], 0x80); + Notify(PSTR(":"), 0x80); + } + PrintHex (my_bdaddr[0], 0x80); #endif } \ No newline at end of file diff --git a/BTD.h b/BTD.h index 238b8959..c314e6cd 100755 --- a/BTD.h +++ b/BTD.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -134,17 +134,17 @@ /** All Bluetooth services should include this class. */ class BluetoothService { public: - /** - * Used to pass acldata to the Bluetooth service. - * @param ACLData Pointer to the incoming acldata. - */ - virtual void ACLData(uint8_t* ACLData); - /** Used to run the different state machines in the Bluetooth service. */ - virtual void Run(); - /** Used to reset the Bluetooth service. */ - virtual void Reset(); - /** Used to disconnect both the L2CAP Channel and the HCI Connection for the Bluetooth service. */ - virtual void disconnect(); + /** + * Used to pass acldata to the Bluetooth service. + * @param ACLData Pointer to the incoming acldata. + */ + virtual void ACLData(uint8_t* ACLData); + /** Used to run the different state machines in the Bluetooth service. */ + virtual void Run(); + /** Used to reset the Bluetooth service. */ + virtual void Reset(); + /** Used to disconnect both the L2CAP Channel and the HCI Connection for the Bluetooth service. */ + virtual void disconnect(); }; /** @@ -153,299 +153,312 @@ public: */ class BTD : public USBDeviceConfig, public UsbConfigXtracter { public: - /** - * Constructor for the BTD class. - * @param p Pointer to USB class instance. - */ - BTD(USB *p); - - /** @name USBDeviceConfig implementation */ - /** - * Initialize the Bluetooth dongle. - * @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 dongle has been initialized. - * @return True if it's ready. - */ - virtual bool isReady() { return bPollEnable; }; - /**@}*/ - - /** @name UsbConfigXtracter implementation */ - /** - * UsbConfigXtracter implementation, used to extract endpoint information. - * @param conf Configuration value. - * @param iface Interface number. - * @param alt Alternate setting. - * @param proto Interface Protocol. - * @param ep Endpoint Descriptor. - */ - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); - /**@}*/ + /** + * Constructor for the BTD class. + * @param p Pointer to USB class instance. + */ + BTD(USB *p); - /** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */ - void disconnect() { - for (uint8_t i=0; idisconnect(); - }; - /** - * Register bluetooth dongle members/services. - * @param pService Pointer to BluetoothService class instance. - * @return The serice ID on succes or -1 on fail. - */ - int8_t registerServiceClass(BluetoothService *pService) { - for (uint8_t i=0; idisconnect(); + }; + + /** + * Register bluetooth dongle members/services. + * @param pService Pointer to BluetoothService class instance. + * @return The serice ID on succes or -1 on fail. + */ + int8_t registerServiceClass(BluetoothService *pService) { + for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) { + if(!btService[i]) { + btService[i] = pService; + return i; // Return ID + } + } + return -1; // ErrorregisterServiceClass + }; + + /** @name HCI Commands */ + /** + * Used to send a HCI Command. + * @param data Data to send. + * @param nbytes Number of bytes to send. + */ + void HCI_Command(uint8_t* data, uint16_t nbytes); + /** Reset the Bluetooth dongle. */ + void hci_reset(); + /** Read the Bluetooth address of the dongle. */ + void hci_read_bdaddr(); + /** Read the HCI Version of the Bluetooth dongle. */ + void hci_read_local_version_information(); + /** + * Set the local name of the Bluetooth dongle. + * @param name Desired name. + */ + void hci_set_local_name(const char* name); + /** Enable visibility to other Bluetooth devices. */ + void hci_write_scan_enable(); + /** Disable visibility to other Bluetooth devices. */ + void hci_write_scan_disable(); + /** Read the remote devices name. */ + void hci_remote_name(); + /** Accept the connection with the Bluetooth device. */ + void hci_accept_connection(); + /** + * Disconnect the HCI connection. + * @param handle The HCI Handle for the connection. + */ + void hci_disconnect(uint16_t handle); + /** + * Respond with the pin for the connection. + * The pin is automatically set for the Wii library, + * but can be customized for the SPP library. + */ + void hci_pin_code_request_reply(); + /** Respons when no pin was set. */ + void hci_pin_code_negative_request_reply(); + /** + * Command is used to reply to a Link Key Request event from the BR/EDR Controller + * if the Host does not have a stored Link Key for the connection. + */ + void hci_link_key_request_negative_reply(); + /** Used to try to authenticate with the remote device. */ + void hci_authentication_request(); + /** Start a HCI inquiry. */ + void hci_inquiry(); + /** Cancel a HCI inquiry. */ + void hci_inquiry_cancel(); + /** Connect to a device. */ + void hci_connect(); + /** Used to a set the class of the device. */ + void hci_write_class_of_device(); + /**@}*/ + + /** @name L2CAP Commands */ + /** + * Used to send L2CAP Commands. + * @param handle HCI Handle. + * @param data Data to send. + * @param nbytes Number of bytes to send. + * @param channelLow,channelHigh Low and high byte of channel to send to. + * If argument is omitted then the Standard L2CAP header: Channel ID (0x01) for ACL-U will be used. + */ + void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00); + /** + * L2CAP Connection Request. + * @param handle HCI handle. + * @param rxid Identifier. + * @param scid Source Channel Identifier. + * @param psm Protocol/Service Multiplexer - see: https://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm. + */ + void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm); + /** + * L2CAP Connection Response. + * @param handle HCI handle. + * @param rxid Identifier. + * @param dcid Destination Channel Identifier. + * @param scid Source Channel Identifier. + * @param result Result - First send ::PENDING and then ::SUCCESSFUL. + */ + void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result); + /** + * L2CAP Config Request. + * @param handle HCI Handle. + * @param rxid Identifier. + * @param dcid Destination Channel Identifier. + */ + void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid); + /** + * L2CAP Config Response. + * @param handle HCI Handle. + * @param rxid Identifier. + * @param scid Source Channel Identifier. + */ + void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid); + /** + * L2CAP Disconnection Request. + * @param handle HCI Handle. + * @param rxid Identifier. + * @param dcid Device Channel Identifier. + * @param scid Source Channel Identifier. + */ + void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid); + /** + * L2CAP Disconnection Response. + * @param handle HCI Handle. + * @param rxid Identifier. + * @param dcid Device Channel Identifier. + * @param scid Source Channel Identifier. + */ + void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid); + /** + * L2CAP Information Response. + * @param handle HCI Handle. + * @param rxid Identifier. + * @param infoTypeLow,infoTypeHigh Infotype. + */ + void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh); + /**@}*/ + + /** Use this to see if it is waiting for a incoming connection. */ + bool watingForConnection; + /** This is used by the service to know when to store the device information. */ + bool l2capConnectionClaimed; + /** This is used by the SPP library to claim the current SDP incoming request. */ + bool sdpConnectionClaimed; + /** This is used by the SPP library to claim the current RFCOMM incoming request. */ + bool rfcommConnectionClaimed; + + /** The name you wish to make the dongle show up as. It is set automatically by the SPP library. */ + const char* btdName; + /** The pin you wish to make the dongle use for authentication. It is set automatically by the SPP library. */ + const char* btdPin; + + /** The bluetooth dongles Bluetooth address. */ + uint8_t my_bdaddr[6]; + /** HCI handle for the last connection. */ + uint16_t hci_handle; + /** Last incoming devices Bluetooth address. */ + uint8_t disc_bdaddr[6]; + /** First 30 chars of last remote name. */ + uint8_t remote_name[30]; + /** + * The supported HCI Version read from the Bluetooth dongle. + * Used by the PS3BT library to check the HCI Version of the Bluetooth dongle, + * it should be at least 3 to work properly with the library. + */ + uint8_t hci_version; + + /** Call this function to pair with a Wiimote */ + void pairWithWiimote() { + pairWithWii = true; + hci_state = HCI_CHECK_WII_SERVICE; + }; + /** Used to only send the ACL data to the wiimote. */ + bool connectToWii; + /** True if a Wiimote is connecting. */ + bool incomingWii; + /** True when it should pair with the incoming Wiimote. */ + bool pairWithWii; + /** True if it's the new Wiimote with the Motion Plus Inside or a Wii U Pro Controller. */ + bool motionPlusInside; + /** True if it's a Wii U Pro Controller. */ + bool wiiUProController; + + /** + * Read the poll interval taken from the endpoint descriptors. + * @return The poll interval in ms. + */ + uint8_t readPollInterval() { + return pollInterval; + }; - /** - * Read the poll interval taken from the endpoint descriptors. - * @return The poll interval in ms. - */ - uint8_t readPollInterval() { return pollInterval; }; - protected: - /** Pointer to USB class instance. */ - USB *pUsb; - /** Device address. */ - uint8_t bAddress; - /** Endpoint info structure. */ - EpInfo epInfo[BTD_MAX_ENDPOINTS]; - - /** Configuration number. */ - uint8_t bConfNum; - /** Total number of endpoints in the configuration. */ - uint8_t bNumEP; - /** Next poll time based on poll interval taken from the USB descriptor. */ - uint32_t qNextPollTime; - - /** Bluetooth dongle control endpoint. */ - static const uint8_t BTD_CONTROL_PIPE; - /** HCI event endpoint index. */ - static const uint8_t BTD_EVENT_PIPE; - /** ACL In endpoint index. */ - static const uint8_t BTD_DATAIN_PIPE; - /** ACL Out endpoint index. */ - static const uint8_t BTD_DATAOUT_PIPE; - - /** - * Used to print the USB Endpoint Descriptor. - * @param ep_ptr Pointer to USB Endpoint Descriptor. - */ - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[BTD_MAX_ENDPOINTS]; + + /** Configuration number. */ + uint8_t bConfNum; + /** Total number of endpoints in the configuration. */ + uint8_t bNumEP; + /** Next poll time based on poll interval taken from the USB descriptor. */ + uint32_t qNextPollTime; + + /** Bluetooth dongle control endpoint. */ + static const uint8_t BTD_CONTROL_PIPE; + /** HCI event endpoint index. */ + static const uint8_t BTD_EVENT_PIPE; + /** ACL In endpoint index. */ + static const uint8_t BTD_DATAIN_PIPE; + /** ACL Out endpoint index. */ + static const uint8_t BTD_DATAOUT_PIPE; + + /** + * Used to print the USB Endpoint Descriptor. + * @param ep_ptr Pointer to USB Endpoint Descriptor. + */ + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + private: - BluetoothService* btService[BTD_NUMSERVICES]; - - bool bPollEnable; - uint8_t pollInterval; - - /* Variables used by high level HCI task */ - uint8_t hci_state; //current state of bluetooth hci connection - uint16_t hci_counter; // counter used for bluetooth hci reset loops - uint8_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset - uint16_t hci_event_flag; // hci flags of received bluetooth events - uint8_t inquiry_counter; - - 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 - - /* State machines */ - void HCI_event_task(); // Poll the HCI event pipe - void HCI_task(); // HCI state machine - void ACL_event_task(); // ACL input pipe - - /* Used to set the Bluetooth Address internally to the PS3 Controllers */ - void setBdaddr(uint8_t* BDADDR); - void setMoveBdaddr(uint8_t* BDADDR); + BluetoothService* btService[BTD_NUMSERVICES]; + + bool bPollEnable; + uint8_t pollInterval; + + /* Variables used by high level HCI task */ + uint8_t hci_state; //current state of bluetooth hci connection + uint16_t hci_counter; // counter used for bluetooth hci reset loops + uint8_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset + uint16_t hci_event_flag; // hci flags of received bluetooth events + uint8_t inquiry_counter; + + 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 + + /* State machines */ + void HCI_event_task(); // Poll the HCI event pipe + void HCI_task(); // HCI state machine + void ACL_event_task(); // ACL input pipe + + /* Used to set the Bluetooth Address internally to the PS3 Controllers */ + void setBdaddr(uint8_t* BDADDR); + void setMoveBdaddr(uint8_t* BDADDR); }; #endif diff --git a/PS3BT.cpp b/PS3BT.cpp index cf35a7f4..088325b4 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -21,540 +21,542 @@ //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers const uint8_t OUTPUT_REPORT_BUFFER[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0): +PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) : pBtd(p) // pointer to USB class instance - mandatory { - if (pBtd) - pBtd->registerServiceClass(this); // Register it as a Bluetooth service - - pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead - pBtd->my_bdaddr[4] = btadr4; - pBtd->my_bdaddr[3] = btadr3; - pBtd->my_bdaddr[2] = btadr2; - pBtd->my_bdaddr[1] = btadr1; - pBtd->my_bdaddr[0] = btadr0; - - HIDBuffer[0] = 0x52;// HID BT Set_report (0x50) | Report Type (Output 0x02) - HIDBuffer[1] = 0x01;// Report ID - - //Needed for PS3 Move Controller commands to work via bluetooth - HIDMoveBuffer[0] = 0xA2;// HID BT DATA_request (0xA0) | Report Type (Output 0x02) - HIDMoveBuffer[1] = 0x02;// Report ID - - /* Set device cid for the control and intterrupt channelse - LSB */ - control_dcid[0] = 0x40;//0x0040 - control_dcid[1] = 0x00; - interrupt_dcid[0] = 0x41;//0x0041 - interrupt_dcid[1] = 0x00; - - Reset(); + if (pBtd) + pBtd->registerServiceClass(this); // Register it as a Bluetooth service + + pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead + pBtd->my_bdaddr[4] = btadr4; + pBtd->my_bdaddr[3] = btadr3; + pBtd->my_bdaddr[2] = btadr2; + pBtd->my_bdaddr[1] = btadr1; + pBtd->my_bdaddr[0] = btadr0; + + HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02) + HIDBuffer[1] = 0x01; // Report ID + + //Needed for PS3 Move Controller commands to work via bluetooth + HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + HIDMoveBuffer[1] = 0x02; // Report ID + + /* Set device cid for the control and intterrupt channelse - LSB */ + control_dcid[0] = 0x40; //0x0040 + control_dcid[1] = 0x00; + interrupt_dcid[0] = 0x41; //0x0041 + interrupt_dcid[1] = 0x00; + + Reset(); } + bool PS3BT::getButtonPress(Button b) { - return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); + return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); } + bool PS3BT::getButtonClick(Button b) { - uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]); - bool click = (ButtonClickState & button); - ButtonClickState &= ~button; // clear "click" event - return click; + uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; } + uint8_t PS3BT::getAnalogButton(Button a) { - if (l2capinbuf == NULL) - return 0; - return (uint8_t)(l2capinbuf[pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])]); + if (l2capinbuf == NULL) + return 0; + return (uint8_t)(l2capinbuf[pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])]); } + uint8_t PS3BT::getAnalogHat(AnalogHat a) { - if (l2capinbuf == NULL) - return 0; - return (uint8_t)(l2capinbuf[(uint8_t)a+15]); + if (l2capinbuf == NULL) + return 0; + return (uint8_t)(l2capinbuf[(uint8_t)a + 15]); } + int16_t PS3BT::getSensor(Sensor a) { - if (l2capinbuf == NULL) - return 0; - if(PS3Connected) { - if (a == aX || a == aY || a == aZ || a == gZ) - return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]); - else - return 0; - } else if(PS3MoveConnected) { - if (a == mXmove || a == mYmove) // These are all 12-bits long - return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1])); - else if (a == mZmove || a == tempMove) // The tempearature is also 12 bits long - return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4)); - else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove - return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8)); - } else - return 0; + if (l2capinbuf == NULL) + return 0; + if (PS3Connected) { + if (a == aX || a == aY || a == aZ || a == gZ) + return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]); + else + return 0; + } else if (PS3MoveConnected) { + if (a == mXmove || a == mYmove) // These are all 12-bits long + return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1])); + else if (a == mZmove || a == tempMove) // The tempearature is also 12 bits long + return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4)); + else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove + return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8)); + } else + return 0; } + double PS3BT::getAngle(Angle a) { - double accXval; - double accYval; - double accZval; - - if(PS3Connected) { - // Data for the Kionix KXPC4 used in the DualShock 3 - const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) - accXval = -((double)getSensor(aX)-zeroG); - accYval = -((double)getSensor(aY)-zeroG); - accZval = -((double)getSensor(aZ)-zeroG); - } else if(PS3MoveConnected) { - // It's a Kionix KXSC4 inside the Motion controller - const uint16_t zeroG = 0x8000; - accXval = -(int16_t)(getSensor(aXmove)-zeroG); - accYval = (int16_t)(getSensor(aYmove)-zeroG); - accZval = (int16_t)(getSensor(aZmove)-zeroG); - } - - // Convert to 360 degrees resolution - // atan2 outputs the value of -π to π (radians) - // We are then converting it to 0 to 2π and then to degrees - if (a == Pitch) { - double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG; - return angle; - } else { - double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG; - return angle; - } + double accXval; + double accYval; + double accZval; + + if (PS3Connected) { + // Data for the Kionix KXPC4 used in the DualShock 3 + const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) + accXval = -((double)getSensor(aX) - zeroG); + accYval = -((double)getSensor(aY) - zeroG); + accZval = -((double)getSensor(aZ) - zeroG); + } else if (PS3MoveConnected) { + // It's a Kionix KXSC4 inside the Motion controller + const uint16_t zeroG = 0x8000; + accXval = -(int16_t)(getSensor(aXmove) - zeroG); + accYval = (int16_t)(getSensor(aYmove) - zeroG); + accZval = (int16_t)(getSensor(aZmove) - zeroG); + } + + // Convert to 360 degrees resolution + // atan2 outputs the value of -π to π (radians) + // We are then converting it to 0 to 2π and then to degrees + if (a == Pitch) { + double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG; + return angle; + } else { + double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG; + return angle; + } } + double PS3BT::get9DOFValues(Sensor a) { // Thanks to Manfred Piendl - if(!PS3MoveConnected) - return 0; - int16_t value = getSensor(a); - if (a == mXmove || a == mYmove || a == mZmove) { - if (value > 2047) - value -= 0x1000; - return (double)value/3.2; // unit: muT = 10^(-6) Tesla - } else if (a == aXmove || a == aYmove || a == aZmove) { - if (value < 0) - value += 0x8000; - else - value -= 0x8000; - return (double)value/442.0; // unit: m/(s^2) - } else if (a == gXmove || a == gYmove || a == gZmove) { - if (value < 0) - value += 0x8000; - else - value -= 0x8000; - if (a == gXmove) - return (double)value/11.6; // unit: deg/s - else if (a == gYmove) - return (double)value/11.2; // unit: deg/s - else // gZmove - return (double)value/9.6; // unit: deg/s - } else - return 0; + if (!PS3MoveConnected) + return 0; + int16_t value = getSensor(a); + if (a == mXmove || a == mYmove || a == mZmove) { + if (value > 2047) + value -= 0x1000; + return (double)value / 3.2; // unit: muT = 10^(-6) Tesla + } else if (a == aXmove || a == aYmove || a == aZmove) { + if (value < 0) + value += 0x8000; + else + value -= 0x8000; + return (double)value / 442.0; // unit: m/(s^2) + } else if (a == gXmove || a == gYmove || a == gZmove) { + if (value < 0) + value += 0x8000; + else + value -= 0x8000; + if (a == gXmove) + return (double)value / 11.6; // unit: deg/s + else if (a == gYmove) + return (double)value / 11.2; // unit: deg/s + else // gZmove + return (double)value / 9.6; // unit: deg/s + } else + return 0; } + String PS3BT::getTemperature() { - if(PS3MoveConnected) { - int16_t input = getSensor(tempMove); - - String output = String(input/100); - output += "."; - if(input%100 < 10) - output += "0"; - output += String(input%100); - - return output; - } + if (PS3MoveConnected) { + int16_t input = getSensor(tempMove); + + String output = String(input / 100); + output += "."; + if (input % 100 < 10) + output += "0"; + output += String(input % 100); + + return output; + } } + bool PS3BT::getStatus(Status c) { - if (l2capinbuf == NULL) + if (l2capinbuf == NULL) + return false; + if (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff)) + return true; return false; - if (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff)) - return true; - return false; } + String PS3BT::getStatusString() { - if (PS3Connected || PS3NavigationConnected) { - char statusOutput[100]; - - strcpy(statusOutput,"ConnectionStatus: "); - - if (getStatus(Plugged)) strcat(statusOutput,"Plugged"); - else if (getStatus(Unplugged)) strcat(statusOutput,"Unplugged"); - else strcat(statusOutput,"Error"); - - - strcat(statusOutput," - PowerRating: "); - if (getStatus(Charging)) strcat(statusOutput,"Charging"); - else if (getStatus(NotCharging)) strcat(statusOutput,"Not Charging"); - else if (getStatus(Shutdown)) strcat(statusOutput,"Shutdown"); - else if (getStatus(Dying)) strcat(statusOutput,"Dying"); - else if (getStatus(Low)) strcat(statusOutput,"Low"); - else if (getStatus(High)) strcat(statusOutput,"High"); - else if (getStatus(Full)) strcat(statusOutput,"Full"); - else strcat(statusOutput,"Error"); - - strcat(statusOutput," - WirelessStatus: "); - - if (getStatus(CableRumble)) strcat(statusOutput,"Cable - Rumble is on"); - else if (getStatus(Cable)) strcat(statusOutput,"Cable - Rumble is off"); - else if (getStatus(BluetoothRumble)) strcat(statusOutput,"Bluetooth - Rumble is on"); - else if (getStatus(Bluetooth)) strcat(statusOutput,"Bluetooth - Rumble is off"); - else strcat(statusOutput,"Error"); - - return statusOutput; - - } - else if(PS3MoveConnected) { - char statusOutput[50]; - - strcpy(statusOutput,"PowerRating: "); - - if (getStatus(MoveCharging)) strcat(statusOutput,"Charging"); - else if (getStatus(MoveNotCharging)) strcat(statusOutput,"Not Charging"); - else if (getStatus(MoveShutdown)) strcat(statusOutput,"Shutdown"); - else if (getStatus(MoveDying)) strcat(statusOutput,"Dying"); - else if (getStatus(MoveLow)) strcat(statusOutput,"Low"); - else if (getStatus(MoveHigh)) strcat(statusOutput,"High"); - else if (getStatus(MoveFull)) strcat(statusOutput,"Full"); - else strcat(statusOutput,"Error"); - - return statusOutput; - } + if (PS3Connected || PS3NavigationConnected) { + char statusOutput[100]; + + strcpy(statusOutput, "ConnectionStatus: "); + + if (getStatus(Plugged)) strcat(statusOutput, "Plugged"); + else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged"); + else strcat(statusOutput, "Error"); + + + strcat(statusOutput, " - PowerRating: "); + if (getStatus(Charging)) strcat(statusOutput, "Charging"); + else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging"); + else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown"); + else if (getStatus(Dying)) strcat(statusOutput, "Dying"); + else if (getStatus(Low)) strcat(statusOutput, "Low"); + else if (getStatus(High)) strcat(statusOutput, "High"); + else if (getStatus(Full)) strcat(statusOutput, "Full"); + else strcat(statusOutput, "Error"); + + strcat(statusOutput, " - WirelessStatus: "); + + if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on"); + else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off"); + else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on"); + else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off"); + else strcat(statusOutput, "Error"); + + return statusOutput; + + } else if (PS3MoveConnected) { + char statusOutput[50]; + + strcpy(statusOutput, "PowerRating: "); + + if (getStatus(MoveCharging)) strcat(statusOutput, "Charging"); + else if (getStatus(MoveNotCharging)) strcat(statusOutput, "Not Charging"); + else if (getStatus(MoveShutdown)) strcat(statusOutput, "Shutdown"); + else if (getStatus(MoveDying)) strcat(statusOutput, "Dying"); + else if (getStatus(MoveLow)) strcat(statusOutput, "Low"); + else if (getStatus(MoveHigh)) strcat(statusOutput, "High"); + else if (getStatus(MoveFull)) strcat(statusOutput, "Full"); + else strcat(statusOutput, "Error"); + + return statusOutput; + } } + void PS3BT::Reset() { - PS3Connected = false; - PS3MoveConnected = false; - PS3NavigationConnected = false; - activeConnection = false; - l2cap_event_flag = 0; // Reset flags - l2cap_state = L2CAP_WAIT; - - // Needed for PS3 Dualshock Controller commands to work via bluetooth - for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) - HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID + PS3Connected = false; + PS3MoveConnected = false; + PS3NavigationConnected = false; + activeConnection = false; + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; + + // Needed for PS3 Dualshock Controller commands to work via bluetooth + for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) + HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID } void PS3BT::disconnect() { // Use this void to disconnect any of the controllers - //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection - pBtd->l2cap_disconnection_request(hci_handle,0x0A, interrupt_scid, interrupt_dcid); - Reset(); - l2cap_state = L2CAP_INTERRUPT_DISCONNECT; + //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection + pBtd->l2cap_disconnection_request(hci_handle, 0x0A, interrupt_scid, interrupt_dcid); + Reset(); + l2cap_state = L2CAP_INTERRUPT_DISCONNECT; } void PS3BT::ACLData(uint8_t* ACLData) { - if(!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected && !activeConnection && !pBtd->connectToWii && !pBtd->incomingWii && !pBtd->pairWithWii) { - if (ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) { - if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) { - pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service - activeConnection = true; - hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection - 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 + if (!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected && !activeConnection && !pBtd->connectToWii && !pBtd->incomingWii && !pBtd->pairWithWii) { + if (ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if ((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) { + pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service + activeConnection = true; + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + 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 - 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: ")); - Serial.print(pBtd->hci_version); - Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR")); - } -#endif - } - } - } - if (((ACLData[0] | (ACLData[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok - for(uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) - 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 - Notify(PSTR("\r\nL2CAP Command Rejected - Reason: ")); - PrintHex(l2capinbuf[13]); - Serial.print(" "); - PrintHex(l2capinbuf[12]); - Serial.print(" Data: "); - PrintHex(l2capinbuf[17]); - Serial.print(" "); - PrintHex(l2capinbuf[16]); - Serial.print(" "); - PrintHex(l2capinbuf[15]); - Serial.print(" "); - PrintHex(l2capinbuf[14]); + 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); + Serial.print(pBtd->hci_version); + Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80); + } #endif - } - else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { -#ifdef EXTRADEBUG - Notify(PSTR("\r\nL2CAP Connection Request - PSM: ")); - PrintHex(l2capinbuf[13]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[12]); - Notify(PSTR(" SCID: ")); - PrintHex(l2capinbuf[15]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[14]); - Notify(PSTR(" Identifier: ")); - PrintHex(l2capinbuf[9]); -#endif - if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { - identifier = l2capinbuf[9]; - control_scid[0] = l2capinbuf[14]; - control_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_CONTROL_REQUEST; - } - else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { - identifier = l2capinbuf[9]; - interrupt_scid[0] = l2capinbuf[14]; - interrupt_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST; - } - } - else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { - if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Serial.print("\r\nHID Control Configuration Complete"); - l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS; } - else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { - //Serial.print("\r\nHID Interrupt Configuration Complete"); - l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS; - } - } } - else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Serial.print("\r\nHID Control Configuration Request"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_REQUEST; - } - else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { - //Serial.print("\r\nHID Interrupt Configuration Request"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_REQUEST; - } - } - else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { -#ifdef DEBUG - Notify(PSTR("\r\nDisconnect Request: Control Channel")); -#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 - Notify(PSTR("\r\nDisconnect Request: Interrupt Channel")); -#endif - identifier = l2capinbuf[9]; - pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid); - Reset(); - } - } - else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { - if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { - //Serial.print("\r\nDisconnect Response: Control Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE; - } - else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { - //Serial.print("\r\nDisconnect Response: Interrupt Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE; - } - } -#ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nL2CAP Unknown Signaling Command: ")); - PrintHex(l2capinbuf[8]); - } -#endif - } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt - //Serial.print("\r\nL2CAP Interrupt"); - if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) { - /* Read Report */ - if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT - if(PS3Connected || PS3NavigationConnected) - ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16)); - else if(PS3MoveConnected) - ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16)); - - //Notify(PSTR("\r\nButtonState"); - //PrintHex(ButtonState); - - if(ButtonState != OldButtonState) { - ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable - OldButtonState = ButtonState; - } - -#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers - for(uint8_t i = 10; i < 58;i++) { - PrintHex(l2capinbuf[i]); - Serial.print(" "); - } - Serial.println(); -#endif - } - } } - L2CAP_task(); - } -} -void PS3BT::L2CAP_task() { - switch (l2cap_state) { - case L2CAP_WAIT: - if (l2cap_connection_request_control_flag) { + if (((ACLData[0] | (ACLData[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok + for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) + 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 - Notify(PSTR("\r\nHID Control Incoming Connection Request")); + Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Serial.print(" "); + PrintHex (l2capinbuf[12], 0x80); + Serial.print(" Data: "); + PrintHex (l2capinbuf[17], 0x80); + Serial.print(" "); + PrintHex (l2capinbuf[16], 0x80); + Serial.print(" "); + PrintHex (l2capinbuf[15], 0x80); + Serial.print(" "); + PrintHex (l2capinbuf[14], 0x80); #endif - pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, control_scid); - l2cap_state = L2CAP_CONTROL_REQUEST; - } - break; - case L2CAP_CONTROL_REQUEST: - if (l2cap_config_request_control_flag) { + } else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { +#ifdef EXTRADEBUG + Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" SCID: "), 0x80); + PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR(" Identifier: "), 0x80); + PrintHex (l2capinbuf[9], 0x80); +#endif + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + identifier = l2capinbuf[9]; + control_scid[0] = l2capinbuf[14]; + control_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_CONTROL_REQUEST; + } else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { + identifier = l2capinbuf[9]; + interrupt_scid[0] = l2capinbuf[14]; + interrupt_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { + if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { + //Serial.print("\r\nHID Control Configuration Complete"); + l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS; + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Serial.print("\r\nHID Interrupt Configuration Complete"); + l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS; + } + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { + //Serial.print("\r\nHID Control Configuration Request"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_REQUEST; + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Serial.print("\r\nHID Interrupt Configuration Request"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { #ifdef DEBUG - Notify(PSTR("\r\nHID Control Configuration Request")); + Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80); #endif - pBtd->l2cap_config_response(hci_handle,identifier, control_scid); - l2cap_state = L2CAP_CONTROL_SUCCESS; - } - break; - - case L2CAP_CONTROL_SUCCESS: - if (l2cap_config_success_control_flag) { + 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 - Notify(PSTR("\r\nHID Control Successfully Configured")); + Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80); #endif - l2cap_state = L2CAP_INTERRUPT_SETUP; - } - break; - case L2CAP_INTERRUPT_SETUP: - if (l2cap_connection_request_interrupt_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nHID Interrupt Incoming Connection Request")); + identifier = l2capinbuf[9]; + pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid); + Reset(); + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { + if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { + //Serial.print("\r\nDisconnect Response: Control Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE; + } else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { + //Serial.print("\r\nDisconnect Response: Interrupt Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE; + } + } +#ifdef EXTRADEBUG + else { + Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); + PrintHex (l2capinbuf[8], 0x80); + } #endif - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, interrupt_scid); - - l2cap_state = L2CAP_INTERRUPT_REQUEST; - } - break; - case L2CAP_INTERRUPT_REQUEST: - if (l2cap_config_request_interrupt_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nHID Interrupt Configuration Request")); -#endif - pBtd->l2cap_config_response(hci_handle,identifier, interrupt_scid); - l2cap_state = L2CAP_INTERRUPT_SUCCESS; - } - break; - case L2CAP_INTERRUPT_SUCCESS: - if (l2cap_config_success_interrupt_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nHID Interrupt Successfully Configured")); -#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; - timer = millis(); - } - break; + } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt + //Serial.print("\r\nL2CAP Interrupt"); + if (PS3Connected || PS3MoveConnected || PS3NavigationConnected) { + /* Read Report */ + if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + if (PS3Connected || PS3NavigationConnected) + ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16)); + else if (PS3MoveConnected) + ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16)); - /* These states are handled in Run() */ - - case L2CAP_INTERRUPT_DISCONNECT: - if (l2cap_disconnect_response_interrupt_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nDisconnected Interrupt Channel")); + //Notify(PSTR("\r\nButtonState", 0x80); + //PrintHex(ButtonState, 0x80); + + if (ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + } + +#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers + for (uint8_t i = 10; i < 58; i++) { + PrintHex (l2capinbuf[i], 0x80); + Serial.print(" "); + } + Serial.println(); #endif - identifier++; - pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); - l2cap_state = L2CAP_CONTROL_DISCONNECT; - } - break; - - case L2CAP_CONTROL_DISCONNECT: - if (l2cap_disconnect_response_control_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nDisconnected Control Channel")); -#endif - pBtd->hci_disconnect(hci_handle); - hci_handle = -1; // Reset handle - l2cap_event_flag = 0; // Reset flags - l2cap_state = L2CAP_WAIT; - } - break; - } + } + } + } + L2CAP_task(); + } } + +void PS3BT::L2CAP_task() { + switch (l2cap_state) { + case L2CAP_WAIT: + if (l2cap_connection_request_control_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80); +#endif + pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, control_scid); + l2cap_state = L2CAP_CONTROL_REQUEST; + } + break; + case L2CAP_CONTROL_REQUEST: + if (l2cap_config_request_control_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); +#endif + pBtd->l2cap_config_response(hci_handle, identifier, control_scid); + l2cap_state = L2CAP_CONTROL_SUCCESS; + } + break; + + case L2CAP_CONTROL_SUCCESS: + if (l2cap_config_success_control_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); +#endif + l2cap_state = L2CAP_INTERRUPT_SETUP; + } + break; + case L2CAP_INTERRUPT_SETUP: + if (l2cap_connection_request_interrupt_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80); +#endif + pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); + + l2cap_state = L2CAP_INTERRUPT_REQUEST; + } + break; + case L2CAP_INTERRUPT_REQUEST: + if (l2cap_config_request_interrupt_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80); +#endif + pBtd->l2cap_config_response(hci_handle, identifier, interrupt_scid); + l2cap_state = L2CAP_INTERRUPT_SUCCESS; + } + break; + case L2CAP_INTERRUPT_SUCCESS: + if (l2cap_config_success_interrupt_flag) { +#ifdef DEBUG + 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; + timer = millis(); + } + break; + + /* These states are handled in Run() */ + + case L2CAP_INTERRUPT_DISCONNECT: + if (l2cap_disconnect_response_interrupt_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); +#endif + identifier++; + pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); + l2cap_state = L2CAP_CONTROL_DISCONNECT; + } + break; + + case L2CAP_CONTROL_DISCONNECT: + if (l2cap_disconnect_response_control_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nDisconnected Control Channel"), 0x80); +#endif + pBtd->hci_disconnect(hci_handle); + hci_handle = -1; // Reset handle + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; + } + break; + } +} + void PS3BT::Run() { - switch (l2cap_state) { - case L2CAP_HID_ENABLE_SIXAXIS: - 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 - l2cap_state = L2CAP_HID_PS3_LED; - timer = millis(); - } - break; - - 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); + switch (l2cap_state) { + case L2CAP_HID_ENABLE_SIXAXIS: + 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 + l2cap_state = L2CAP_HID_PS3_LED; + timer = millis(); + } + break; + + 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 - Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); + 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 + 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 - Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); + 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(); + PS3NavigationConnected = true; + } else if (remote_name[0] == 'M') { // First letter in Motion Controller ('M') + moveSetBulb(Red); + timerBulbRumble = millis(); #ifdef DEBUG - Notify(PSTR("\r\nMotion Controller Enabled\r\n")); + Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80); #endif - PS3MoveConnected = true; - } - l2cap_state = L2CAP_DONE; - } - break; - - case L2CAP_DONE: - if (PS3MoveConnected) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on - if (millis() - timerBulbRumble > 4000) { //Send at least every 4th second - HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on - timerBulbRumble = millis(); - } - } - break; - } + PS3MoveConnected = true; + } + l2cap_state = L2CAP_DONE; + } + break; + + case L2CAP_DONE: + if (PS3MoveConnected) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on + if (millis() - timerBulbRumble > 4000) { //Send at least every 4th second + HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); //The Bulb and rumble values, has to be written again and again, for it to stay turned on + timerBulbRumble = millis(); + } + } + break; + } } /************************************************************/ @@ -562,96 +564,105 @@ void PS3BT::Run() { /************************************************************/ //Playstation Sixaxis Dualshock and Navigation Controller commands -void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) { - if (millis() - timerHID <= 250)// Check if is has been more than 250ms since last command - delay((uint32_t)(250 - (millis() - timerHID)));//There have to be a delay between commands - pBtd->L2CAP_Command(hci_handle,data,nbytes,control_scid[0],control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel - timerHID = millis(); + +void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) { + if (millis() - timerHID <= 250)// Check if is has been more than 250ms since last command + delay((uint32_t)(250 - (millis() - timerHID))); //There have to be a delay between commands + pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel + timerHID = millis(); } + void PS3BT::setAllOff() { - for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) - HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID - - HID_Command(HIDBuffer, HID_BUFFERSIZE); -} -void PS3BT::setRumbleOff() { - HIDBuffer[3] = 0x00; - HIDBuffer[4] = 0x00;//low mode off - HIDBuffer[5] = 0x00; - HIDBuffer[6] = 0x00;//high mode off - - HID_Command(HIDBuffer, HID_BUFFERSIZE); -} -void PS3BT::setRumbleOn(Rumble mode) { - /* Still not totally sure how it works, maybe something like this instead? - * 3 - duration_right - * 4 - power_right - * 5 - duration_left - * 6 - power_left - */ - if ((mode & 0x30) > 0) { - HIDBuffer[3] = 0xfe; - HIDBuffer[5] = 0xfe; - if (mode == RumbleHigh) { - HIDBuffer[4] = 0;//low mode off - HIDBuffer[6] = 0xff;//high mode on - } - else { - HIDBuffer[4] = 0xff;//low mode on - HIDBuffer[6] = 0;//high mode off - } + for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) + HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); //First two bytes reserved for report type and ID + HID_Command(HIDBuffer, HID_BUFFERSIZE); - } } + +void PS3BT::setRumbleOff() { + HIDBuffer[3] = 0x00; + HIDBuffer[4] = 0x00; //low mode off + HIDBuffer[5] = 0x00; + HIDBuffer[6] = 0x00; //high mode off + + HID_Command(HIDBuffer, HID_BUFFERSIZE); +} + +void PS3BT::setRumbleOn(Rumble mode) { + if ((mode & 0x30) > 0x00) { + uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow + if (mode == RumbleHigh) { + power[0] = 0x00; + power[1] = 0xff; + } + setRumbleOn(0xfe, power[0], 0xfe, power[1]); + } +} + +void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) { + HIDBuffer[3] = rightDuration; + HIDBuffer[4] = rightPower; + HIDBuffer[5] = leftDuration; + HIDBuffer[6] = leftPower; + HID_Command(HIDBuffer, HID_BUFFERSIZE); +} + void PS3BT::setLedOff(LED a) { - HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1)); - HID_Command(HIDBuffer, HID_BUFFERSIZE); + HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1)); + HID_Command(HIDBuffer, HID_BUFFERSIZE); } + void PS3BT::setLedOn(LED a) { - HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1); - HID_Command(HIDBuffer, HID_BUFFERSIZE); + HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1); + HID_Command(HIDBuffer, HID_BUFFERSIZE); } + void PS3BT::setLedToggle(LED a) { - HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1); - HID_Command(HIDBuffer, HID_BUFFERSIZE); + HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1); + HID_Command(HIDBuffer, HID_BUFFERSIZE); } + void PS3BT::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB - uint8_t cmd_buf[6]; - cmd_buf[0] = 0x53;// HID BT Set_report (0x50) | Report Type (Feature 0x03) - cmd_buf[1] = 0xF4;// Report ID - cmd_buf[2] = 0x42;// Special PS3 Controller enable commands - cmd_buf[3] = 0x03; - cmd_buf[4] = 0x00; - cmd_buf[5] = 0x00; - - HID_Command(cmd_buf, 6); + uint8_t cmd_buf[6]; + cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03) + cmd_buf[1] = 0xF4; // Report ID + cmd_buf[2] = 0x42; // Special PS3 Controller enable commands + cmd_buf[3] = 0x03; + cmd_buf[4] = 0x00; + cmd_buf[5] = 0x00; + + HID_Command(cmd_buf, 6); } //Playstation Move Controller commands -void PS3BT::HIDMove_Command(uint8_t* data,uint8_t nbytes) { - if (millis() - timerHID <= 250)// Check if is has been less than 200ms since last command - delay((uint32_t)(250 - (millis() - timerHID)));//There have to be a delay between commands - pBtd->L2CAP_Command(hci_handle,data,nbytes,interrupt_scid[0],interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel - timerHID = millis(); + +void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) { + if (millis() - timerHID <= 250)// Check if is has been less than 200ms since last command + delay((uint32_t)(250 - (millis() - timerHID))); //There have to be a delay between commands + pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel + timerHID = millis(); } + void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set the Color using RGB values - //set the Bulb's values into the write buffer - HIDMoveBuffer[3] = r; - HIDMoveBuffer[4] = g; - HIDMoveBuffer[5] = b; - - HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); + //set the Bulb's values into the write buffer + HIDMoveBuffer[3] = r; + HIDMoveBuffer[4] = g; + HIDMoveBuffer[5] = b; + + HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); } + void PS3BT::moveSetBulb(Colors color) { //Use this to set the Color using the predefined colors in enum - moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color)); + moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color)); } + void PS3BT::moveSetRumble(uint8_t rumble) { #ifdef DEBUG - 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%")); + 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 - //set the rumble value into the write buffer - HIDMoveBuffer[7] = rumble; - - HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); -} \ No newline at end of file + //set the rumble value into the write buffer + HIDMoveBuffer[7] = rumble; + + HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); +} diff --git a/PS3BT.h b/PS3BT.h index 75bd4d6e..ef0b7544 100644 --- a/PS3BT.h +++ b/PS3BT.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -60,187 +60,195 @@ /** * This BluetoothService class implements support for all the official PS3 Controllers: * Dualshock 3, Navigation or a Motion controller via Bluetooth. - * + * * Information about the protocol can be found at the wiki: https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information. */ class PS3BT : public BluetoothService { public: - /** - * Constructor for the PS3BT class. - * @param pBtd Pointer to BTD class instance. - * @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0 - * Pass your dongles Bluetooth address into the constructor, - * This will set BTD#my_bdaddr, so you don't have to plug in the dongle before pairing with your controller. - */ - PS3BT(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0); - - /** @name BluetoothService implementation */ - /** - * Used to pass acldata to the services. - * @param ACLData Incoming acldata. - */ - virtual void ACLData(uint8_t* ACLData); - /** Used to run part of the state maschine. */ - virtual void Run(); - /** Use this to reset the service. */ - virtual void Reset(); - /** Used this to disconnect any of the controllers. */ - virtual void disconnect(); - /**@}*/ - - /** @name PS3 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). - */ - bool getButtonPress(Button b); - bool getButtonClick(Button b); - /**@}*/ - /** @name PS3 Controller functions */ - /** - * Used to get the analog value from button presses. - * @param a The ::Button to read. - * The supported buttons are: - * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, - * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. - * @return Analog value in the range of 0-255. - */ - uint8_t getAnalogButton(Button a); - /** - * Used to read the analog joystick. - * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. - * @return Return the analog value in the range of 0-255. - */ - uint8_t getAnalogHat(AnalogHat a); - /** - * Used to read the sensors inside the Dualshock 3 and Move controller. - * @param a - * The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside. - * The Move controller has a 3-axis accelerometer, a 3-axis gyro, a 3-axis magnetometer - * and a temperature sensor inside. - * @return Return the raw sensor value. - */ - int16_t getSensor(Sensor a); - /** - * Use this to get ::Pitch and ::Roll calculated using the accelerometer. - * @param a Either ::Pitch or ::Roll. - * @return Return the angle in the range of 0-360. - */ - double getAngle(Angle a); - /** - * Read the sensors inside the Move controller. - * @param a ::aXmove, ::aYmove, ::aZmove, ::gXmove, ::gYmove, ::gZmove, ::mXmove, ::mYmove, and ::mXmove. - * @return The value in SI units. - */ - double get9DOFValues(Sensor a); - /** - * Get the ::Status from the controller. - * @param c The ::Status you want to read. - * @return True if correct and false if not. - */ - bool getStatus(Status c); - /** - * Read all the available ::Status from the controller. - * @return One large string with all the information. - */ - String getStatusString(); - /** - * Read the temperature from the Move controller. - * @return The temperature in degrees celsius. - */ - String getTemperature(); - - /** Used to set all LEDs and ::Rumble off. */ - void setAllOff(); - /** Turn off ::Rumble. */ - void setRumbleOff(); - /** - * Turn on ::Rumble. - * @param mode Either ::RumbleHigh or ::RumbleLow. - */ - void setRumbleOn(Rumble mode); - /** - * Turn the specific ::LED off. - * @param a The ::LED to turn off. - */ - void setLedOff(LED a); - /** - * Turn the specific ::LED on. - * @param a The ::LED to turn on. - */ - void setLedOn(LED a); - /** - * Toggle the specific ::LED. - * @param a The ::LED to toggle. - */ - void setLedToggle(LED a); - - /** - * Use this to set the Color using RGB values. - * @param r,g,b RGB value. - */ - void moveSetBulb(uint8_t r, uint8_t g, uint8_t b); - /** - * Use this to set the color using the predefined colors in ::Colors. - * @param color The desired color. - */ - void moveSetBulb(Colors color); - /** - * Set the rumble value inside the Move controller. - * @param rumble The desired value in the range from 64-255. - */ - void moveSetRumble(uint8_t rumble); - /**@}*/ - - /** 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. */ - bool PS3MoveConnected; - /** Variable used to indicate if the navigation controller is successfully connected. */ - bool PS3NavigationConnected; - + /** + * Constructor for the PS3BT class. + * @param pBtd Pointer to BTD class instance. + * @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0 + * Pass your dongles Bluetooth address into the constructor, + * This will set BTD#my_bdaddr, so you don't have to plug in the dongle before pairing with your controller. + */ + PS3BT(BTD *pBtd, uint8_t btadr5 = 0, uint8_t btadr4 = 0, uint8_t btadr3 = 0, uint8_t btadr2 = 0, uint8_t btadr1 = 0, uint8_t btadr0 = 0); + + /** @name BluetoothService implementation */ + /** + * Used to pass acldata to the services. + * @param ACLData Incoming acldata. + */ + virtual void ACLData(uint8_t* ACLData); + /** Used to run part of the state maschine. */ + virtual void Run(); + /** Use this to reset the service. */ + virtual void Reset(); + /** Used this to disconnect any of the controllers. */ + virtual void disconnect(); + /**@}*/ + + /** @name PS3 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). + */ + bool getButtonPress(Button b); + bool getButtonClick(Button b); + /**@}*/ + /** @name PS3 Controller functions */ + /** + * Used to get the analog value from button presses. + * @param a The ::Button to read. + * The supported buttons are: + * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, + * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. + * @return Analog value in the range of 0-255. + */ + uint8_t getAnalogButton(Button a); + /** + * Used to read the analog joystick. + * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. + * @return Return the analog value in the range of 0-255. + */ + uint8_t getAnalogHat(AnalogHat a); + /** + * Used to read the sensors inside the Dualshock 3 and Move controller. + * @param a + * The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside. + * The Move controller has a 3-axis accelerometer, a 3-axis gyro, a 3-axis magnetometer + * and a temperature sensor inside. + * @return Return the raw sensor value. + */ + int16_t getSensor(Sensor a); + /** + * Use this to get ::Pitch and ::Roll calculated using the accelerometer. + * @param a Either ::Pitch or ::Roll. + * @return Return the angle in the range of 0-360. + */ + double getAngle(Angle a); + /** + * Read the sensors inside the Move controller. + * @param a ::aXmove, ::aYmove, ::aZmove, ::gXmove, ::gYmove, ::gZmove, ::mXmove, ::mYmove, and ::mXmove. + * @return The value in SI units. + */ + double get9DOFValues(Sensor a); + /** + * Get the ::Status from the controller. + * @param c The ::Status you want to read. + * @return True if correct and false if not. + */ + bool getStatus(Status c); + /** + * Read all the available ::Status from the controller. + * @return One large string with all the information. + */ + String getStatusString(); + /** + * Read the temperature from the Move controller. + * @return The temperature in degrees celsius. + */ + String getTemperature(); + + /** Used to set all LEDs and ::Rumble off. */ + void setAllOff(); + /** Turn off ::Rumble. */ + void setRumbleOff(); + /** + * Turn on ::Rumble. + * @param mode Either ::RumbleHigh or ::RumbleLow. + */ + void setRumbleOn(Rumble mode); + /** + * Turn on ::Rumble using custom duration and power. + * @param rightDuration The duration of the right/low rumble effect. + * @param rightPower The intensity of the right/low rumble effect. + * @param leftDuration The duration of the left/high rumble effect. + * @param leftPower The intensity of the left/high rumble effect. + */ + void setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower); + /** + * Turn the specific ::LED off. + * @param a The ::LED to turn off. + */ + void setLedOff(LED a); + /** + * Turn the specific ::LED on. + * @param a The ::LED to turn on. + */ + void setLedOn(LED a); + /** + * Toggle the specific ::LED. + * @param a The ::LED to toggle. + */ + void setLedToggle(LED a); + + /** + * Use this to set the Color using RGB values. + * @param r,g,b RGB value. + */ + void moveSetBulb(uint8_t r, uint8_t g, uint8_t b); + /** + * Use this to set the color using the predefined colors in ::Colors. + * @param color The desired color. + */ + void moveSetBulb(Colors color); + /** + * Set the rumble value inside the Move controller. + * @param rumble The desired value in the range from 64-255. + */ + void moveSetRumble(uint8_t rumble); + /**@}*/ + + /** 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. */ + bool PS3MoveConnected; + /** Variable used to indicate if the navigation controller is successfully connected. */ + bool PS3NavigationConnected; + private: - /* mandatory members */ - BTD *pBtd; - - void L2CAP_task(); // L2CAP state machine - - /* Variables filled from HCI event management */ - int16_t hci_handle; - uint8_t remote_name[30]; // First 30 chars of remote name - bool activeConnection; // Used to indicate if it's already has established a connection - - /* variables used by high level L2CAP task */ - uint8_t l2cap_state; - uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events - - unsigned long timer; - - uint32_t ButtonState; - uint32_t OldButtonState; - uint32_t ButtonClickState; - - uint32_t timerHID; // Timer used see if there has to be a delay before a new HID command - uint32_t timerBulbRumble;// used to continuously set PS3 Move controller Bulb and rumble values - - uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data - uint8_t HIDBuffer[HID_BUFFERSIZE]; // Used to store HID commands - uint8_t HIDMoveBuffer[HID_BUFFERSIZE]; // Used to store HID commands for the Move controller - - /* L2CAP Channels */ - uint8_t control_scid[2]; // L2CAP source CID for HID_Control - uint8_t control_dcid[2]; // 0x0040 - uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt - uint8_t interrupt_dcid[2]; // 0x0041 - uint8_t identifier; // Identifier for connection - - /* HID Commands */ - void HID_Command(uint8_t* data, uint8_t nbytes); - void HIDMove_Command(uint8_t* data, uint8_t nbytes); - void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth + /* mandatory members */ + BTD *pBtd; + + void L2CAP_task(); // L2CAP state machine + + /* Variables filled from HCI event management */ + int16_t hci_handle; + uint8_t remote_name[30]; // First 30 chars of remote name + bool activeConnection; // Used to indicate if it's already has established a connection + + /* variables used by high level L2CAP task */ + uint8_t l2cap_state; + uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events + + unsigned long timer; + + uint32_t ButtonState; + uint32_t OldButtonState; + uint32_t ButtonClickState; + + uint32_t timerHID; // Timer used see if there has to be a delay before a new HID command + uint32_t timerBulbRumble; // used to continuously set PS3 Move controller Bulb and rumble values + + uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data + uint8_t HIDBuffer[HID_BUFFERSIZE]; // Used to store HID commands + uint8_t HIDMoveBuffer[HID_BUFFERSIZE]; // Used to store HID commands for the Move controller + + /* L2CAP Channels */ + uint8_t control_scid[2]; // L2CAP source CID for HID_Control + uint8_t control_dcid[2]; // 0x0040 + uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt + uint8_t interrupt_dcid[2]; // 0x0041 + uint8_t identifier; // Identifier for connection + + /* HID Commands */ + void HID_Command(uint8_t* data, uint8_t nbytes); + void HIDMove_Command(uint8_t* data, uint8_t nbytes); + void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth }; -#endif \ No newline at end of file +#endif diff --git a/PS3Enums.h b/PS3Enums.h index 449f93b9..d42f7903 100644 --- a/PS3Enums.h +++ b/PS3Enums.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -22,17 +22,17 @@ /** Used to set the LEDs on the controllers */ const uint8_t LEDS[] PROGMEM = { - 0x01, // LED1 - 0x02, // LED2 - 0x04, // LED3 - 0x08, // LED4 - - 0x09, // LED5 - 0x0A, // LED6 - 0x0C, // LED7 - 0x0D, // LED8 - 0x0E, // LED9 - 0x0F // LED10 + 0x01, // LED1 + 0x02, // LED2 + 0x04, // LED3 + 0x08, // LED4 + + 0x09, // LED5 + 0x0A, // LED6 + 0x0C, // LED7 + 0x0D, // LED8 + 0x0E, // LED9 + 0x0F // LED10 }; /** @@ -41,29 +41,29 @@ const uint8_t LEDS[] PROGMEM = { * Note: that the location is shiftet 9 when it's connected via USB. */ const uint32_t BUTTONS[] PROGMEM = { - 0x10, // UP - 0x20, // RIGHT - 0x40, // DOWN - 0x80, // LEFT + 0x10, // UP + 0x20, // RIGHT + 0x40, // DOWN + 0x80, // LEFT - 0x01, // SELECT - 0x08, // START - 0x02, // L3 - 0x04, // R3 - - 0x0100, // L2 - 0x0200, // R2 - 0x0400, // L1 - 0x0800, // R1 + 0x01, // SELECT + 0x08, // START + 0x02, // L3 + 0x04, // R3 - 0x1000, // TRIANGLE - 0x2000, // CIRCLE - 0x4000, // CROSS - 0x8000, // SQUARE - - 0x010000, // PS - 0x080000, // MOVE - covers 12 bits - we only need to read the top 8 - 0x100000 // T - covers 12 bits - we only need to read the top 8 + 0x0100, // L2 + 0x0200, // R2 + 0x0400, // L1 + 0x0800, // R1 + + 0x1000, // TRIANGLE + 0x2000, // CIRCLE + 0x4000, // CROSS + 0x8000, // SQUARE + + 0x010000, // PS + 0x080000, // MOVE - covers 12 bits - we only need to read the top 8 + 0x100000 // T - covers 12 bits - we only need to read the top 8 }; /** @@ -72,122 +72,125 @@ const uint32_t BUTTONS[] PROGMEM = { * Note: that the location is shiftet 9 when it's connected via USB. */ const uint8_t ANALOGBUTTONS[] PROGMEM = { - 23, // UP_ANALOG - 24, // RIGHT_ANALOG - 25, // DOWN_ANALOG - 26, // LEFT_ANALOG - 0,0,0,0, // Skip SELECT, L3, R3 and START - - 27, // L2_ANALOG - 28, // R2_ANALOG - 29, // L1_ANALOG - 30, // R1_ANALOG - 31, // TRIANGLE_ANALOG - 32, // CIRCLE_ANALOG - 33, // CROSS_ANALOG - 34, // SQUARE_ANALOG - 0,0, // Skip PS and MOVE - - // Playstation Move Controller - 15 // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading) + 23, // UP_ANALOG + 24, // RIGHT_ANALOG + 25, // DOWN_ANALOG + 26, // LEFT_ANALOG + 0, 0, 0, 0, // Skip SELECT, L3, R3 and START + + 27, // L2_ANALOG + 28, // R2_ANALOG + 29, // L1_ANALOG + 30, // R1_ANALOG + 31, // TRIANGLE_ANALOG + 32, // CIRCLE_ANALOG + 33, // CROSS_ANALOG + 34, // SQUARE_ANALOG + 0, 0, // Skip PS and MOVE + + // Playstation Move Controller + 15 // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading) }; /** Used to set the colors of the move controller. */ enum Colors { - /** r = 255, g = 0, b = 0 */ - Red = 0xFF0000, - /** r = 0, g = 255, b = 0 */ - Green = 0xFF00, - /** r = 0, g = 0, b = 255 */ - Blue = 0xFF, - - /** r = 255, g = 235, b = 4 */ - Yellow = 0xFFEB04, - /** r = 0, g = 255, b = 255 */ - Lightblue = 0xFFFF, - /** r = 255, g = 0, b = 255 */ - Purble = 0xFF00FF, - - /** r = 255, g = 255, b = 255 */ - White = 0xFFFFFF, - /** r = 0, g = 0, b = 0 */ - Off = 0x00, + /** r = 255, g = 0, b = 0 */ + Red = 0xFF0000, + /** r = 0, g = 255, b = 0 */ + Green = 0xFF00, + /** r = 0, g = 0, b = 255 */ + Blue = 0xFF, + + /** r = 255, g = 235, b = 4 */ + Yellow = 0xFFEB04, + /** r = 0, g = 255, b = 255 */ + Lightblue = 0xFFFF, + /** r = 255, g = 0, b = 255 */ + Purble = 0xFF00FF, + + /** r = 255, g = 255, b = 255 */ + White = 0xFFFFFF, + /** r = 0, g = 0, b = 0 */ + Off = 0x00, }; /** * Sensors inside the Sixaxis Dualshock 3 and Move controller. - * + * * Note: that the location is shiftet 9 when it's connected via USB. */ enum Sensor { - /** Accelerometer x-axis */ - aX = 50, - /** Accelerometer y-axis */ - aY = 52, - /** Accelerometer z-axis */ - aZ = 54, - /** Gyro z-axis */ - gZ = 56, + /** Accelerometer x-axis */ + aX = 50, + /** Accelerometer y-axis */ + aY = 52, + /** Accelerometer z-axis */ + aZ = 54, + /** Gyro z-axis */ + gZ = 56, - /** Accelerometer x-axis */ - aXmove = 28, - /** Accelerometer z-axis */ - aZmove = 30, - /** Accelerometer y-axis */ - aYmove = 32, - - /** Gyro x-axis */ - gXmove = 40, - /** Gyro z-axis */ - gZmove = 42, - /** Gyro y-axis */ - gYmove = 44, - - /** Temperature sensor */ - tempMove = 46, - - /** Magnetometer x-axis */ - mXmove = 47, - /** Magnetometer z-axis */ - mZmove = 49, - /** Magnetometer y-axis */ - mYmove = 50, + /** Accelerometer x-axis */ + aXmove = 28, + /** Accelerometer z-axis */ + aZmove = 30, + /** Accelerometer y-axis */ + aYmove = 32, + + /** Gyro x-axis */ + gXmove = 40, + /** Gyro z-axis */ + gZmove = 42, + /** Gyro y-axis */ + gYmove = 44, + + /** Temperature sensor */ + tempMove = 46, + + /** Magnetometer x-axis */ + mXmove = 47, + /** Magnetometer z-axis */ + mZmove = 49, + /** Magnetometer y-axis */ + mYmove = 50, }; + /** Used to get the angle calculated using the accelerometer. */ enum Angle { - Pitch = 0x01, - Roll = 0x02, + Pitch = 0x01, + Roll = 0x02, }; + enum Status { - // Note that the location is shiftet 9 when it's connected via USB - // Byte location | bit location - Plugged = (38 << 8) | 0x02, - Unplugged = (38 << 8) | 0x03, - - Charging = (39 << 8) | 0xEE, - NotCharging = (39 << 8) | 0xF1, - Shutdown = (39 << 8) | 0x01, - Dying = (39 << 8) | 0x02, - Low = (39 << 8) | 0x03, - High = (39 << 8) | 0x04, - Full = (39 << 8) | 0x05, - - MoveCharging = (21 << 8) | 0xEE, - MoveNotCharging = (21 << 8) | 0xF1, - MoveShutdown = (21 << 8) | 0x01, - MoveDying = (21 << 8) | 0x02, - MoveLow = (21 << 8) | 0x03, - MoveHigh = (21 << 8) | 0x04, - MoveFull = (21 << 8) | 0x05, - - CableRumble = (40 << 8) | 0x10,//Opperating by USB and rumble is turned on - Cable = (40 << 8) | 0x12,//Opperating by USB and rumble is turned off - BluetoothRumble = (40 << 8) | 0x14,//Opperating by bluetooth and rumble is turned on - Bluetooth = (40 << 8) | 0x16,//Opperating by bluetooth and rumble is turned off + // Note that the location is shiftet 9 when it's connected via USB + // Byte location | bit location + Plugged = (38 << 8) | 0x02, + Unplugged = (38 << 8) | 0x03, + + Charging = (39 << 8) | 0xEE, + NotCharging = (39 << 8) | 0xF1, + Shutdown = (39 << 8) | 0x01, + Dying = (39 << 8) | 0x02, + Low = (39 << 8) | 0x03, + High = (39 << 8) | 0x04, + Full = (39 << 8) | 0x05, + + MoveCharging = (21 << 8) | 0xEE, + MoveNotCharging = (21 << 8) | 0xF1, + MoveShutdown = (21 << 8) | 0x01, + MoveDying = (21 << 8) | 0x02, + MoveLow = (21 << 8) | 0x03, + MoveHigh = (21 << 8) | 0x04, + MoveFull = (21 << 8) | 0x05, + + CableRumble = (40 << 8) | 0x10, //Opperating by USB and rumble is turned on + Cable = (40 << 8) | 0x12, //Opperating by USB and rumble is turned off + BluetoothRumble = (40 << 8) | 0x14, //Opperating by bluetooth and rumble is turned on + Bluetooth = (40 << 8) | 0x16, //Opperating by bluetooth and rumble is turned off }; -enum Rumble { - RumbleHigh = 0x10, - RumbleLow = 0x20, + +enum Rumble { + RumbleHigh = 0x10, + RumbleLow = 0x20, }; #endif \ No newline at end of file diff --git a/PS3USB.cpp b/PS3USB.cpp index 57c2e2b9..ae44f9c0 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -21,531 +21,545 @@ //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers const uint8_t PS3_REPORT_BUFFER[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const uint8_t MOVE_REPORT_BUFFER[] PROGMEM = { - 0x02, 0x00, // Always 0x02, 0x00, - 0x00, 0x00, 0x00, // r, g, b, - 0x00, // Always 0x00, - 0x00 // Rumble + 0x02, 0x00, // Always 0x02, 0x00, + 0x00, 0x00, 0x00, // r, g, b, + 0x00, // Always 0x00, + 0x00 // Rumble }; -PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0): +PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) : 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; iRegisterDeviceClass(this); //set devConfig[] entry - - my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead - my_bdaddr[4] = btadr4; - my_bdaddr[3] = btadr3; - my_bdaddr[2] = btadr2; - my_bdaddr[1] = btadr1; - my_bdaddr[0] = btadr0; + for (uint8_t i = 0; i < PS3_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 + + my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead + my_bdaddr[4] = btadr4; + my_bdaddr[3] = btadr3; + my_bdaddr[2] = btadr2; + my_bdaddr[1] = btadr1; + my_bdaddr[0] = btadr0; } uint8_t PS3USB::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\nPS3USB Init")); -#endif - // check if address has already been assigned to an instance - if (bAddress) { -#ifdef DEBUG - Notify(PSTR("\r\nAddress in use")); -#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 - Notify(PSTR("\r\nAddress not found")); -#endif - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } - - if (!p->epinfo) { -#ifdef DEBUG - Notify(PSTR("\r\nepinfo is null")); -#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 != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID)) - 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 - Notify(PSTR("\r\nsetAddr: ")); -#endif - PrintHex(rcode); - return rcode; - } -#ifdef EXTRADEBUG - Notify(PSTR("\r\nAddr: ")); - PrintHex(bAddress); -#endif - 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 PID and VID we will use known values for the - configuration values for device, interface, endpoints and HID for the PS3 Controllers */ - - /* Initialize data structures for endpoints of device */ - epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint - epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT; - epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0; - epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0; - epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint - epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT; - epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0; - epInfo[ PS3_INPUT_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[ PS3_CONTROL_PIPE ].epAddr, 1); - if( rcode ) - goto FailSetConf; - - if(PID == PS3_PID || PID == PS3NAVIGATION_PID) { - if(PID == PS3_PID) { -#ifdef DEBUG - Notify(PSTR("\r\nDualshock 3 Controller Connected")); -#endif - PS3Connected = true; - } else { // must be a navigation controller -#ifdef DEBUG - Notify(PSTR("\r\nNavigation Controller Connected")); -#endif - PS3NavigationConnected = true; - } - /* Set internal bluetooth address and request for data */ - setBdaddr(my_bdaddr); - enable_sixaxis(); - setLedOn(LED1); - - // Needed for PS3 Dualshock and Navigation commands to work - for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) - writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); - - 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 - Notify(PSTR("\r\nMotion Controller Connected")); -#endif - PS3MoveConnected = true; - setMoveBdaddr(my_bdaddr); // Set internal bluetooth address - moveSetBulb(Red); - - // Needed for Move commands to work - for (uint8_t i = 0; i < MOVE_REPORT_BUFFER_SIZE; i++) - writeBuf[i] = pgm_read_byte(&MOVE_REPORT_BUFFER[i]); - } + uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint16_t PID; + uint16_t VID; - bPollEnable = true; - Notify(PSTR("\r\n")); - timer = millis(); - return 0; // successful configuration - - /* diagnostic messages */ + // get memory address of USB device address pool + AddressPool &addrPool = pUsb->GetAddressPool(); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nPS3USB Init"), 0x80); +#endif + // check if address has already been assigned to an instance + if (bAddress) { +#ifdef DEBUG + 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 + Notify(PSTR("\r\nAddress not found"), 0x80); +#endif + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { +#ifdef DEBUG + 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 != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID)) + 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 + Notify(PSTR("\r\nsetAddr: "), 0x80); +#endif + PrintHex (rcode, 0x80); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + PrintHex (bAddress, 0x80); +#endif + 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 PID and VID we will use known values for the + configuration values for device, interface, endpoints and HID for the PS3 Controllers */ + + /* Initialize data structures for endpoints of device */ + epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint + epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT; + epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0; + epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0; + epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint + epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT; + epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0; + epInfo[ PS3_INPUT_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[ PS3_CONTROL_PIPE ].epAddr, 1); + if (rcode) + goto FailSetConf; + + if (PID == PS3_PID || PID == PS3NAVIGATION_PID) { + if (PID == PS3_PID) { +#ifdef DEBUG + Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80); +#endif + PS3Connected = true; + } else { // must be a navigation controller +#ifdef DEBUG + 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); + + // Needed for PS3 Dualshock and Navigation commands to work + for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) + writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); + + 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 + Notify(PSTR("\r\nMotion Controller Connected"), 0x80); +#endif + PS3MoveConnected = true; + setMoveBdaddr(my_bdaddr); // Set internal bluetooth address + moveSetBulb(Red); + + // Needed for Move commands to work + for (uint8_t i = 0; i < MOVE_REPORT_BUFFER_SIZE; i++) + writeBuf[i] = pgm_read_byte(&MOVE_REPORT_BUFFER[i]); + } + + bPollEnable = true; + Notify(PSTR("\r\n"), 0x80); + timer = millis(); + return 0; // successful configuration + + /* diagnostic messages */ FailGetDevDescr: #ifdef DEBUG - Notify(PSTR("\r\ngetDevDescr:")); + Notify(PSTR("\r\ngetDevDescr:"), 0x80); #endif - goto Fail; + goto Fail; FailSetDevTblEntry: #ifdef DEBUG - Notify(PSTR("\r\nsetDevTblEn:")); + Notify(PSTR("\r\nsetDevTblEn:"), 0x80); #endif - goto Fail; + goto Fail; FailSetConf: #ifdef DEBUG - Notify(PSTR("\r\nsetConf:")); + Notify(PSTR("\r\nsetConf:"), 0x80); #endif - goto Fail; + goto Fail; FailUnknownDevice: #ifdef DEBUG - Notify(PSTR("\r\nUnknown Device Connected - VID: ")); - PrintHex(VID); - Notify(PSTR(" PID: ")); - PrintHex(PID); + Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); + PrintHex (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + PrintHex (PID, 0x80); #endif - rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - goto Fail; + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + goto Fail; Fail: #ifdef DEBUG - Notify(PSTR("\r\nPS3 Init Failed, error code: ")); - Serial.print(rcode,HEX); -#endif - Release(); - return rcode; + Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80); + Serial.print(rcode, HEX); +#endif + Release(); + return rcode; } /* Performs a cleanup after failed Init() attempt */ uint8_t PS3USB::Release() { - PS3Connected = false; - PS3MoveConnected = false; - PS3NavigationConnected = false; - pUsb->GetAddressPool().FreeAddress(bAddress); - bAddress = 0; - bPollEnable = false; - return 0; + PS3Connected = false; + PS3MoveConnected = false; + PS3NavigationConnected = false; + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; + return 0; } -uint8_t PS3USB::Poll() { - if (!bPollEnable) - return 0; - - if(PS3Connected || PS3NavigationConnected) { - uint16_t BUFFER_SIZE = EP_MAXPKTSIZE; - pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1 - if(millis() - timer > 100) { // Loop 100ms before processing data - readReport(); + +uint8_t PS3USB::Poll() { + if (!bPollEnable) + return 0; + + if (PS3Connected || PS3NavigationConnected) { + uint16_t BUFFER_SIZE = EP_MAXPKTSIZE; + pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1 + if (millis() - timer > 100) { // Loop 100ms before processing data + readReport(); #ifdef PRINTREPORT - printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers + printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers #endif + } + } else if (PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB + if (millis() - timer > 4000) // Send at least every 4th second + { + Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on + timer = millis(); + } } - } - else if(PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB - if (millis() - timer > 4000) // Send at least every 4th second - { - Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on - timer = millis(); - } - } - return 0; + return 0; } -void PS3USB::readReport() { - if (readBuf == NULL) - return; +void PS3USB::readReport() { + if (readBuf == NULL) + return; - ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16)); - - //Notify(PSTR("\r\nButtonState"); - //PrintHex(ButtonState); - - if(ButtonState != OldButtonState) { - ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable - OldButtonState = ButtonState; - } + ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16)); + + //Notify(PSTR("\r\nButtonState", 0x80); + //PrintHex(ButtonState, 0x80); + + if (ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + } } void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers #ifdef PRINTREPORT - if (readBuf == NULL) - return; - for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE;i++) { - PrintHex(readBuf[i]); - Serial.print(" "); - } - Serial.println(); + if (readBuf == NULL) + return; + for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) { + PrintHex (readBuf[i], 0x80); + Serial.print(" "); + } + Serial.println(); #endif } bool PS3USB::getButtonPress(Button b) { - return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); + return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); } + bool PS3USB::getButtonClick(Button b) { - uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]); - bool click = (ButtonClickState & button); - ButtonClickState &= ~button; // clear "click" event - return click; + uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; } + uint8_t PS3USB::getAnalogButton(Button a) { - if (readBuf == NULL) - return 0; - return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a]))-9]); + if (readBuf == NULL) + return 0; + return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])) - 9]); } + uint8_t PS3USB::getAnalogHat(AnalogHat a) { - if (readBuf == NULL) - return 0; - return (uint8_t)(readBuf[((uint8_t)a+6)]); + if (readBuf == NULL) + return 0; + return (uint8_t)(readBuf[((uint8_t)a + 6)]); } + uint16_t PS3USB::getSensor(Sensor a) { - if (readBuf == NULL) - return 0; - return ((readBuf[((uint16_t)a)-9] << 8) | readBuf[((uint16_t)a + 1)-9]); + if (readBuf == NULL) + return 0; + return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]); } -double PS3USB::getAngle(Angle a) { - if(PS3Connected) { - double accXval; - double accYval; - double accZval; - - // Data for the Kionix KXPC4 used in the DualShock 3 - const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) - accXval = -((double)getSensor(aX)-zeroG); - accYval = -((double)getSensor(aY)-zeroG); - accZval = -((double)getSensor(aZ)-zeroG); - - // Convert to 360 degrees resolution - // atan2 outputs the value of -π to π (radians) - // We are then converting it to 0 to 2π and then to degrees - if (a == Pitch) { - double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG; - return angle; - } else { - double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG; - return angle; - } - } else - return 0; + +double PS3USB::getAngle(Angle a) { + if (PS3Connected) { + double accXval; + double accYval; + double accZval; + + // Data for the Kionix KXPC4 used in the DualShock 3 + const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) + accXval = -((double)getSensor(aX) - zeroG); + accYval = -((double)getSensor(aY) - zeroG); + accZval = -((double)getSensor(aZ) - zeroG); + + // Convert to 360 degrees resolution + // atan2 outputs the value of -π to π (radians) + // We are then converting it to 0 to 2π and then to degrees + if (a == Pitch) { + double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG; + return angle; + } else { + double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG; + return angle; + } + } else + return 0; } + bool PS3USB::getStatus(Status c) { - if (readBuf == NULL) + if (readBuf == NULL) + return false; + if (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff)) + return true; return false; - if (readBuf[((uint16_t)c >> 8)-9] == ((uint8_t)c & 0xff)) - return true; - return false; } + String PS3USB::getStatusString() { - if (PS3Connected || PS3NavigationConnected) { - char statusOutput[100]; - - strcpy(statusOutput,"ConnectionStatus: "); - - if (getStatus(Plugged)) strcat(statusOutput,"Plugged"); - else if (getStatus(Unplugged)) strcat(statusOutput,"Unplugged"); - else strcat(statusOutput,"Error"); - - - strcat(statusOutput," - PowerRating: "); - - if (getStatus(Charging)) strcat(statusOutput,"Charging"); - else if (getStatus(NotCharging)) strcat(statusOutput,"Not Charging"); - else if (getStatus(Shutdown)) strcat(statusOutput,"Shutdown"); - else if (getStatus(Dying)) strcat(statusOutput,"Dying"); - else if (getStatus(Low)) strcat(statusOutput,"Low"); - else if (getStatus(High)) strcat(statusOutput,"High"); - else if (getStatus(Full)) strcat(statusOutput,"Full"); - else strcat(statusOutput,"Error"); - - strcat(statusOutput," - WirelessStatus: "); - - if (getStatus(CableRumble)) strcat(statusOutput,"Cable - Rumble is on"); - else if (getStatus(Cable)) strcat(statusOutput,"Cable - Rumble is off"); - else if (getStatus(BluetoothRumble)) strcat(statusOutput,"Bluetooth - Rumble is on"); - else if (getStatus(Bluetooth)) strcat(statusOutput,"Bluetooth - Rumble is off"); - else strcat(statusOutput,"Error"); - - return statusOutput; - } + if (PS3Connected || PS3NavigationConnected) { + char statusOutput[100]; + + strcpy(statusOutput, "ConnectionStatus: "); + + if (getStatus(Plugged)) strcat(statusOutput, "Plugged"); + else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged"); + else strcat(statusOutput, "Error"); + + + strcat(statusOutput, " - PowerRating: "); + + if (getStatus(Charging)) strcat(statusOutput, "Charging"); + else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging"); + else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown"); + else if (getStatus(Dying)) strcat(statusOutput, "Dying"); + else if (getStatus(Low)) strcat(statusOutput, "Low"); + else if (getStatus(High)) strcat(statusOutput, "High"); + else if (getStatus(Full)) strcat(statusOutput, "Full"); + else strcat(statusOutput, "Error"); + + strcat(statusOutput, " - WirelessStatus: "); + + if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on"); + else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off"); + else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on"); + else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off"); + else strcat(statusOutput, "Error"); + + return statusOutput; + } } /* Playstation Sixaxis Dualshock and Navigation Controller commands */ void PS3USB::PS3_Command(uint8_t* data, uint16_t nbytes) { - //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x01), Report Type (Output 0x02), interface (0x00), datalength, datalength, data) - pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL); + //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x01), Report Type (Output 0x02), interface (0x00), datalength, datalength, data) + pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL); } + void PS3USB::setAllOff() { - for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) - writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer - - PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE); -} -void PS3USB::setRumbleOff() { - writeBuf[1] = 0x00; - writeBuf[2] = 0x00;//low mode off - writeBuf[3] = 0x00; - writeBuf[4] = 0x00;//high mode off - - PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE); -} -void PS3USB::setRumbleOn(Rumble mode) { - /* Still not totally sure how it works, maybe something like this instead? - * 3 - duration_right - * 4 - power_right - * 5 - duration_left - * 6 - power_left - */ - if ((mode & 0x30) > 0) { - writeBuf[1] = 0xfe; - writeBuf[3] = 0xfe; - if (mode == RumbleHigh) { - writeBuf[2] = 0;//low mode off - writeBuf[4] = 0xff;//high mode on - } - else { - writeBuf[2] = 0xff;//low mode on - writeBuf[4] = 0;//high mode off - } + for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) + writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer + PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE); - } } + +void PS3USB::setRumbleOff() { + writeBuf[1] = 0x00; + writeBuf[2] = 0x00; //low mode off + writeBuf[3] = 0x00; + writeBuf[4] = 0x00; //high mode off + + PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE); +} + +void PS3USB::setRumbleOn(Rumble mode) { + if ((mode & 0x30) > 0x00) { + uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow + if (mode == RumbleHigh) { + power[0] = 0x00; + power[1] = 0xff; + } + setRumbleOn(0xfe, power[0], 0xfe, power[1]); + } +} + +void PS3USB::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) { + writeBuf[1] = rightDuration; + writeBuf[2] = rightPower; + writeBuf[3] = leftDuration; + writeBuf[4] = leftPower; + 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); + 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); + 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); + writeBuf[9] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1); + PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE); } -void PS3USB::setBdaddr(uint8_t* BDADDR) { - /* Set the internal bluetooth address */ - uint8_t buf[8]; - buf[0] = 0x01; - buf[1] = 0x00; - for (uint8_t i = 0; i < 6; i++) - buf[i+2] = BDADDR[5 - i];//Copy into buffer, has to be written reversed - - //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) - pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); + +void PS3USB::setBdaddr(uint8_t* BDADDR) { + /* Set the internal bluetooth address */ + uint8_t buf[8]; + buf[0] = 0x01; + buf[1] = 0x00; + for (uint8_t i = 0; i < 6; i++) + buf[i + 2] = BDADDR[5 - i]; //Copy into buffer, has to be written reversed + + //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) + pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); #ifdef DEBUG - Notify(PSTR("\r\nBluetooth Address was set to: ")); - for(int8_t i = 5; i > 0; i--) { - PrintHex(my_bdaddr[i]); - Serial.print(":"); - } - PrintHex(my_bdaddr[0]); + Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (my_bdaddr[i], 0x80); + Serial.print(":"); + } + PrintHex (my_bdaddr[0], 0x80); #endif - return; + return; } + void PS3USB::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB - uint8_t cmd_buf[4]; - cmd_buf[0] = 0x42;// Special PS3 Controller enable commands - cmd_buf[1] = 0x0c; - cmd_buf[2] = 0x00; - cmd_buf[3] = 0x00; - - //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF4), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) - pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL); + uint8_t cmd_buf[4]; + cmd_buf[0] = 0x42; // Special PS3 Controller enable commands + cmd_buf[1] = 0x0c; + cmd_buf[2] = 0x00; + cmd_buf[3] = 0x00; + + //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF4), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) + pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL); } /* Playstation Move Controller commands */ void PS3USB::Move_Command(uint8_t* data, uint16_t nbytes) { - pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data); -} + pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data); +} void PS3USB::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set the Color using RGB values - // set the Bulb's values into the write buffer - writeBuf[2] = r; - writeBuf[3] = g; - writeBuf[4] = b; - - Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); + // set the Bulb's values into the write buffer + writeBuf[2] = r; + writeBuf[3] = g; + writeBuf[4] = b; + + Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); } + void PS3USB::moveSetBulb(Colors color) { //Use this to set the Color using the predefined colors in "enums.h" - moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color)); + moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color)); } + void PS3USB::moveSetRumble(uint8_t rumble) { #ifdef DEBUG - 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%")); + 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 - //set the rumble value into the write buffer - writeBuf[6] = rumble; - - Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); + //set the rumble value into the write buffer + writeBuf[6] = rumble; + + Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); } + void PS3USB::setMoveBdaddr(uint8_t* BDADDR) { - /* Set the internal bluetooth address */ - uint8_t buf[11]; - buf[0] = 0x05; - buf[7] = 0x10; - buf[8] = 0x01; - buf[9] = 0x02; - buf[10] = 0x12; - - for (uint8_t i = 0; i < 6; i++) - buf[i + 1] = BDADDR[i]; - - //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); + /* Set the internal bluetooth address */ + uint8_t buf[11]; + buf[0] = 0x05; + buf[7] = 0x10; + buf[8] = 0x01; + buf[9] = 0x02; + buf[10] = 0x12; + + for (uint8_t i = 0; i < 6; i++) + buf[i + 1] = BDADDR[i]; + + //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); #ifdef DEBUG - Notify(PSTR("\r\nBluetooth Address was set to: ")); - for(int8_t i = 5; i > 0; i--) { - PrintHex(my_bdaddr[i]); - Serial.print(":"); - } - PrintHex(my_bdaddr[0]); + Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + PrintHex (my_bdaddr[i], 0x80); + Serial.print(":"); + } + PrintHex (my_bdaddr[0], 0x80); #endif - return; -} \ No newline at end of file + return; +} diff --git a/PS3USB.h b/PS3USB.h index b313b05e..05a9476c 100644 --- a/PS3USB.h +++ b/PS3USB.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -56,193 +56,207 @@ /** * This class implements support for all the official PS3 Controllers: * Dualshock 3, Navigation or a Motion controller via USB. - * + * * One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB on the Move controller. - * + * * Information about the protocol can be found at the wiki: https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information. */ class PS3USB : public USBDeviceConfig { public: - /** - * Constructor for the PS3USB class. - * @param pUsb Pointer to USB class instance. - * @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0 - * Pass your dongles Bluetooth address into the constructor, - * so you are able to pair the controller with a Bluetooth dongle. - */ - PS3USB(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0); - - /** @name USBDeviceConfig implementation */ - /** - * Initialize the PS3 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; }; - /**@}*/ + /** + * Constructor for the PS3USB class. + * @param pUsb Pointer to USB class instance. + * @param btadr5,btadr4,btadr3,btadr2,btadr1,btadr0 + * Pass your dongles Bluetooth address into the constructor, + * so you are able to pair the controller with a Bluetooth dongle. + */ + PS3USB(USB *pUsb, uint8_t btadr5 = 0, uint8_t btadr4 = 0, uint8_t btadr3 = 0, uint8_t btadr2 = 0, uint8_t btadr1 = 0, uint8_t btadr0 = 0); - /** - * Used to set the Bluetooth address inside the Dualshock 3 and Navigation controller. - * @param BDADDR Your dongles Bluetooth address. - */ - void setBdaddr(uint8_t* BDADDR); - /** - * Used to set the Bluetooth address inside the Move controller. - * @param BDADDR Your dongles Bluetooth address. - */ - void setMoveBdaddr(uint8_t* BDADDR); + /** @name USBDeviceConfig implementation */ + /** + * Initialize the PS3 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(); - /** @name PS3 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). - */ - bool getButtonPress(Button b); - bool getButtonClick(Button b); - /**@}*/ - /** @name PS3 Controller functions */ - /** - * Used to get the analog value from button presses. - * @param a The ::Button to read. - * The supported buttons are: - * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, - * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. - * @return Analog value in the range of 0-255. - */ - uint8_t getAnalogButton(Button a); - /** - * Used to read the analog joystick. - * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. - * @return Return the analog value in the range of 0-255. - */ - uint8_t getAnalogHat(AnalogHat a); - /** - * Used to read the sensors inside the Dualshock 3 controller. - * @param a - * The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside. - * @return Return the raw sensor value. - */ - uint16_t getSensor(Sensor a); - /** - * Use this to get ::Pitch and ::Roll calculated using the accelerometer. - * @param a Either ::Pitch or ::Roll. - * @return Return the angle in the range of 0-360. - */ - double getAngle(Angle a); - /** - * Get the ::Status from the controller. - * @param c The ::Status you want to read. - * @return True if correct and false if not. - */ - bool getStatus(Status c); - /** - * Read all the available ::Status from the controller. - * @return One large string with all the information. - */ - String getStatusString(); + /** + * Get the device address. + * @return The device address. + */ + virtual uint8_t GetAddress() { + return bAddress; + }; - /** Used to set all LEDs and ::Rumble off. */ - void setAllOff(); - /** Turn off ::Rumble. */ - void setRumbleOff(); - /** - * Turn on ::Rumble. - * @param mode Either ::RumbleHigh or ::RumbleLow. - */ - void setRumbleOn(Rumble mode); - /** - * Turn the specific ::LED off. - * @param a The ::LED to turn off. - */ - void setLedOff(LED a); - /** - * Turn the specific ::LED on. - * @param a The ::LED to turn on. - */ - void setLedOn(LED a); - /** - * Toggle the specific ::LED. - * @param a The ::LED to toggle. - */ - void setLedToggle(LED a); - - /** - * Use this to set the Color using RGB values. - * @param r,g,b RGB value. - */ - void moveSetBulb(uint8_t r, uint8_t g, uint8_t b); - /** - * Use this to set the color using the predefined colors in ::Colors. - * @param color The desired color. - */ - void moveSetBulb(Colors color); - /** - * Set the rumble value inside the Move controller. - * @param rumble The desired value in the range from 64-255. - */ - void moveSetRumble(uint8_t rumble); - /**@}*/ + /** + * Used to check if the controller has been initialized. + * @return True if it's ready. + */ + virtual bool isReady() { + return bPollEnable; + }; + /**@}*/ - /** 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. */ - bool PS3MoveConnected; - /** Variable used to indicate if the navigation controller is successfully connected. */ - bool PS3NavigationConnected; - -protected: - /** Pointer to USB class instance. */ - USB *pUsb; - /** Device address. */ - uint8_t bAddress; - /** Endpoint info structure. */ - EpInfo epInfo[PS3_MAX_ENDPOINTS]; - -private: - bool bPollEnable; - - uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values + /** + * Used to set the Bluetooth address inside the Dualshock 3 and Navigation controller. + * @param BDADDR Your dongles Bluetooth address. + */ + void setBdaddr(uint8_t* BDADDR); + /** + * Used to set the Bluetooth address inside the Move controller. + * @param BDADDR Your dongles Bluetooth address. + */ + void setMoveBdaddr(uint8_t* BDADDR); - uint32_t ButtonState; - uint32_t OldButtonState; - uint32_t ButtonClickState; - - uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor - uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data - uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data - - void readReport(); // read incoming data - void printReport(); // print incoming date - Uncomment for debugging + /** @name PS3 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). + */ + bool getButtonPress(Button b); + bool getButtonClick(Button b); + /**@}*/ + /** @name PS3 Controller functions */ + /** + * Used to get the analog value from button presses. + * @param a The ::Button to read. + * The supported buttons are: + * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, + * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. + * @return Analog value in the range of 0-255. + */ + uint8_t getAnalogButton(Button a); + /** + * Used to read the analog joystick. + * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. + * @return Return the analog value in the range of 0-255. + */ + uint8_t getAnalogHat(AnalogHat a); + /** + * Used to read the sensors inside the Dualshock 3 controller. + * @param a + * The Dualshock 3 has a 3-axis accelerometer and a 1-axis gyro inside. + * @return Return the raw sensor value. + */ + uint16_t getSensor(Sensor a); + /** + * Use this to get ::Pitch and ::Roll calculated using the accelerometer. + * @param a Either ::Pitch or ::Roll. + * @return Return the angle in the range of 0-360. + */ + double getAngle(Angle a); + /** + * Get the ::Status from the controller. + * @param c The ::Status you want to read. + * @return True if correct and false if not. + */ + bool getStatus(Status c); + /** + * Read all the available ::Status from the controller. + * @return One large string with all the information. + */ + String getStatusString(); - /* Private commands */ - void PS3_Command(uint8_t* data, uint16_t nbytes); - void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via USB - void Move_Command(uint8_t* data, uint16_t nbytes); + /** Used to set all LEDs and ::Rumble off. */ + void setAllOff(); + /** Turn off ::Rumble. */ + void setRumbleOff(); + /** + * Turn on ::Rumble. + * @param mode Either ::RumbleHigh or ::RumbleLow. + */ + void setRumbleOn(Rumble mode); + /** + * Turn on ::Rumble using custom duration and power. + * @param rightDuration The duration of the right/low rumble effect. + * @param rightPower The intensity of the right/low rumble effect. + * @param leftDuration The duration of the left/high rumble effect. + * @param leftPower The intensity of the left/high rumble effect. + */ + void setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower); + /** + * Turn the specific ::LED off. + * @param a The ::LED to turn off. + */ + void setLedOff(LED a); + /** + * Turn the specific ::LED on. + * @param a The ::LED to turn on. + */ + void setLedOn(LED a); + /** + * Toggle the specific ::LED. + * @param a The ::LED to toggle. + */ + void setLedToggle(LED a); + + /** + * Use this to set the Color using RGB values. + * @param r,g,b RGB value. + */ + void moveSetBulb(uint8_t r, uint8_t g, uint8_t b); + /** + * Use this to set the color using the predefined colors in ::Colors. + * @param color The desired color. + */ + void moveSetBulb(Colors color); + /** + * Set the rumble value inside the Move controller. + * @param rumble The desired value in the range from 64-255. + */ + void moveSetRumble(uint8_t rumble); + /**@}*/ + + /** 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. */ + bool PS3MoveConnected; + /** Variable used to indicate if the navigation controller is successfully connected. */ + bool PS3NavigationConnected; + +protected: + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[PS3_MAX_ENDPOINTS]; + +private: + bool bPollEnable; + + uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values + + uint32_t ButtonState; + uint32_t OldButtonState; + uint32_t ButtonClickState; + + uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor + uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data + uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data + + void readReport(); // read incoming data + void printReport(); // print incoming date - Uncomment for debugging + + /* Private commands */ + void PS3_Command(uint8_t* data, uint16_t nbytes); + void enable_sixaxis(); // Command used to enable the Dualshock 3 and Navigation controller to send data via USB + void Move_Command(uint8_t* data, uint16_t nbytes); }; #endif diff --git a/SPP.cpp b/SPP.cpp index 62920555..8455d974 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -23,889 +23,914 @@ /* * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0. */ -const uint8_t rfcomm_crc_table[256] PROGMEM = { /* reversed, 8-bit, poly=0x07 */ - 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, - 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, - 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, - 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, - 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, - 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, - 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, - 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, - 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, - 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, - 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, - 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, - 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, - 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, - 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, - 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF +const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */ + 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, + 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, + 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, + 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, + 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, + 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, + 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, + 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, + 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, + 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, + 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, + 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, + 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, + 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, + 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, + 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF }; -SPP::SPP(BTD *p, const char* name, const char* pin): +SPP::SPP(BTD *p, const char* name, const char* pin) : pBtd(p) // Pointer to BTD class instance - mandatory { - if (pBtd) - pBtd->registerServiceClass(this); // Register it as a Bluetooth service - - pBtd->btdName = name; - pBtd->btdPin = pin; - - /* Set device cid for the SDP and RFCOMM channelse */ - sdp_dcid[0] = 0x50; // 0x0050 - sdp_dcid[1] = 0x00; - rfcomm_dcid[0] = 0x51; // 0x0051 - rfcomm_dcid[1] = 0x00; - - Reset(); + if (pBtd) + pBtd->registerServiceClass(this); // Register it as a Bluetooth service + + pBtd->btdName = name; + pBtd->btdPin = pin; + + /* Set device cid for the SDP and RFCOMM channelse */ + sdp_dcid[0] = 0x50; // 0x0050 + sdp_dcid[1] = 0x00; + rfcomm_dcid[0] = 0x51; // 0x0051 + rfcomm_dcid[1] = 0x00; + + Reset(); } + void SPP::Reset() { - connected = false; - RFCOMMConnected = false; - SDPConnected = false; - l2cap_sdp_state = L2CAP_SDP_WAIT; - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; - l2cap_event_flag = 0; + connected = false; + RFCOMMConnected = false; + SDPConnected = false; + l2cap_sdp_state = L2CAP_SDP_WAIT; + l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; + l2cap_event_flag = 0; } -void SPP::disconnect(){ - connected = false; - // First the two L2CAP channels has to be disconencted and then the HCI connection - if(RFCOMMConnected) - pBtd->l2cap_disconnection_request(hci_handle,0x0A, rfcomm_scid, rfcomm_dcid); - if(RFCOMMConnected && SDPConnected) - delay(1); // Add delay between commands - if(SDPConnected) - pBtd->l2cap_disconnection_request(hci_handle,0x0B, sdp_scid, sdp_dcid); - l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE; + +void SPP::disconnect() { + connected = false; + // First the two L2CAP channels has to be disconencted and then the HCI connection + if (RFCOMMConnected) + pBtd->l2cap_disconnection_request(hci_handle, 0x0A, rfcomm_scid, rfcomm_dcid); + if (RFCOMMConnected && SDPConnected) + delay(1); // Add delay between commands + if (SDPConnected) + pBtd->l2cap_disconnection_request(hci_handle, 0x0B, sdp_scid, sdp_dcid); + l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE; } + void SPP::ACLData(uint8_t* l2capinbuf) { - if(!connected) { - if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { - if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) { - pBtd->sdpConnectionClaimed = true; - hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection - l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state - } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) { - pBtd->rfcommConnectionClaimed = true; - hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state - } + if (!connected) { + if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) { + pBtd->sdpConnectionClaimed = true; + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state + } else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) { + pBtd->rfcommConnectionClaimed = true; + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state + } + } } - } - 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) { + 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 - Notify(PSTR("\r\nL2CAP Command Rejected - Reason: ")); - PrintHex(l2capinbuf[13]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[12]); - Notify(PSTR(" Data: ")); - PrintHex(l2capinbuf[17]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[16]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[15]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[14]); + Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" Data: "), 0x80); + PrintHex (l2capinbuf[17], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[16], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[14], 0x80); #endif - } else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { + } else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { #ifdef EXTRADEBUG - Notify(PSTR("\r\nL2CAP Connection Request - PSM: ")); - PrintHex(l2capinbuf[13]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[12]); - Notify(PSTR(" SCID: ")); - PrintHex(l2capinbuf[15]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[14]); - Notify(PSTR(" Identifier: ")); - PrintHex(l2capinbuf[9]); + Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" SCID: "), 0x80); + PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR(" Identifier: "), 0x80); + PrintHex (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]; - sdp_scid[0] = l2capinbuf[14]; - sdp_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_SDP_REQUEST; - } else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || ----- - identifier = l2capinbuf[9]; - rfcomm_scid[0] = l2capinbuf[14]; - rfcomm_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; - } - } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { - if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success - if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { - //Serial.print("\r\nSDP Configuration Complete"); - l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_SUCCESS; - } - else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { - //Serial.print("\r\nRFCOMM Configuration Complete"); - l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; - } - } - } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { - if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { - //Serial.print("\r\nSDP Configuration Request"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_REQUEST; - } - else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { - //Serial.print("\r\nRFCOMM Configuration Request"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; - } - } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { - if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { - //Notify(PSTR("\r\nDisconnect Request: SDP Channel")); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_SDP_REQUEST; - } else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { - //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel")); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; - } - } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { - if (l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) { - //Serial.print("\r\nDisconnect Response: SDP Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE; - } else if (l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) { - //Serial.print("\r\nDisconnect Response: RFCOMM Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE; - } - } else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) { + 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]; + sdp_scid[0] = l2capinbuf[14]; + sdp_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_SDP_REQUEST; + } else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || ----- + identifier = l2capinbuf[9]; + rfcomm_scid[0] = l2capinbuf[14]; + rfcomm_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { + if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success + if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { + //Serial.print("\r\nSDP Configuration Complete"); + l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_SUCCESS; + } else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { + //Serial.print("\r\nRFCOMM Configuration Complete"); + l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; + } + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { + if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { + //Serial.print("\r\nSDP Configuration Request"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_SDP_REQUEST; + } else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { + //Serial.print("\r\nRFCOMM Configuration Request"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { + if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { + //Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_SDP_REQUEST; + } else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) { + //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { + if (l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) { + //Serial.print("\r\nDisconnect Response: SDP Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE; + } else if (l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) { + //Serial.print("\r\nDisconnect Response: RFCOMM Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE; + } + } else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) { #ifdef DEBUG - Notify(PSTR("\r\nInformation request")); + Notify(PSTR("\r\nInformation request"), 0x80); #endif - identifier = l2capinbuf[9]; - pBtd->l2cap_information_response(hci_handle,identifier,l2capinbuf[12],l2capinbuf[13]); - } + identifier = l2capinbuf[9]; + pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]); + } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nL2CAP Unknown Signaling Command: ")); - PrintHex(l2capinbuf[8]); - } + else { + Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); + PrintHex (l2capinbuf[8], 0x80); + } #endif - } else if (l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP - if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) { - /* - Serial.print("\r\nUUID: 0x"); - Serial.print(l2capinbuf[16],HEX); - Serial.print(" "); - Serial.print(l2capinbuf[17],HEX); - */ - if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) { - if(firstMessage) { - serialPortResponse1(l2capinbuf[9],l2capinbuf[10]); - firstMessage = false; - } else { - serialPortResponse2(l2capinbuf[9],l2capinbuf[10]); // Serialport continuation state - firstMessage = true; - } - } else if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) { - if(firstMessage) { - l2capResponse1(l2capinbuf[9],l2capinbuf[10]); - firstMessage = false; - } else { - l2capResponse2(l2capinbuf[9],l2capinbuf[10]); // L2CAP continuation state - firstMessage = true; - } - } else - serviceNotSupported(l2capinbuf[9],l2capinbuf[10]); // The service is not supported - } - } else if (l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM - rfcommChannel = l2capinbuf[8] & 0xF8; - rfcommDirection = l2capinbuf[8] & 0x04; - rfcommCommandResponse = l2capinbuf[8] & 0x02; - rfcommChannelType = l2capinbuf[9] & 0xEF; - rfcommPfBit = l2capinbuf[9] & 0x10; - - if(rfcommChannel>>3 != 0x00) - rfcommChannelConnection = rfcommChannel; - + } else if (l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP + if (l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) { + /* + Serial.print("\r\nUUID: 0x"); + Serial.print(l2capinbuf[16],HEX); + Serial.print(" "); + Serial.print(l2capinbuf[17],HEX); + */ + if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) { + if (firstMessage) { + serialPortResponse1(l2capinbuf[9], l2capinbuf[10]); + firstMessage = false; + } else { + serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state + firstMessage = true; + } + } else if ((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) { + if (firstMessage) { + l2capResponse1(l2capinbuf[9], l2capinbuf[10]); + firstMessage = false; + } else { + l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state + firstMessage = true; + } + } else + serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported + } + } else if (l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM + rfcommChannel = l2capinbuf[8] & 0xF8; + rfcommDirection = l2capinbuf[8] & 0x04; + rfcommCommandResponse = l2capinbuf[8] & 0x02; + rfcommChannelType = l2capinbuf[9] & 0xEF; + rfcommPfBit = l2capinbuf[9] & 0x10; + + if (rfcommChannel >> 3 != 0x00) + rfcommChannelConnection = rfcommChannel; + #ifdef EXTRADEBUG - Notify(PSTR("\r\nRFCOMM Channel: ")); - Serial.print(rfcommChannel>>3,HEX); - Notify(PSTR(" Direction: ")); - Serial.print(rfcommDirection>>2,HEX); - Notify(PSTR(" CommandResponse: ")); - Serial.print(rfcommCommandResponse>>1,HEX); - Notify(PSTR(" ChannelType: ")); - Serial.print(rfcommChannelType,HEX); - Notify(PSTR(" PF_BIT: ")); - Serial.print(rfcommPfBit,HEX); + Notify(PSTR("\r\nRFCOMM Channel: "), 0x80); + Serial.print(rfcommChannel >> 3, HEX); + Notify(PSTR(" Direction: "), 0x80); + Serial.print(rfcommDirection >> 2, HEX); + Notify(PSTR(" CommandResponse: "), 0x80); + Serial.print(rfcommCommandResponse >> 1, HEX); + Notify(PSTR(" ChannelType: "), 0x80); + Serial.print(rfcommChannelType, HEX); + Notify(PSTR(" PF_BIT: "), 0x80); + Serial.print(rfcommPfBit, HEX); #endif - if (rfcommChannelType == RFCOMM_DISC) { + if (rfcommChannelType == RFCOMM_DISC) { #ifdef DEBUG - Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: ")); - Serial.print(rfcommChannel>>3,HEX); + Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80); + Serial.print(rfcommChannel >> 3, HEX); #endif - connected = false; - sendRfcomm(rfcommChannel,rfcommDirection,rfcommCommandResponse,RFCOMM_UA,rfcommPfBit,rfcommbuf,0x00); // UA Command - } - if(connected) { - /* Read the incoming message */ - if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) { - uint8_t length = l2capinbuf[10] >> 1; // Get length - uint8_t offset = l2capinbuf[4]-length-4; // See if there is credit - if(rfcommAvailable + length <= sizeof(rfcommDataBuffer)) { // Don't add data to buffer if it would be full - for(uint8_t i = 0; i < length; i++) - rfcommDataBuffer[rfcommAvailable+i] = l2capinbuf[11+i+offset]; - rfcommAvailable += length; - } + connected = false; + sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command + } + if (connected) { + /* Read the incoming message */ + if (rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) { + uint8_t length = l2capinbuf[10] >> 1; // Get length + uint8_t offset = l2capinbuf[4] - length - 4; // See if there is credit + if (rfcommAvailable + length <= sizeof (rfcommDataBuffer)) { // Don't add data to buffer if it would be full + for (uint8_t i = 0; i < length; i++) + rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset]; + rfcommAvailable += length; + } #ifdef EXTRADEBUG - Notify(PSTR("\r\nRFCOMM Data Available: ")); - Serial.print(rfcommAvailable); - if (offset) { - Notify(PSTR(" - Credit: 0x")); - Serial.print(l2capinbuf[11],HEX); - } + Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80); + Serial.print(rfcommAvailable); + if (offset) { + Notify(PSTR(" - Credit: 0x"), 0x80); + Serial.print(l2capinbuf[11], HEX); + } #endif #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth - for(uint8_t i = 0; i < length; i++) - Serial.write(l2capinbuf[i+11+offset]); + for (uint8_t i = 0; i < length; i++) + Serial.write(l2capinbuf[i + 11 + offset]); #endif - } else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command + } else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command #ifdef DEBUG - Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command")); + Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80); #endif - rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command - rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 - rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM - rfcommbuf[4] = l2capinbuf[15]; // Priority - rfcommbuf[5] = l2capinbuf[16]; // Timer - rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB - rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB - 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 - } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command + rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command + rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 + rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM + rfcommbuf[4] = l2capinbuf[15]; // Priority + rfcommbuf[5] = l2capinbuf[16]; // Timer + rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB + rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB + 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 + } else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command #ifdef DEBUG - Notify(PSTR("\r\nSend UIH Modem Status Response")); + Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80); #endif - rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response - rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) - rfcommbuf[3] = l2capinbuf[14]; - sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x04); + rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response + rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) + rfcommbuf[3] = l2capinbuf[14]; + sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04); + } + } else { + if (rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish +#ifdef DEBUG + 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 + Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80); +#endif + rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response + rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 + rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM + rfcommbuf[4] = 0x00; // Priority + rfcommbuf[5] = 0x00; // Timer + rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50) + rfcommbuf[7] = 0x00; // Max Fram Size MSB + rfcommbuf[8] = 0x00; // MaxRatransm. + 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 + Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80); +#endif + rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response + rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) + rfcommbuf[3] = l2capinbuf[14]; + sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04); + + delay(1); +#ifdef DEBUG + Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80); +#endif + rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command + rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) + rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES) + + 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 + Notify(PSTR("\r\nSend UIH Command with credit"), 0x80); +#endif + sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit + creditSent = true; + timer = millis(); + waitForLastCommand = true; + } + } else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit +#ifdef DEBUG + 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 + Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80); +#endif + rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command + rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 + rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 + rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM + rfcommbuf[4] = l2capinbuf[15]; // Priority + rfcommbuf[5] = l2capinbuf[16]; // Timer + rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB + rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB + 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 + Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80); +#endif + waitForLastCommand = false; + creditSent = false; + connected = true; // The RFCOMM channel is now established + } +#ifdef DEBUG + else if (rfcommChannelType != RFCOMM_DISC) { + Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80); + PrintHex (rfcommChannelType, 0x80); + Notify(PSTR(" Command: "), 0x80); + PrintHex (l2capinbuf[11], 0x80); + } +#endif + } } - } else { - if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish -#ifdef DEBUG - Notify(PSTR("\r\nReceived SABM Command")); -#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 - Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command")); -#endif - rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response - rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 - rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM - rfcommbuf[4] = 0x00; // Priority - rfcommbuf[5] = 0x00; // Timer - rfcommbuf[6] = BULK_MAXPKTSIZE-14; // Max Fram Size LSB - set to the size of received data (50) - rfcommbuf[7] = 0x00; // Max Fram Size MSB - rfcommbuf[8] = 0x00; // MaxRatransm. - 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 - Notify(PSTR("\r\nSend UIH Modem Status Response")); -#endif - rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response - rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) - rfcommbuf[3] = l2capinbuf[14]; - sendRfcomm(rfcommChannel,rfcommDirection,0,RFCOMM_UIH,rfcommPfBit,rfcommbuf,0x04); - - delay(1); -#ifdef DEBUG - Notify(PSTR("\r\nSend UIH Modem Status Command")); -#endif - rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command - rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3) - rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES) - - 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 - Notify(PSTR("\r\nSend UIH Command with credit")); -#endif - sendRfcommCredit(rfcommChannelConnection,rfcommDirection,0,RFCOMM_UIH,0x10,sizeof(rfcommDataBuffer)); // Send credit - creditSent = true; - timer = millis(); - waitForLastCommand = true; - } - } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit -#ifdef DEBUG - Notify(PSTR("\r\nReceived UIH Command with credit")); -#endif - } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command -#ifdef DEBUG - Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command")); -#endif - rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command - rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1 - rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1 - rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM - rfcommbuf[4] = l2capinbuf[15]; // Priority - rfcommbuf[5] = l2capinbuf[16]; // Timer - rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB - rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB - 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 - Notify(PSTR("\r\nRFCOMM Connection is now established\r\n")); -#endif - waitForLastCommand = false; - creditSent = false; - connected = true; // The RFCOMM channel is now established - } -#ifdef DEBUG - else if(rfcommChannelType != RFCOMM_DISC) { - Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: ")); - PrintHex(rfcommChannelType); - Notify(PSTR(" Command: ")); - PrintHex(l2capinbuf[11]); - } -#endif - } - } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: ")); - PrintHex(l2capinbuf[7]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[6]); + else { + Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80); + PrintHex (l2capinbuf[7], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[6], 0x80); + } +#endif + SDP_task(); + RFCOMM_task(); } -#endif - SDP_task(); - RFCOMM_task(); - } } + 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 + 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 - Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n")); + Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80); #endif - creditSent = false; - waitForLastCommand = false; - connected = true; // The RFCOMM channel is now established - } + creditSent = false; + waitForLastCommand = false; + connected = true; // The RFCOMM channel is now established + } } + void SPP::SDP_task() { - switch (l2cap_sdp_state) - { - case L2CAP_SDP_WAIT: - if (l2cap_connection_request_sdp_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_SDP_REQUEST; // Clear flag + switch (l2cap_sdp_state) { + case L2CAP_SDP_WAIT: + if (l2cap_connection_request_sdp_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_SDP_REQUEST; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nSDP Incoming Connection Request")); + Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80); #endif - pBtd->l2cap_connection_response(hci_handle,identifier, sdp_dcid, sdp_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, sdp_dcid, sdp_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, sdp_scid); - l2cap_sdp_state = L2CAP_SDP_REQUEST; - } - break; - case L2CAP_SDP_REQUEST: - if (l2cap_config_request_sdp_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_REQUEST; // Clear flag + pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid); + l2cap_sdp_state = L2CAP_SDP_REQUEST; + } + break; + case L2CAP_SDP_REQUEST: + if (l2cap_config_request_sdp_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_REQUEST; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nSDP Configuration Request")); -#endif - pBtd->l2cap_config_response(hci_handle,identifier, sdp_scid); - l2cap_sdp_state = L2CAP_SDP_SUCCESS; - } - break; - case L2CAP_SDP_SUCCESS: - if (l2cap_config_success_sdp_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_SUCCESS; // Clear flag -#ifdef DEBUG - Notify(PSTR("\r\nSDP Successfully Configured")); + Notify(PSTR("\r\nSDP Configuration Request"), 0x80); #endif - firstMessage = true; // Reset bool - SDPConnected = true; - l2cap_sdp_state = L2CAP_SDP_DONE; - } - break; - case L2CAP_SDP_DONE: - if(l2cap_disconnect_request_sdp_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_SDP_REQUEST; // Clear flag - SDPConnected = false; + pBtd->l2cap_config_response(hci_handle, identifier, sdp_scid); + l2cap_sdp_state = L2CAP_SDP_SUCCESS; + } + break; + case L2CAP_SDP_SUCCESS: + if (l2cap_config_success_sdp_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_SUCCESS; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nDisconnected SDP Channel")); + Notify(PSTR("\r\nSDP Successfully Configured"), 0x80); #endif - pBtd->l2cap_disconnection_response(hci_handle,identifier,sdp_dcid,sdp_scid); - l2cap_sdp_state = L2CAP_SDP_WAIT; - } else if(l2cap_connection_request_sdp_flag) - l2cap_rfcomm_state = L2CAP_SDP_WAIT; - 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) { + firstMessage = true; // Reset bool + SDPConnected = true; + l2cap_sdp_state = L2CAP_SDP_DONE; + } + break; + case L2CAP_SDP_DONE: + if (l2cap_disconnect_request_sdp_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_SDP_REQUEST; // Clear flag + SDPConnected = false; #ifdef DEBUG - Notify(PSTR("\r\nDisconnected L2CAP Connection")); + Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80); #endif - RFCOMMConnected = false; - SDPConnected = false; - pBtd->hci_disconnect(hci_handle); - hci_handle = -1; // Reset handle - l2cap_event_flag = 0; // Reset flags - l2cap_sdp_state = L2CAP_SDP_WAIT; - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; - } - break; - } + pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid); + l2cap_sdp_state = L2CAP_SDP_WAIT; + } else if (l2cap_connection_request_sdp_flag) + l2cap_rfcomm_state = L2CAP_SDP_WAIT; + 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 + Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80); +#endif + RFCOMMConnected = false; + SDPConnected = false; + pBtd->hci_disconnect(hci_handle); + hci_handle = -1; // Reset handle + l2cap_event_flag = 0; // Reset flags + l2cap_sdp_state = L2CAP_SDP_WAIT; + l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; + } + break; + } } -void SPP::RFCOMM_task() -{ - switch (l2cap_rfcomm_state) - { - case L2CAP_RFCOMM_WAIT: - if(l2cap_connection_request_rfcomm_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; // Clear flag + +void SPP::RFCOMM_task() { + switch (l2cap_rfcomm_state) { + case L2CAP_RFCOMM_WAIT: + if (l2cap_connection_request_rfcomm_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nRFCOMM Incoming Connection Request")); + Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80); #endif - pBtd->l2cap_connection_response(hci_handle,identifier, rfcomm_dcid, rfcomm_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, rfcomm_scid); - l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST; - } - break; - case L2CAP_RFCOMM_REQUEST: - if (l2cap_config_request_rfcomm_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; // Clear flag + pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, rfcomm_scid); + l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST; + } + break; + case L2CAP_RFCOMM_REQUEST: + if (l2cap_config_request_rfcomm_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nRFCOMM Configuration Request")); + Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80); #endif - pBtd->l2cap_config_response(hci_handle,identifier, rfcomm_scid); - l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS; - } - break; - case L2CAP_RFCOMM_SUCCESS: - if (l2cap_config_success_rfcomm_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; // Clear flag + pBtd->l2cap_config_response(hci_handle, identifier, rfcomm_scid); + l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS; + } + break; + case L2CAP_RFCOMM_SUCCESS: + if (l2cap_config_success_rfcomm_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; // Clear flag #ifdef DEBUG - Notify(PSTR("\r\nRFCOMM Successfully Configured")); -#endif - rfcommAvailable = 0; // Reset number of bytes available - bytesRead = 0; // Reset number of bytes received - RFCOMMConnected = true; - l2cap_rfcomm_state = L2CAP_RFCOMM_DONE; - } - break; - case L2CAP_RFCOMM_DONE: - if(l2cap_disconnect_request_rfcomm_flag) { - l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; // Clear flag - RFCOMMConnected = false; - connected = false; -#ifdef DEBUG - Notify(PSTR("\r\nDisconnected RFCOMM Channel")); + Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80); #endif - pBtd->l2cap_disconnection_response(hci_handle,identifier,rfcomm_dcid,rfcomm_scid); - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; - } else if(l2cap_connection_request_rfcomm_flag) - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; - break; - } + rfcommAvailable = 0; // Reset number of bytes available + bytesRead = 0; // Reset number of bytes received + RFCOMMConnected = true; + l2cap_rfcomm_state = L2CAP_RFCOMM_DONE; + } + break; + case L2CAP_RFCOMM_DONE: + if (l2cap_disconnect_request_rfcomm_flag) { + l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; // Clear flag + RFCOMMConnected = false; + connected = false; +#ifdef DEBUG + Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80); +#endif + pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid); + l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; + } else if (l2cap_connection_request_rfcomm_flag) + l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; + break; + } } /************************************************************/ /* SDP Commands */ + /************************************************************/ void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs - pBtd->L2CAP_Command(hci_handle,data,nbytes,sdp_scid[0],sdp_scid[1]); + pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]); } + void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; - l2capoutbuf[1] = transactionIDHigh; - l2capoutbuf[2] = transactionIDLow; - l2capoutbuf[3] = 0x00; // Parameter Length - l2capoutbuf[4] = 0x05; // Parameter Length - l2capoutbuf[5] = 0x00; // AttributeListsByteCount - l2capoutbuf[6] = 0x02; // AttributeListsByteCount - - /* Attribute ID/Value Sequence: */ - l2capoutbuf[7] = 0x35; - l2capoutbuf[8] = 0x00; - l2capoutbuf[9] = 0x00; - - SDP_Command(l2capoutbuf,10); + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[1] = transactionIDHigh; + l2capoutbuf[2] = transactionIDLow; + l2capoutbuf[3] = 0x00; // Parameter Length + l2capoutbuf[4] = 0x05; // Parameter Length + l2capoutbuf[5] = 0x00; // AttributeListsByteCount + l2capoutbuf[6] = 0x02; // AttributeListsByteCount + + /* Attribute ID/Value Sequence: */ + l2capoutbuf[7] = 0x35; + l2capoutbuf[8] = 0x00; + l2capoutbuf[9] = 0x00; + + SDP_Command(l2capoutbuf, 10); } + void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; - l2capoutbuf[1] = transactionIDHigh; - l2capoutbuf[2] = transactionIDLow; - l2capoutbuf[3] = 0x00; // Parameter Length - l2capoutbuf[4] = 0x2B; // Parameter Length - l2capoutbuf[5] = 0x00; // AttributeListsByteCount - l2capoutbuf[6] = 0x26; // AttributeListsByteCount + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[1] = transactionIDHigh; + l2capoutbuf[2] = transactionIDLow; + l2capoutbuf[3] = 0x00; // Parameter Length + l2capoutbuf[4] = 0x2B; // Parameter Length + l2capoutbuf[5] = 0x00; // AttributeListsByteCount + l2capoutbuf[6] = 0x26; // AttributeListsByteCount - /* Attribute ID/Value Sequence: */ - l2capoutbuf[7] = 0x36; - l2capoutbuf[8] = 0x00; - l2capoutbuf[9] = 0x3C; - l2capoutbuf[10] = 0x36; - l2capoutbuf[11] = 0x00; - - l2capoutbuf[12] = 0x39; - l2capoutbuf[13] = 0x09; - l2capoutbuf[14] = 0x00; - l2capoutbuf[15] = 0x00; - l2capoutbuf[16] = 0x0A; - l2capoutbuf[17] = 0x00; - l2capoutbuf[18] = 0x01; - l2capoutbuf[19] = 0x00; - l2capoutbuf[20] = 0x06; - l2capoutbuf[21] = 0x09; - l2capoutbuf[22] = 0x00; - l2capoutbuf[23] = 0x01; - l2capoutbuf[24] = 0x35; - l2capoutbuf[25] = 0x03; - l2capoutbuf[26] = 0x19; - l2capoutbuf[27] = 0x11; - - l2capoutbuf[28] = 0x01; - l2capoutbuf[29] = 0x09; - l2capoutbuf[30] = 0x00; - l2capoutbuf[31] = 0x04; - l2capoutbuf[32] = 0x35; - l2capoutbuf[33] = 0x0C; - l2capoutbuf[34] = 0x35; - l2capoutbuf[35] = 0x03; - l2capoutbuf[36] = 0x19; - l2capoutbuf[37] = 0x01; - l2capoutbuf[38] = 0x00; - l2capoutbuf[39] = 0x35; - l2capoutbuf[40] = 0x05; - l2capoutbuf[41] = 0x19; - l2capoutbuf[42] = 0x00; - l2capoutbuf[43] = 0x03; - - l2capoutbuf[44] = 0x08; - l2capoutbuf[45] = 0x02; // Two extra bytes - l2capoutbuf[46] = 0x00; // 25 (0x19) more bytes to come - l2capoutbuf[47] = 0x19; - - SDP_Command(l2capoutbuf,48); + /* Attribute ID/Value Sequence: */ + l2capoutbuf[7] = 0x36; + l2capoutbuf[8] = 0x00; + l2capoutbuf[9] = 0x3C; + l2capoutbuf[10] = 0x36; + l2capoutbuf[11] = 0x00; + + l2capoutbuf[12] = 0x39; + l2capoutbuf[13] = 0x09; + l2capoutbuf[14] = 0x00; + l2capoutbuf[15] = 0x00; + l2capoutbuf[16] = 0x0A; + l2capoutbuf[17] = 0x00; + l2capoutbuf[18] = 0x01; + l2capoutbuf[19] = 0x00; + l2capoutbuf[20] = 0x06; + l2capoutbuf[21] = 0x09; + l2capoutbuf[22] = 0x00; + l2capoutbuf[23] = 0x01; + l2capoutbuf[24] = 0x35; + l2capoutbuf[25] = 0x03; + l2capoutbuf[26] = 0x19; + l2capoutbuf[27] = 0x11; + + l2capoutbuf[28] = 0x01; + l2capoutbuf[29] = 0x09; + l2capoutbuf[30] = 0x00; + l2capoutbuf[31] = 0x04; + l2capoutbuf[32] = 0x35; + l2capoutbuf[33] = 0x0C; + l2capoutbuf[34] = 0x35; + l2capoutbuf[35] = 0x03; + l2capoutbuf[36] = 0x19; + l2capoutbuf[37] = 0x01; + l2capoutbuf[38] = 0x00; + l2capoutbuf[39] = 0x35; + l2capoutbuf[40] = 0x05; + l2capoutbuf[41] = 0x19; + l2capoutbuf[42] = 0x00; + l2capoutbuf[43] = 0x03; + + l2capoutbuf[44] = 0x08; + l2capoutbuf[45] = 0x02; // Two extra bytes + l2capoutbuf[46] = 0x00; // 25 (0x19) more bytes to come + l2capoutbuf[47] = 0x19; + + SDP_Command(l2capoutbuf, 48); } + void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; - l2capoutbuf[1] = transactionIDHigh; - l2capoutbuf[2] = transactionIDLow; - l2capoutbuf[3] = 0x00; // Parameter Length - l2capoutbuf[4] = 0x1C; // Parameter Length - l2capoutbuf[5] = 0x00; // AttributeListsByteCount - l2capoutbuf[6] = 0x19; // AttributeListsByteCount - - /* Attribute ID/Value Sequence: */ - l2capoutbuf[7] = 0x01; - l2capoutbuf[8] = 0x09; - l2capoutbuf[9] = 0x00; - l2capoutbuf[10] = 0x06; - l2capoutbuf[11] = 0x35; - - l2capoutbuf[12] = 0x09; - l2capoutbuf[13] = 0x09; - l2capoutbuf[14] = 0x65; - l2capoutbuf[15] = 0x6E; - l2capoutbuf[16] = 0x09; - l2capoutbuf[17] = 0x00; - l2capoutbuf[18] = 0x6A; - l2capoutbuf[19] = 0x09; - l2capoutbuf[20] = 0x01; - l2capoutbuf[21] = 0x00; - l2capoutbuf[22] = 0x09; - l2capoutbuf[23] = 0x01; - l2capoutbuf[24] = 0x00; - l2capoutbuf[25] = 0x25; + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[1] = transactionIDHigh; + l2capoutbuf[2] = transactionIDLow; + l2capoutbuf[3] = 0x00; // Parameter Length + l2capoutbuf[4] = 0x1C; // Parameter Length + l2capoutbuf[5] = 0x00; // AttributeListsByteCount + l2capoutbuf[6] = 0x19; // AttributeListsByteCount - l2capoutbuf[26] = 0x05; // Name length - l2capoutbuf[27] = 'T'; - l2capoutbuf[28] = 'K'; - l2capoutbuf[29] = 'J'; - l2capoutbuf[30] = 'S'; - l2capoutbuf[31] = 'P'; - l2capoutbuf[32] = 0x00; // No more data + /* Attribute ID/Value Sequence: */ + l2capoutbuf[7] = 0x01; + l2capoutbuf[8] = 0x09; + l2capoutbuf[9] = 0x00; + l2capoutbuf[10] = 0x06; + l2capoutbuf[11] = 0x35; - SDP_Command(l2capoutbuf,33); + l2capoutbuf[12] = 0x09; + l2capoutbuf[13] = 0x09; + l2capoutbuf[14] = 0x65; + l2capoutbuf[15] = 0x6E; + l2capoutbuf[16] = 0x09; + l2capoutbuf[17] = 0x00; + l2capoutbuf[18] = 0x6A; + l2capoutbuf[19] = 0x09; + l2capoutbuf[20] = 0x01; + l2capoutbuf[21] = 0x00; + l2capoutbuf[22] = 0x09; + l2capoutbuf[23] = 0x01; + l2capoutbuf[24] = 0x00; + l2capoutbuf[25] = 0x25; + + l2capoutbuf[26] = 0x05; // Name length + l2capoutbuf[27] = 'T'; + l2capoutbuf[28] = 'K'; + l2capoutbuf[29] = 'J'; + l2capoutbuf[30] = 'S'; + l2capoutbuf[31] = 'P'; + l2capoutbuf[32] = 0x00; // No more data + + SDP_Command(l2capoutbuf, 33); } + void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - serialPortResponse1(transactionIDHigh,transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again + serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again } + void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - serialPortResponse2(transactionIDHigh,transactionIDLow); // Same data as serialPortResponse2 + serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2 } /************************************************************/ /* RFCOMM Commands */ + /************************************************************/ void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) { - pBtd->L2CAP_Command(hci_handle,data,nbytes,rfcomm_scid[0],rfcomm_scid[1]); + pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]); } void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) { - l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address - l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control - l2capoutbuf[2] = length << 1 | 0x01; // Length and format (allways 0x01 bytes format) - uint8_t i = 0; - for(; i < length; i++) - l2capoutbuf[i+3] = data[i]; - l2capoutbuf[i+3] = calcFcs(l2capoutbuf); + l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address + l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control + l2capoutbuf[2] = length << 1 | 0x01; // Length and format (allways 0x01 bytes format) + uint8_t i = 0; + for (; i < length; i++) + l2capoutbuf[i + 3] = data[i]; + l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); #ifdef EXTRADEBUG - Notify(PSTR(" - RFCOMM Data: ")); - for(i = 0; i < length+4; i++) { - Serial.print(l2capoutbuf[i],HEX); - Notify(PSTR(" ")); - } -#endif - RFCOMM_Command(l2capoutbuf,length+4); -} + Notify(PSTR(" - RFCOMM Data: "), 0x80); + for (i = 0; i < length + 4; i++) { + Serial.print(l2capoutbuf[i], HEX); + Notify(PSTR(" "), 0x80); + } +#endif + RFCOMM_Command(l2capoutbuf, length + 4); +} void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) { - l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address - l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control - l2capoutbuf[2] = 0x01; // Length = 0 - l2capoutbuf[3] = credit; // Credit - l2capoutbuf[4] = calcFcs(l2capoutbuf); + l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address + l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control + l2capoutbuf[2] = 0x01; // Length = 0 + l2capoutbuf[3] = credit; // Credit + l2capoutbuf[4] = calcFcs(l2capoutbuf); #ifdef EXTRADEBUG - Notify(PSTR(" - RFCOMM Credit Data: ")); - for(uint8_t i = 0; i < 5; i++) { - Serial.print(l2capoutbuf[i],HEX); - Notify(PSTR(" ")); - } + Notify(PSTR(" - RFCOMM Credit Data: "), 0x80); + for (uint8_t i = 0; i < 5; i++) { + Serial.print(l2capoutbuf[i], HEX); + Notify(PSTR(" "), 0x80); + } #endif - RFCOMM_Command(l2capoutbuf,5); + RFCOMM_Command(l2capoutbuf, 5); } /* CRC on 2 bytes */ uint8_t SPP::__crc(uint8_t* data) { - return(pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xff ^ data[0]]) ^ data[1]])); + return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xff ^ data[0]]) ^ data[1]])); } /* Calculate FCS - we never actually check if the host sends correct FCS to the Arduino */ uint8_t SPP::calcFcs(uint8_t *data) { - if((data[1] & 0xEF) == RFCOMM_UIH) - return (0xff - __crc(data)); // FCS on 2 bytes - else - return (0xff - pgm_read_byte(&rfcomm_crc_table[__crc(data) ^ data[2]])); // FCS on 3 bytes + if ((data[1] & 0xEF) == RFCOMM_UIH) + return (0xff - __crc(data)); // FCS on 2 bytes + else + return (0xff - pgm_read_byte(&rfcomm_crc_table[__crc(data) ^ data[2]])); // FCS on 3 bytes } /* Serial commands */ void SPP::print(const String &str) { - if(!connected) - return; - uint8_t length = str.length(); - if(length > (sizeof(l2capoutbuf)-4)) - length = sizeof(l2capoutbuf)-4; - l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address - l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control - l2capoutbuf[2] = length << 1 | 1; // Length - uint8_t i = 0; - for(; i < length; i++) - l2capoutbuf[i+3] = str[i]; - l2capoutbuf[i+3] = calcFcs(l2capoutbuf); - - RFCOMM_Command(l2capoutbuf,length+4); + if (!connected) + return; + uint8_t length = str.length(); + if (length > (sizeof (l2capoutbuf) - 4)) + length = sizeof (l2capoutbuf) - 4; + l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; + ; // RFCOMM Address + l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control + l2capoutbuf[2] = length << 1 | 1; // Length + uint8_t i = 0; + for (; i < length; i++) + l2capoutbuf[i + 3] = str[i]; + l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); + + RFCOMM_Command(l2capoutbuf, length + 4); } + void SPP::print(const char* str) { - if(!connected) - return; - uint8_t length = strlen(str); - if(length > (sizeof(l2capoutbuf)-4)) - length = sizeof(l2capoutbuf)-4; - l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address - l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control - l2capoutbuf[2] = length << 1 | 1; // Length - uint8_t i = 0; - for(; i < length; i++) - l2capoutbuf[i+3] = str[i]; - l2capoutbuf[i+3] = calcFcs(l2capoutbuf); - - RFCOMM_Command(l2capoutbuf,length+4); + if (!connected) + return; + uint8_t length = strlen(str); + if (length > (sizeof (l2capoutbuf) - 4)) + length = sizeof (l2capoutbuf) - 4; + l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; + ; // RFCOMM Address + l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control + l2capoutbuf[2] = length << 1 | 1; // Length + uint8_t i = 0; + for (; i < length; i++) + l2capoutbuf[i + 3] = str[i]; + l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); + + RFCOMM_Command(l2capoutbuf, length + 4); } + void SPP::print(uint8_t* array, uint8_t length) { - if(!connected) - return; - if(length > (sizeof(l2capoutbuf)-4)) - length = sizeof(l2capoutbuf)-4; - l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress;; // RFCOMM Address - l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control - l2capoutbuf[2] = length << 1 | 1; // Length - uint8_t i = 0; - for(; i < length; i++) - l2capoutbuf[i+3] = array[i]; - l2capoutbuf[i+3] = calcFcs(l2capoutbuf); - - RFCOMM_Command(l2capoutbuf,length+4); + if (!connected) + return; + if (length > (sizeof (l2capoutbuf) - 4)) + length = sizeof (l2capoutbuf) - 4; + l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; + ; // RFCOMM Address + l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control + l2capoutbuf[2] = length << 1 | 1; // Length + uint8_t i = 0; + for (; i < length; i++) + l2capoutbuf[i + 3] = array[i]; + l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); + + RFCOMM_Command(l2capoutbuf, length + 4); } + void SPP::println(const String &str) { - String output = str + "\r\n"; - print(output); + String output = str + "\r\n"; + print(output); } + void SPP::println(const char* str) { - char output[strlen(str)+3]; - strcpy(output,str); - strcat(output,"\r\n"); - print(output); + char output[strlen(str) + 3]; + strcpy(output, str); + strcat(output, "\r\n"); + print(output); } + void SPP::println(uint8_t data) { - uint8_t buf[3] = {data, '\r', '\n'}; - print(buf,3); + uint8_t buf[3] = {data, '\r', '\n'}; + print(buf, 3); } + void SPP::println(uint8_t* array, uint8_t length) { - uint8_t buf[length+2]; - memcpy(buf,array,length); - buf[length] = '\r'; - buf[length+1] = '\n'; - print(buf,length+2); + uint8_t buf[length + 2]; + memcpy(buf, array, length); + buf[length] = '\r'; + buf[length + 1] = '\n'; + print(buf, length + 2); } + void SPP::printFlashString(const __FlashStringHelper *ifsh, bool newline) { - const char PROGMEM *p = (const char PROGMEM *)ifsh; - uint8_t size = 0; - while (1) { // Calculate the size of the string - uint8_t c = pgm_read_byte(p+size); - if (c == 0) - break; - size++; - } - uint8_t buf[size+2]; // Add two extra in case it needs to print a newline and carriage return - - for(uint8_t i = 0; i < size; i++) - buf[i] = pgm_read_byte(p++); - - if(newline) { - buf[size] = '\r'; - buf[size+1] = '\n'; - print(buf,size+2); - } else - print(buf,size); + const char PROGMEM *p = (const char PROGMEM *)ifsh; + uint8_t size = 0; + while (1) { // Calculate the size of the string + uint8_t c = pgm_read_byte(p + size); + if (c == 0) + break; + size++; + } + uint8_t buf[size + 2]; // Add two extra in case it needs to print a newline and carriage return + + for (uint8_t i = 0; i < size; i++) + buf[i] = pgm_read_byte(p++); + + if (newline) { + buf[size] = '\r'; + buf[size + 1] = '\n'; + print(buf, size + 2); + } else + print(buf, size); } + void SPP::println(void) { - uint8_t buf[2] = {'\r','\n'}; - print(buf,2); + uint8_t buf[2] = {'\r', '\n'}; + print(buf, 2); } /* These must be used to print numbers */ void SPP::printNumber(uint32_t n) { - char output[11]; - intToString(n,output); - print(output); + char output[11]; + intToString(n, output); + print(output); } + void SPP::printNumberln(uint32_t n) { - char output[13]; - intToString(n,output); - strcat(output,"\r\n"); - print(output); + char output[13]; + intToString(n, output); + strcat(output, "\r\n"); + print(output); } + void SPP::printNumber(int32_t n) { - char output[12]; - intToString(n,output); - print(output); + char output[12]; + intToString(n, output); + print(output); } + void SPP::printNumberln(int32_t n) { - char output[14]; - intToString(n,output); - strcat(output,"\r\n"); - print(output); + char output[14]; + intToString(n, output); + strcat(output, "\r\n"); + print(output); } + void SPP::intToString(int32_t input, char* output) { - if(input < 0) { - char buf[11]; - intToString((uint32_t)(input*-1),buf); - strcpy(output,"-"); - strcat(output,buf); - } else - intToString((uint32_t)input,output); + if (input < 0) { + char buf[11]; + intToString((uint32_t)(input*-1), buf); + strcpy(output, "-"); + strcat(output, buf); + } else + intToString((uint32_t)input, output); } + void SPP::intToString(uint32_t input, char* output) { - uint32_t temp = input; - uint8_t digits = 0; - while(temp) { - temp /= 10; - digits++; - } - if(digits == 0) - strcpy(output,"0"); - else { - for(uint8_t i = 1; i <= digits; i++) { - output[digits-i] = input%10 + '0'; // Get number and convert to ASCII Character - input /= 10; + uint32_t temp = input; + uint8_t digits = 0; + while (temp) { + temp /= 10; + digits++; + } + if (digits == 0) + strcpy(output, "0"); + else { + for (uint8_t i = 1; i <= digits; i++) { + output[digits - i] = input % 10 + '0'; // Get number and convert to ASCII Character + input /= 10; + } + output[digits] = '\0'; // Add null character } - output[digits] = '\0'; // Add null character - } } void SPP::printNumber(double n, uint8_t digits) { - char output[13+digits]; - doubleToString(n,output,digits); - print(output); + char output[13 + digits]; + doubleToString(n, output, digits); + print(output); } + void SPP::printNumberln(double n, uint8_t digits) { - char output[15+digits]; - doubleToString(n,output,digits); - strcat(output,"\r\n"); - print(output); + char output[15 + digits]; + doubleToString(n, output, digits); + strcat(output, "\r\n"); + print(output); } + void SPP::doubleToString(double input, char* output, uint8_t digits) { - char buffer[13+digits]; - if(input < 0) { - strcpy(output,"-"); - input = -input; - } - else - strcpy(output,""); - - // Round correctly - double rounding = 0.5; - for (uint8_t i=0; i (sizeof(rfcommDataBuffer)-5)) { // We will send the command just before it runs out of credit - bytesRead = 0; - sendRfcommCredit(rfcommChannelConnection,rfcommDirection,0,RFCOMM_UIH,0x10,sizeof(rfcommDataBuffer)); // Send more credit + if (rfcommAvailable == 0) // Don't read if there is nothing in the buffer + return 0; + uint8_t output = rfcommDataBuffer[0]; + for (uint8_t i = 1; i < rfcommAvailable; i++) + rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left + rfcommAvailable--; + bytesRead++; + if (bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit + bytesRead = 0; + sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit #ifdef EXTRADEBUG - Notify(PSTR("\r\nSent ")); - Serial.print(sizeof(rfcommDataBuffer)); - Notify(PSTR(" more credit")); + Notify(PSTR("\r\nSent "), 0x80); + Serial.print(sizeof (rfcommDataBuffer)); + Notify(PSTR(" more credit"), 0x80); #endif - } - return output; + } + return output; } \ No newline at end of file diff --git a/SPP.h b/SPP.h index 070add5b..61a5a4c2 100644 --- a/SPP.h +++ b/SPP.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -70,7 +70,7 @@ #define extendAddress 0x01 // Allways 1 -// Multiplexer message types +// Multiplexer message types #define BT_RFCOMM_PN_CMD 0x83 #define BT_RFCOMM_PN_RSP 0x81 #define BT_RFCOMM_MSC_CMD 0xE3 @@ -87,276 +87,310 @@ #define BT_RFCOMM_RLS_CMD 0x53 #define BT_RFCOMM_RLS_RSP 0x51 #define BT_RFCOMM_NSC_RSP 0x11 -*/ + */ /** This BluetoothService class implements the Serial Port Protocol (SPP). */ class SPP : public BluetoothService { public: - /** - * Constructor for the SPP class. - * @param p Pointer to BTD class instance. - * @param name Set the name to BTD#btdName. If argument is omitted, then "Arduino" will be used. - * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used. - */ - SPP(BTD *p, const char* name = "Arduino", const char* pin = "1234"); + /** + * Constructor for the SPP class. + * @param p Pointer to BTD class instance. + * @param name Set the name to BTD#btdName. If argument is omitted, then "Arduino" will be used. + * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used. + */ + SPP(BTD *p, const char* name = "Arduino", const char* pin = "1234"); - /** @name BluetoothService implementation */ - /** - * Used to pass acldata to the services. - * @param ACLData Incoming acldata. - */ - virtual void ACLData(uint8_t* ACLData); - /** Used to establish the connection automatically. */ - virtual void Run(); - /** Use this to reset the service. */ - virtual void Reset(); - /** Used this to disconnect the virtual serial port. */ - virtual void disconnect(); - /**@}*/ - - /** Variable used to indicate if the connection is established. */ - bool connected; - - /** @name Serial port profile (SPP) Print functions */ - /** - * Used to send Arduino String data type. - * @param str String to send. - */ - void print(const String &str); - /** - * Same as print(const String &str), but will include newline and carriage return. - * @param str String to send. - */ - void println(const String &str); - - /** - * Used to send standard strings. - * @param str String to send. - */ - void print(const char* str); - /** - * Same as print(const char* str), but will include newline and carriage return. - * @param str String to send. - */ - void println(const char* str); + /** @name BluetoothService implementation */ + /** + * Used to pass acldata to the services. + * @param ACLData Incoming acldata. + */ + virtual void ACLData(uint8_t* ACLData); + /** Used to establish the connection automatically. */ + virtual void Run(); + /** Use this to reset the service. */ + virtual void Reset(); + /** Used this to disconnect the virtual serial port. */ + virtual void disconnect(); + /**@}*/ - /** - * Used to send single bytes. - * @param data Data to send. - */ - void print(uint8_t data) { print(&data,1); }; - /** - * Same as print(uint8_t data), but will include newline and carriage return. - * @param data Data to send. - */ - void println(uint8_t data); + /** Variable used to indicate if the connection is established. */ + bool connected; - /** - * Used to send arrays. - * @param array Array to send. - * @param length Number of bytes to send. - */ - void print(uint8_t* array, uint8_t length); - /** - * Same as print(uint8_t* array, uint8_t length), but will include newline and carriage return. - * @param array Array to send. - * @param length Number of bytes to send. - */ - void println(uint8_t* array, uint8_t length); + /** @name Serial port profile (SPP) Print functions */ + /** + * Used to send Arduino String data type. + * @param str String to send. + */ + void print(const String &str); + /** + * Same as print(const String &str), but will include newline and carriage return. + * @param str String to send. + */ + void println(const String &str); - /** - * Used to print strings stored in flash. - * Use "SerialBT.print(F("String"));" to print a string stored in flash. - * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. - */ - void print(const __FlashStringHelper *ifsh) { printFlashString(ifsh,false); }; - /** - * Same as print(const __FlashStringHelper *ifsh), but will include newline and carriage return. - * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. - */ - void println(const __FlashStringHelper *ifsh) { printFlashString(ifsh,true); }; - /** - * Helper function to print a string stored in flash. - * @param ifsh String stored in flash you want to print. - * @param newline Set this to true to include newline and carriage return. - */ - void printFlashString(const __FlashStringHelper *ifsh, bool newline); + /** + * Used to send standard strings. + * @param str String to send. + */ + void print(const char* str); + /** + * Same as print(const char* str), but will include newline and carriage return. + * @param str String to send. + */ + void println(const char* str); + + /** + * Used to send single bytes. + * @param data Data to send. + */ + void print(uint8_t data) { + print(&data, 1); + }; + /** + * Same as print(uint8_t data), but will include newline and carriage return. + * @param data Data to send. + */ + void println(uint8_t data); + + /** + * Used to send arrays. + * @param array Array to send. + * @param length Number of bytes to send. + */ + void print(uint8_t* array, uint8_t length); + /** + * Same as print(uint8_t* array, uint8_t length), but will include newline and carriage return. + * @param array Array to send. + * @param length Number of bytes to send. + */ + void println(uint8_t* array, uint8_t length); + + /** + * Used to print strings stored in flash. + * Use "SerialBT.print(F("String"));" to print a string stored in flash. + * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. + */ + void print(const __FlashStringHelper *ifsh) { + printFlashString(ifsh, false); + }; + + /** + * Same as print(const __FlashStringHelper *ifsh), but will include newline and carriage return. + * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. + */ + void println(const __FlashStringHelper *ifsh) { + printFlashString(ifsh, true); + }; + /** + * Helper function to print a string stored in flash. + * @param ifsh String stored in flash you want to print. + * @param newline Set this to true to include newline and carriage return. + */ + void printFlashString(const __FlashStringHelper *ifsh, bool newline); - /** Use this to print newline and carriage return. */ - void println(void); + /** Use this to print newline and carriage return. */ + void println(void); - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint8_t n) { printNumber((uint32_t)n); }; - /** - * Same as printNumber(uint8_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint8_t n) { printNumberln((uint32_t)n); }; - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int8_t n) { printNumber((int32_t)n); }; - /** - * Same as printNumber(int8_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int8_t n) { printNumberln((int32_t)n); }; + /** + * Used to print unsigned integers. + * @param n Unsigned integer to send. + */ + void printNumber(uint8_t n) { + printNumber((uint32_t) n); + }; - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint16_t n) { printNumber((uint32_t)n); }; - /** - * Same as printNumber(uint16_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint16_t n) { printNumberln((uint32_t)n); }; - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int16_t n) { printNumber((int32_t)n); }; - /** - * Same as printNumber(int16_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int16_t n) { printNumberln((int32_t)n); }; + /** + * Same as printNumber(uint8_t n), but will include newline and carriage return. + * @param n Unsigned integer to send. + */ + void printNumberln(uint8_t n) { + printNumberln((uint32_t) n); + }; - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint32_t n); - /** - * Same as printNumber(uint32_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint32_t n); - - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int32_t n); - /** - * Same as printNumber(int32_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int32_t n); + /** + * Used to print signed integers. + * @param n Signed integer to send. + */ + void printNumber(int8_t n) { + printNumber((int32_t) n); + }; - /** - * Helper function to convert from an unsigned integer to a string. - * @param input Unsigned integer to convert. - * @param output Output buffer. - */ - void intToString(int32_t input, char* output); - /** - * Helper function to convert from a signed integer to a string. - * @param input Signed integer to convert. - * @param output Output buffer. - */ - void intToString(uint32_t input, char* output); + /** + * Same as printNumber(int8_t n), but will include newline and carriage return. + * @param n Signed integer to send. + */ + void printNumberln(int8_t n) { + printNumberln((int32_t) n); + }; + + /** + * Used to print unsigned integers. + * @param n Unsigned integer to send. + */ + void printNumber(uint16_t n) { + printNumber((uint32_t) n); + }; + + /** + * Same as printNumber(uint16_t n), but will include newline and carriage return. + * @param n Unsigned integer to send. + */ + void printNumberln(uint16_t n) { + printNumberln((uint32_t) n); + }; + + /** + * Used to print signed integers. + * @param n Signed integer to send. + */ + void printNumber(int16_t n) { + printNumber((int32_t) n); + }; + + /** + * Same as printNumber(int16_t n), but will include newline and carriage return. + * @param n Signed integer to send. + */ + void printNumberln(int16_t n) { + printNumberln((int32_t) n); + }; + + /** + * Used to print unsigned integers. + * @param n Unsigned integer to send. + */ + void printNumber(uint32_t n); + /** + * Same as printNumber(uint32_t n), but will include newline and carriage return. + * @param n Unsigned integer to send. + */ + void printNumberln(uint32_t n); + + /** + * Used to print signed integers. + * @param n Signed integer to send. + */ + void printNumber(int32_t n); + /** + * Same as printNumber(int32_t n), but will include newline and carriage return. + * @param n Signed integer to send. + */ + void printNumberln(int32_t n); + + /** + * Helper function to convert from an unsigned integer to a string. + * @param input Unsigned integer to convert. + * @param output Output buffer. + */ + void intToString(int32_t input, char* output); + /** + * Helper function to convert from a signed integer to a string. + * @param input Signed integer to convert. + * @param output Output buffer. + */ + void intToString(uint32_t input, char* output); + + /** + * Used to print floating-point numbers. + * @param n Floating-point number to print. + * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. + */ + void printNumber(double n, uint8_t digits = 2); + /** + * Same as printNumber(double n, uint8_t digits), but will include newline and carriage return. + * @param n Floating-point number to print. + * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. + */ + void printNumberln(double n, uint8_t digits = 2); + /** + * Helper function to convert from a double to a string. + * @param input Floating-point number to convert. + * @param output Output buffer. + * @param digits Number of digits to convert. If argument is omitted, then 2 digits will be used. + */ + void doubleToString(double input, char* output, uint8_t digits = 2); + + /** + * Get number of bytes waiting to be read. + * @return Return the number of bytes ready to be read. + */ + uint8_t available() { + return rfcommAvailable; + }; + /** + * Used to read the buffer. + * @return Return the byte. Will return 0 if no byte is available. + */ + uint8_t read(); + + /** Discard all the bytes in the buffer. */ + void flush() { + rfcommAvailable = 0; + }; + /**@}*/ - /** - * Used to print floating-point numbers. - * @param n Floating-point number to print. - * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. - */ - void printNumber(double n, uint8_t digits = 2); - /** - * Same as printNumber(double n, uint8_t digits), but will include newline and carriage return. - * @param n Floating-point number to print. - * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. - */ - void printNumberln(double n, uint8_t digits = 2); - /** - * Helper function to convert from a double to a string. - * @param input Floating-point number to convert. - * @param output Output buffer. - * @param digits Number of digits to convert. If argument is omitted, then 2 digits will be used. - */ - void doubleToString(double input, char* output, uint8_t digits = 2); - - /** - * Get number of bytes waiting to be read. - * @return Return the number of bytes ready to be read. - */ - uint8_t available() { return rfcommAvailable; }; - /** - * Used to read the buffer. - * @return Return the byte. Will return 0 if no byte is available. - */ - uint8_t read(); - /** Discard all the bytes in the buffer. */ - void flush() { rfcommAvailable = 0; }; - /**@}*/ - private: - /* Bluetooth dongle library pointer */ - BTD *pBtd; - - /* Set true when a channel is created */ - bool SDPConnected; - bool RFCOMMConnected; - - uint16_t hci_handle; // The HCI Handle for the connection - - /* Variables used by L2CAP state maschines */ - uint8_t l2cap_sdp_state; - uint8_t l2cap_rfcomm_state; - uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events - - uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data - uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands - - /* L2CAP Channels */ - uint8_t sdp_scid[2]; // L2CAP source CID for SDP - uint8_t sdp_dcid[2]; // 0x0050 - uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM - uint8_t rfcomm_dcid[2]; // 0x0051 - uint8_t identifier; // Identifier for command + /* Bluetooth dongle library pointer */ + BTD *pBtd; - /* RFCOMM Variables */ - uint8_t rfcommChannel; - uint8_t rfcommChannelConnection; // This is the channel the SPP chanel will be running at - uint8_t rfcommDirection; - uint8_t rfcommCommandResponse; - uint8_t rfcommChannelType; - uint8_t rfcommPfBit; - - unsigned long timer; - bool waitForLastCommand; - bool creditSent; - - uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data - uint8_t rfcommAvailable; - - bool firstMessage; // Used to see if it's the first SDP request received - uint8_t bytesRead; // Counter to see when it's time to send more credit - - /* State machines */ - void SDP_task(); // SDP state machine - void RFCOMM_task(); // RFCOMM state machine - - /* SDP Commands */ - void SDP_Command(uint8_t* data, uint8_t nbytes); - void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow); - void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow); - void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow); - void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow); - void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow); - - /* RFCOMM Commands */ - void RFCOMM_Command(uint8_t* data, uint8_t nbytes); - void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length); - void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit); - uint8_t calcFcs(uint8_t *data); - uint8_t __crc(uint8_t* data); + /* Set true when a channel is created */ + bool SDPConnected; + bool RFCOMMConnected; + + uint16_t hci_handle; // The HCI Handle for the connection + + /* Variables used by L2CAP state maschines */ + uint8_t l2cap_sdp_state; + uint8_t l2cap_rfcomm_state; + uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events + + uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data + uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands + + /* L2CAP Channels */ + uint8_t sdp_scid[2]; // L2CAP source CID for SDP + uint8_t sdp_dcid[2]; // 0x0050 + uint8_t rfcomm_scid[2]; // L2CAP source CID for RFCOMM + uint8_t rfcomm_dcid[2]; // 0x0051 + uint8_t identifier; // Identifier for command + + /* RFCOMM Variables */ + uint8_t rfcommChannel; + uint8_t rfcommChannelConnection; // This is the channel the SPP chanel will be running at + uint8_t rfcommDirection; + uint8_t rfcommCommandResponse; + uint8_t rfcommChannelType; + uint8_t rfcommPfBit; + + unsigned long timer; + bool waitForLastCommand; + bool creditSent; + + uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data + uint8_t rfcommAvailable; + + bool firstMessage; // Used to see if it's the first SDP request received + uint8_t bytesRead; // Counter to see when it's time to send more credit + + /* State machines */ + void SDP_task(); // SDP state machine + void RFCOMM_task(); // RFCOMM state machine + + /* SDP Commands */ + void SDP_Command(uint8_t* data, uint8_t nbytes); + void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow); + void serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow); + void serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow); + void l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow); + void l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow); + + /* RFCOMM Commands */ + void RFCOMM_Command(uint8_t* data, uint8_t nbytes); + void sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length); + void sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit); + uint8_t calcFcs(uint8_t *data); + uint8_t __crc(uint8_t* data); }; #endif \ No newline at end of file diff --git a/Usb.cpp b/Usb.cpp index 08e017c6..ec273f43 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* USB functions */ #include "avrpins.h" @@ -31,611 +31,587 @@ static uint8_t usb_error = 0; static uint8_t usb_task_state; /* constructor */ -USB::USB () : bmHubPre(0) -{ - usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine - init(); +USB::USB() : bmHubPre(0) { + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine + init(); } /* Initialize data structures */ -void USB::init() -{ - devConfigIndex = 0; - bmHubPre = 0; +void USB::init() { + devConfigIndex = 0; + bmHubPre = 0; } -uint8_t USB::getUsbTaskState( void ) -{ - return( usb_task_state ); +uint8_t USB::getUsbTaskState(void) { + return ( usb_task_state); } -void USB::setUsbTaskState( uint8_t state ) -{ - usb_task_state = state; -} +void USB::setUsbTaskState(uint8_t state) { + usb_task_state = state; +} -EpInfo* USB::getEpInfoEntry( uint8_t addr, uint8_t ep ) -{ - UsbDevice *p = addrPool.GetUsbDevicePtr(addr); +EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) { + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); - if (!p || !p->epinfo) - return NULL; + if (!p || !p->epinfo) + return NULL; - EpInfo *pep = p->epinfo; + EpInfo *pep = p->epinfo; - for (uint8_t i=0; iepcount; i++) - { - if ((pep)->epAddr == ep) - return pep; + for (uint8_t i = 0; i < p->epcount; i++) { + if ((pep)->epAddr == ep) + return pep; - pep ++; - } - return NULL; + pep++; + } + return NULL; } /* set device table entry */ + /* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */ -uint8_t USB::setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr ) -{ - if (!eprecord_ptr) - return USB_ERROR_INVALID_ARGUMENT; +uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) { + if (!eprecord_ptr) + return USB_ERROR_INVALID_ARGUMENT; - UsbDevice *p = addrPool.GetUsbDevicePtr(addr); + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->address = addr; - p->epinfo = eprecord_ptr; - p->epcount = epcount; + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - return 0; + p->address = addr; + p->epinfo = eprecord_ptr; + p->epcount = epcount; + + return 0; } -uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit) -{ - UsbDevice *p = addrPool.GetUsbDevicePtr(addr); +uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit) { + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - if (!p->epinfo) - return USB_ERROR_EPINFO_IS_NULL; + if (!p->epinfo) + return USB_ERROR_EPINFO_IS_NULL; - *ppep = getEpInfoEntry(addr, ep); + *ppep = getEpInfoEntry(addr, ep); - if (!*ppep) - return USB_ERROR_EP_NOT_FOUND_IN_TBL; + if (!*ppep) + return USB_ERROR_EP_NOT_FOUND_IN_TBL; - nak_limit = (0x0001UL << ( ( (*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower) ); - nak_limit--; - -/* - USBTRACE2("\r\nAddress: ", addr); - USBTRACE2(" EP: ", ep); - USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower); - USBTRACE2(" NAK Limit: ", nak_limit); - USBTRACE("\r\n"); -*/ - regWr( rPERADDR, addr ); //set peripheral address + nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower)); + nak_limit--; + /* + USBTRACE2("\r\nAddress: ", addr); + USBTRACE2(" EP: ", ep); + USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower); + USBTRACE2(" NAK Limit: ", nak_limit); + USBTRACE("\r\n"); + */ + regWr(rPERADDR, addr); //set peripheral address - uint8_t mode = regRd( rMODE ); + uint8_t mode = regRd(rMODE); - // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise - regWr( rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); + // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise + regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); - return 0; + return 0; } /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ /* depending on request. Actual requests are defined as inlines */ /* return codes: */ /* 00 = success */ + /* 01-0f = non-zero HRSLT */ -uint8_t USB::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) -{ - boolean direction = false; //request direction, IN or OUT - uint8_t rcode; - SETUP_PKT setup_pkt; +uint8_t USB::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) { + bool direction = false; //request direction, IN or OUT + uint8_t rcode; + SETUP_PKT setup_pkt; - EpInfo *pep = NULL; - uint16_t nak_limit; + EpInfo *pep = NULL; + uint16_t nak_limit; - rcode = SetAddress(addr, ep, &pep, nak_limit); + rcode = SetAddress(addr, ep, &pep, nak_limit); - if (rcode) - return rcode; + if (rcode) + return rcode; - direction = (( bmReqType & 0x80 ) > 0); + direction = ((bmReqType & 0x80) > 0); - /* fill in setup packet */ - setup_pkt.ReqType_u.bmRequestType = bmReqType; - setup_pkt.bRequest = bRequest; - setup_pkt.wVal_u.wValueLo = wValLo; - setup_pkt.wVal_u.wValueHi = wValHi; - setup_pkt.wIndex = wInd; - setup_pkt.wLength = total; - - bytesWr( rSUDFIFO, 8, (uint8_t*)&setup_pkt ); //transfer to setup packet FIFO + /* fill in setup packet */ + setup_pkt.ReqType_u.bmRequestType = bmReqType; + setup_pkt.bRequest = bRequest; + setup_pkt.wVal_u.wValueLo = wValLo; + setup_pkt.wVal_u.wValueHi = wValHi; + setup_pkt.wIndex = wInd; + setup_pkt.wLength = total; - rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet + bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO - if( rcode ) //return HRSLT if not zero - return( rcode ); + rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet - if( dataptr != NULL ) //data stage, if present - { - if( direction ) //IN transfer - { - uint16_t left = total; + if (rcode) //return HRSLT if not zero + return ( rcode); - pep->bmRcvToggle = 1; //bmRCVTOG1; + if (dataptr != NULL) //data stage, if present + { + if (direction) //IN transfer + { + uint16_t left = total; - while (left) - { - // Bytes read into buffer - uint16_t read = nbytes; - //uint16_t read = (leftbmRcvToggle = 1; //bmRCVTOG1; - rcode = InTransfer( pep, nak_limit, &read, dataptr ); + while (left) { + // Bytes read into buffer + uint16_t read = nbytes; + //uint16_t read = (leftParse( read, dataptr, total - left ); + if (rcode) + return rcode; - left -= read; + // Invoke callback function if inTransfer completed successfuly and callback function pointer is specified + if (!rcode && p) + ((USBReadParser*)p)->Parse(read, dataptr, total - left); - if (read < nbytes) - break; - } - } - else //OUT transfer - { - pep->bmSndToggle = 1; //bmSNDTOG1; - rcode = OutTransfer( pep, nak_limit, nbytes, dataptr ); - } - if( rcode ) //return error - return( rcode ); - } - // Status stage - return dispatchPkt( (direction) ? tokOUTHS : tokINHS, ep, nak_limit ); //GET if direction + left -= read; + + if (read < nbytes) + break; + } + } else //OUT transfer + { + pep->bmSndToggle = 1; //bmSNDTOG1; + rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); + } + if (rcode) //return error + return ( rcode); + } + // Status stage + return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction } /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ /* Keep sending INs and writes data to memory area pointed by 'data' */ + /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, fe USB xfer timeout */ -uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) -{ - EpInfo *pep = NULL; - uint16_t nak_limit = 0; +uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) { + EpInfo *pep = NULL; + uint16_t nak_limit = 0; - uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); + uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); - if (rcode) - return rcode; - - return InTransfer(pep, nak_limit, nbytesptr, data); + if (rcode) { + //printf("SetAddress Failed"); + return rcode; + } + return InTransfer(pep, nak_limit, nbytesptr, data); } -uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) -{ - uint8_t rcode = 0; - uint8_t pktsize; +uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) { + uint8_t rcode = 0; + uint8_t pktsize; - uint16_t nbytes = *nbytesptr; - uint8_t maxpktsize = pep->maxPktSize; + uint16_t nbytes = *nbytesptr; + //printf("Requesting %i bytes ", nbytes); + uint8_t maxpktsize = pep->maxPktSize; - *nbytesptr = 0; - regWr( rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0 ); //set toggle value + *nbytesptr = 0; + regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value - 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 ) - return( rcode ); //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 */ - if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) - return ( 0xf0 ); //receive error - - pktsize = regRd( rRCVBC ); //number of received bytes - - assert(pktsize <= nbytes); - - int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); + 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 (mem_left < 0) - mem_left = 0; + if (rcode) { + //printf("Problem! %i\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 */ + if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) { + //printf("Problem! NO RCVDAVIRQ!\r\n"); + rcode = 0xf0; //receive error + break; + } + pktsize = regRd(rRCVBC); //number of received bytes + //printf("Got %i bytes ", pktsize); + assert(pktsize <= nbytes); - data = bytesRd( rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data ); + int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); - regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer - *nbytesptr += pktsize; // add this packet's byte count to total transfer length + if (mem_left < 0) + mem_left = 0; - /* The transfer is complete under two conditions: */ - /* 1. The device sent a short packet (L.T. maxPacketSize) */ - /* 2. 'nbytes' have been transferred. */ - if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? - { - // Save toggle value - pep->bmRcvToggle = (( regRd( rHRSL ) & bmRCVTOGRD )) ? 1 : 0; + data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); - return( 0 ); - } // if - } //while( 1 ) + regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer + *nbytesptr += pktsize; // add this packet's byte count to total transfer length + + /* The transfer is complete under two conditions: */ + /* 1. The device sent a short packet (L.T. maxPacketSize) */ + /* 2. 'nbytes' have been transferred. */ + if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? + { + // Save toggle value + pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0; + //printf("\r\n"); + rcode = 0; + break; + } // if + } //while( 1 ) + return ( rcode); } /* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */ + /* 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; +uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) { + EpInfo *pep = NULL; + uint16_t nak_limit; - uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); + uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); - if (rcode) - return rcode; + if (rcode) + return rcode; - return OutTransfer(pep, nak_limit, nbytes, data); + return OutTransfer(pep, nak_limit, nbytes, data); } -uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) -{ - uint8_t rcode, retry_count; - uint8_t *data_p = data; //local copy of the data pointer - uint16_t bytes_tosend, nak_count; - uint16_t bytes_left = nbytes; +uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) { + uint8_t rcode = hrSUCCESS, retry_count; + uint8_t *data_p = data; //local copy of the data pointer + uint16_t bytes_tosend, nak_count; + uint16_t bytes_left = nbytes; - uint8_t maxpktsize = pep->maxPktSize; - - if (maxpktsize < 1 || maxpktsize > 64) - return USB_ERROR_INVALID_MAX_PKT_SIZE; - - unsigned long timeout = millis() + USB_XFER_TIMEOUT; - - regWr( rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0 ); //set toggle value - - while( bytes_left ) - { - retry_count = 0; - nak_count = 0; - bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left; - bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO - regWr( rSNDBC, bytes_tosend ); //set number of bytes - regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); + uint8_t maxpktsize = pep->maxPktSize; - while( rcode && ( timeout > millis())) - { - switch( rcode ) - { - case hrNAK: - nak_count ++; - if( nak_limit && ( nak_count == nak_limit )) - return( rcode ); - break; - case hrTIMEOUT: - retry_count ++; - if( retry_count == USB_RETRY_LIMIT ) - return( rcode ); - break; - default: - return( rcode ); - }//switch( rcode + if (maxpktsize < 1 || maxpktsize > 64) + return USB_ERROR_INVALID_MAX_PKT_SIZE; - /* process NAK according to Host out NAK bug */ - regWr( rSNDBC, 0 ); - regWr( rSNDFIFO, *data_p ); - regWr( rSNDBC, bytes_tosend ); - regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); - }//while( rcode && .... - bytes_left -= bytes_tosend; - data_p += bytes_tosend; - }//while( bytes_left... - pep->bmSndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle - return( rcode ); //should be 0 in all cases + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + + regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value + + while (bytes_left) { + retry_count = 0; + nak_count = 0; + bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; + bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO + regWr(rSNDBC, bytes_tosend); //set number of bytes + regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet + while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ + regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ + rcode = (regRd(rHRSL) & 0x0f); + + while (rcode && (timeout > millis())) { + switch (rcode) { + case hrNAK: + nak_count++; + if (nak_limit && (nak_count == nak_limit)) + return ( rcode); + break; + case hrTIMEOUT: + retry_count++; + if (retry_count == USB_RETRY_LIMIT) + return ( rcode); + break; + default: + return ( rcode); + }//switch( rcode + + /* process NAK according to Host out NAK bug */ + regWr(rSNDBC, 0); + regWr(rSNDFIFO, *data_p); + regWr(rSNDBC, bytes_tosend); + regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet + while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ + regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ + rcode = (regRd(rHRSL) & 0x0f); + }//while( rcode && .... + bytes_left -= bytes_tosend; + data_p += bytes_tosend; + }//while( bytes_left... + 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 */ /* 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 */ + /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ -uint8_t USB::dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit ) -{ - unsigned long timeout = millis() + USB_XFER_TIMEOUT; - uint8_t tmpdata; - uint8_t rcode; - uint8_t retry_count = 0; - uint16_t nak_count = 0; +uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) { + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + uint8_t tmpdata; + uint8_t rcode = hrSUCCESS; + uint8_t retry_count = 0; + uint16_t nak_count = 0; - while( timeout > millis() ) - { - regWr( rHXFR, ( token|ep )); //launch the transfer - rcode = USB_ERROR_TRANSFER_TIMEOUT; + while (timeout > millis()) { + regWr(rHXFR, (token | ep)); //launch the transfer + rcode = USB_ERROR_TRANSFER_TIMEOUT; - while( millis() < timeout ) //wait for transfer completion - { - tmpdata = regRd( rHIRQ ); + while (millis() < timeout) //wait for transfer completion + { + tmpdata = regRd(rHIRQ); - if( tmpdata & bmHXFRDNIRQ ) - { - regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt - rcode = 0x00; - break; - }//if( tmpdata & bmHXFRDNIRQ + if (tmpdata & bmHXFRDNIRQ) { + regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt + rcode = 0x00; + break; + }//if( tmpdata & bmHXFRDNIRQ - }//while ( millis() < timeout + }//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 + rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result - switch( rcode ) - { - case hrNAK: - nak_count ++; - if( nak_limit && ( nak_count == nak_limit )) - return( rcode ); - //delay(1); - break; - case hrTIMEOUT: - retry_count ++; - if( retry_count == USB_RETRY_LIMIT ) - return( rcode ); - break; - default: - return( rcode ); - }//switch( rcode + switch (rcode) { + case hrNAK: + nak_count++; + if (nak_limit && (nak_count == nak_limit)) + return ( rcode); + break; + case hrTIMEOUT: + retry_count++; + if (retry_count == USB_RETRY_LIMIT) + return ( rcode); + break; + default: + return ( rcode); + }//switch( rcode - }//while( timeout > millis() - return( rcode ); + }//while( timeout > millis() + return ( rcode); } /* USB main task. Performs enumeration/cleanup */ -void USB::Task( void ) //USB state machine +void USB::Task(void) //USB state machine { - uint8_t rcode; - uint8_t tmpdata; - static unsigned long delay = 0; - USB_DEVICE_DESCRIPTOR buf; - bool lowspeed = false; + uint8_t rcode; + uint8_t tmpdata; + static unsigned long delay = 0; + //USB_DEVICE_DESCRIPTOR buf; + bool lowspeed = false; - MAX3421E::Task(); + MAX3421E::Task(); - tmpdata = getVbusState(); + tmpdata = getVbusState(); - /* modify USB task state if Vbus changed */ - switch( tmpdata ) - { - case SE1: //illegal state - usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; - lowspeed = false; - break; - case SE0: //disconnected - if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) - usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; - lowspeed = false; - break; - case LSHOST: - lowspeed = true; - case FSHOST: //attached - if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) - { - delay = millis() + USB_SETTLE_DELAY; - usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; - } - break; - }// switch( tmpdata + /* modify USB task state if Vbus changed */ + switch (tmpdata) { + case SE1: //illegal state + usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; + lowspeed = false; + break; + case SE0: //disconnected + if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED) + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; + lowspeed = false; + break; + case LSHOST: + lowspeed = true; + case FSHOST: //attached + if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) { + delay = millis() + USB_SETTLE_DELAY; + usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; + } + break; + }// switch( tmpdata - for (uint8_t i=0; iPoll(); + for (uint8_t i = 0; i < USB_NUMDEVICES; i++) + if (devConfig[i]) + rcode = devConfig[i]->Poll(); - switch( usb_task_state ) { - case USB_DETACHED_SUBSTATE_INITIALIZE: - init(); + switch (usb_task_state) { + case USB_DETACHED_SUBSTATE_INITIALIZE: + init(); - for (uint8_t i=0; iRelease(); + for (uint8_t i = 0; i < USB_NUMDEVICES; i++) + if (devConfig[i]) + rcode = devConfig[i]->Release(); - usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; - break; - case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here - break; - case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here - break; - case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device - if( delay < millis() ) - usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; - break; - case USB_ATTACHED_SUBSTATE_RESET_DEVICE: - regWr( rHCTL, bmBUSRST ); //issue bus reset - usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; - break; - case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: - if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) - { - 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 - } - break; - case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order - if( regRd( rHIRQ ) & bmFRAMEIRQ ) //when first SOF received we can continue - { - if( delay < millis() ) //20ms passed - usb_task_state = USB_STATE_CONFIGURING; - } - break; - case USB_STATE_CONFIGURING: - rcode = Configuring(0, 0, lowspeed); + usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; + break; + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here + break; + case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here + break; + case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device + if (delay < millis()) + usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; + break; + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: + regWr(rHCTL, bmBUSRST); //issue bus reset + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; + break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: + if ((regRd(rHCTL) & bmBUSRST) == 0) { + 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 + } + break; + case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order + if (regRd(rHIRQ) & bmFRAMEIRQ) //when first SOF received we can continue + { + if (delay < millis()) //20ms passed + usb_task_state = USB_STATE_CONFIGURING; + } + break; + case USB_STATE_CONFIGURING: + rcode = Configuring(0, 0, lowspeed); - if (rcode) - { - if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) - { - usb_error = rcode; - usb_task_state = USB_STATE_ERROR; - } - } - else - usb_task_state = USB_STATE_RUNNING; - break; - case USB_STATE_RUNNING: - break; - case USB_STATE_ERROR: - break; - } // switch( usb_task_state ) -} - -uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) -{ - uint8_t buf[12]; - uint8_t rcode; - UsbDevice *p0 = NULL, *p = NULL; - - // Get pointer to pseudo device with address 0 assigned - p0 = addrPool.GetUsbDevicePtr(0); - - if (!p0) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p0->epinfo) - return USB_ERROR_EPINFO_IS_NULL; - - p0->lowspeed = (lowspeed) ? true : false; - - // Allocate new address according to device class - uint8_t bAddress = addrPool.AllocAddress(parent, false, port); - - if (!bAddress) - return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - // Assign new address to the device - rcode = setAddr( 0, 0, bAddress ); - - if (rcode) - { - addrPool.FreeAddress(bAddress); - bAddress = 0; - return rcode; - } - return 0; -}; - -uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) -{ - static uint8_t dev_index = 0; - uint8_t rcode = 0; - - for (; devConfigIndexInit(parent, port, lowspeed); - - if (!rcode) - { - devConfigIndex = 0; - return 0; - } - 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; - - 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; + if (rcode) { + if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) { + usb_error = rcode; + usb_task_state = USB_STATE_ERROR; + } + } else + usb_task_state = USB_STATE_RUNNING; + break; + case USB_STATE_RUNNING: + break; + case USB_STATE_ERROR: + break; + } // switch( usb_task_state ) } -uint8_t USB::ReleaseDevice(uint8_t addr) -{ - if (!addr) - return 0; +uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) { + //uint8_t buf[12]; + uint8_t rcode; + UsbDevice *p0 = NULL, *p = NULL; - for (uint8_t i=0; iGetAddress() == addr) - return devConfig[i]->Release(); + // Get pointer to pseudo device with address 0 assigned + p0 = addrPool.GetUsbDevicePtr(0); + + if (!p0) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p0->epinfo) + return USB_ERROR_EPINFO_IS_NULL; + + p0->lowspeed = (lowspeed) ? true : false; + + // Allocate new address according to device class + uint8_t bAddress = addrPool.AllocAddress(parent, false, port); + + if (!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + // Assign new address to the device + rcode = setAddr(0, 0, bAddress); + + if (rcode) { + addrPool.FreeAddress(bAddress); + bAddress = 0; + return rcode; + } + return 0; +}; + +uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { + //static uint8_t dev_index = 0; + uint8_t rcode = 0; + + for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { + if (!devConfig[devConfigIndex]) + continue; + + rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed); + + if (!rcode) { + devConfigIndex = 0; + return 0; + } + 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; + + 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; +} + +uint8_t USB::ReleaseDevice(uint8_t addr) { + if (!addr) + return 0; + + for (uint8_t i = 0; i < USB_NUMDEVICES; i++) + if (devConfig[i]->GetAddress() == addr) + return devConfig[i]->Release(); + + return 0; } #if 1 //!defined(USB_METHODS_INLINE) //get device descriptor -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, nbytes, dataptr, NULL )); + +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, nbytes, dataptr, NULL)); } -//get configuration descriptor -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, nbytes, dataptr, NULL )); +//get configuration descriptor + +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, nbytes, dataptr, NULL)); } -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 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, 8, conf, buf); - if (ret) - return ret; + if (ret) + return ret; - uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; - delay(100); - //USBTRACE2("\r\ntotal conf.size:", total); + uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; - return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p )); + //USBTRACE2("\r\ntotal conf.size:", total); + + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p)); } //get string descriptor -uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, uint16_t ns, 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, ns, ns, dataptr, NULL )); + +uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, 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, ns, ns, dataptr, NULL)); } -//set address -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, 0x0000, NULL, NULL )); +//set address + +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, 0x0000, NULL, NULL)); } //set configuration -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, 0x0000, NULL, NULL )); + +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, 0x0000, NULL, NULL)); } #endif // defined(USB_METHODS_INLINE) diff --git a/Usb.h b/Usb.h index 7acdb2d5..c27796d2 100644 --- a/Usb.h +++ b/Usb.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* USB functions */ #ifndef _usb_h_ #define _usb_h_ @@ -44,28 +44,18 @@ e-mail : support@circuitsathome.com #include "hexdump.h" #include "message.h" - +extern int UsbDEBUGlvl; /* 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 MAX3421E; // Black Widow -#elif defined(BOARD_TEENSY_PLUS_PLUS) -typedef MAX3421e MAX3421E; // Teensy++ 2.0 & 1.0 -#elif defined(BOARD_MEGA_ADK) -typedef MAX3421e MAX3421E; // Arduino Mega ADK -#elif defined(BOARD_BALANDUINO) -typedef MAX3421e MAX3421E; // Balanduino +typedef MAX3421e MAX3421E; // Black Widow #else -typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.) +typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560 #endif //Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s))) -#define USBTRACE(s) (Serial.print((s))) -#define USBTRACE2(s,r) (Serial.print((s)), Serial.println((r),HEX)) +#define USBTRACE(s) (Notify(PSTR(s), 0x80)) +#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80)) @@ -80,22 +70,22 @@ typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Me // 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_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_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_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_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_MISC 0xef // Miscellaneous #define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific #define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific @@ -104,42 +94,41 @@ typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Me #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_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 +#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 -{ +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; + 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_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 +#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_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_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 @@ -150,134 +139,138 @@ public: /* 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 - }; - }ReqType_u; - uint8_t bRequest; // 1 Request - union { - uint16_t wValue; // 2 Depends on bRequest - struct { - uint8_t wValueLo; - uint8_t wValueHi; - }; - }wVal_u; - uint16_t wIndex; // 4 Depends on bRequest - uint16_t wLength; // 6 Depends on bRequest -} SETUP_PKT, *PSETUP_PKT; + + 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 -{ + +class USBReadParser { public: - virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; + virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; }; +class USB : public MAX3421E { + AddressPoolImpl addrPool; + USBDeviceConfig* devConfig[USB_NUMDEVICES]; + uint8_t devConfigIndex; + uint8_t bmHubPre; -class USB : public MAX3421E -{ - AddressPoolImpl addrPool; - USBDeviceConfig* devConfig[USB_NUMDEVICES]; - uint8_t devConfigIndex; - uint8_t bmHubPre; +public: + USB(void); - public: - USB( void ); + void SetHubPreMask() { + bmHubPre |= bmHUBPRE; + }; - void SetHubPreMask() { bmHubPre |= bmHUBPRE; }; - void ResetHubPreMask() { bmHubPre &= (~bmHUBPRE); }; + void ResetHubPreMask() { + bmHubPre &= (~bmHUBPRE); + }; - AddressPool& GetAddressPool() - { - return (AddressPool&)addrPool; - }; - uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) - { - for (uint8_t i=0; iregisterServiceClass(this); // Register it as a Bluetooth service - - pBtd->pairWithWii = pair; - - HIDBuffer[0] = 0xA2;// HID BT DATA_request (0xA0) | Report Type (Output 0x02) - - /* Set device cid for the control and intterrupt channelse - LSB */ - control_dcid[0] = 0x60;//0x0060 - control_dcid[1] = 0x00; - interrupt_dcid[0] = 0x61;//0x0061 - interrupt_dcid[1] = 0x00; - - Reset(); + if (pBtd) + pBtd->registerServiceClass(this); // Register it as a Bluetooth service + + pBtd->pairWithWii = pair; + + HIDBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + + /* Set device cid for the control and intterrupt channelse - LSB */ + control_dcid[0] = 0x60; //0x0060 + control_dcid[1] = 0x00; + interrupt_dcid[0] = 0x61; //0x0061 + interrupt_dcid[1] = 0x00; + + Reset(); } + void WII::Reset() { - wiimoteConnected = false; - nunchuckConnected = false; - motionPlusConnected = false; - activateNunchuck = false; - motionValuesReset = false; - activeConnection = false; - pBtd->motionPlusInside = false; - pBtd->wiiUProController = false; - wiiUProControllerConnected = false; - l2cap_event_flag = 0; // Reset flags - l2cap_state = L2CAP_WAIT; + wiimoteConnected = false; + nunchuckConnected = false; + motionPlusConnected = false; + activateNunchuck = false; + motionValuesReset = false; + activeConnection = false; + pBtd->motionPlusInside = false; + pBtd->wiiUProController = false; + wiiUProControllerConnected = false; + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; } void WII::disconnect() { // Use this void to disconnect any of the controllers - if(motionPlusConnected && !pBtd->motionPlusInside) { // Disable the Motion Plus extension -#ifdef DEBUG - Notify(PSTR("\r\nDeactivating Motion Plus")); + if (motionPlusConnected && !pBtd->motionPlusInside) { // Disable the Motion Plus extension +#ifdef DEBUG + Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80); #endif - initExtension1(); // This will disable the Motion Plus extension - } - //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection - pBtd->l2cap_disconnection_request(hci_handle,0x0A, interrupt_scid, interrupt_dcid); - Reset(); - l2cap_state = L2CAP_INTERRUPT_DISCONNECT; + initExtension1(); // This will disable the Motion Plus extension + } + //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection + pBtd->l2cap_disconnection_request(hci_handle, 0x0A, interrupt_scid, interrupt_dcid); + Reset(); + l2cap_state = L2CAP_INTERRUPT_DISCONNECT; } void WII::ACLData(uint8_t* l2capinbuf) { - if(!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) { - if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { - if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { - pBtd->incomingWii = false; - pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service - activeConnection = true; - hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection - l2cap_state = L2CAP_WAIT; - } - } - } - if ((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000)) { // acl_handle_ok or it's a new connection - if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U - if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { -#ifdef DEBUG - Notify(PSTR("\r\nL2CAP Command Rejected - Reason: ")); - PrintHex(l2capinbuf[13]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[12]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[17]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[16]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[15]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[14]); -#endif - } - else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) { - if (((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success - if (l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { // Success - //Serial.print("\r\nHID Control Connection Complete"); - identifier = l2capinbuf[9]; - control_scid[0] = l2capinbuf[12]; - control_scid[1] = l2capinbuf[13]; - l2cap_event_flag |= L2CAP_FLAG_CONTROL_CONNECTED; - } - else if (l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) { - //Serial.print("\r\nHID Interrupt Connection Complete"); - identifier = l2capinbuf[9]; - interrupt_scid[0] = l2capinbuf[12]; - interrupt_scid[1] = l2capinbuf[13]; - l2cap_event_flag |= L2CAP_FLAG_INTERRUPT_CONNECTED; - } - } - } - else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { -#ifdef EXTRADEBUG - Notify(PSTR("\r\nL2CAP Connection Request - PSM: ")); - PrintHex(l2capinbuf[13]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[12]); - Notify(PSTR(" SCID: ")); - PrintHex(l2capinbuf[15]); - Notify(PSTR(" ")); - PrintHex(l2capinbuf[14]); - Notify(PSTR(" Identifier: ")); - PrintHex(l2capinbuf[9]); -#endif - if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { - identifier = l2capinbuf[9]; - control_scid[0] = l2capinbuf[14]; - control_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_CONTROL_REQUEST; - } - else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { - identifier = l2capinbuf[9]; - interrupt_scid[0] = l2capinbuf[14]; - interrupt_scid[1] = l2capinbuf[15]; - l2cap_event_flag |= L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST; - } - } - else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { - if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Serial.print("\r\nHID Control Configuration Complete"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS; - } - else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { - //Serial.print("\r\nHID Interrupt Configuration Complete"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS; - } - } - } - else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Serial.print("\r\nHID Control Configuration Request"); - pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); - } - else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { - //Serial.print("\r\nHID Interrupt Configuration Request"); - pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid); - } - } - else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { - if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { -#ifdef DEBUG - Notify(PSTR("\r\nDisconnect Request: Control Channel")); -#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 - Notify(PSTR("\r\nDisconnect Request: Interrupt Channel")); -#endif - identifier = l2capinbuf[9]; - pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid); - Reset(); - } - } - else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { - if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { - //Serial.print("\r\nDisconnect Response: Control Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE; - } - else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { - //Serial.print("\r\nDisconnect Response: Interrupt Channel"); - identifier = l2capinbuf[9]; - l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE; - } - } -#ifdef EXTRADEBUG - else { - identifier = l2capinbuf[9]; - Notify(PSTR("\r\nL2CAP Unknown Signaling Command: ")); - PrintHex(l2capinbuf[8]); - } -#endif - } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt - //Serial.print("\r\nL2CAP Interrupt"); - if(wiimoteConnected) { - if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT - if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons - if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); - else if(wiiUProControllerConnected) - ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); - else if(motionPlusConnected) { - if(l2capinbuf[20] & 0x02) // Only update the wiimote buttons, since the extension bytes are from the Motion Plus - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); - else if (nunchuckConnected) // Update if it's a report from the Nunchuck - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); - //else if(classicControllerConnected) // Update if it's a report from the Classic Controller + if (!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) { + if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + pBtd->incomingWii = false; + pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service + activeConnection = true; + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + l2cap_state = L2CAP_WAIT; } - else if(nunchuckConnected) // The Nunchuck is directly connected - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16)); - //else if(classicControllerConnected) // The Classic Controller is directly connected - else if(!unknownExtensionConnected) - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); + } + } + if ((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000)) { // acl_handle_ok or it's a new connection + if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U + if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { +#ifdef DEBUG + Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[17], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[16], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[14], 0x80); +#endif + } else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) { + if (((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success + if (l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { // Success + //Serial.print("\r\nHID Control Connection Complete"); + identifier = l2capinbuf[9]; + control_scid[0] = l2capinbuf[12]; + control_scid[1] = l2capinbuf[13]; + l2cap_event_flag |= L2CAP_FLAG_CONTROL_CONNECTED; + } else if (l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) { + //Serial.print("\r\nHID Interrupt Connection Complete"); + identifier = l2capinbuf[9]; + interrupt_scid[0] = l2capinbuf[12]; + interrupt_scid[1] = l2capinbuf[13]; + l2cap_event_flag |= L2CAP_FLAG_INTERRUPT_CONNECTED; + } + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { +#ifdef EXTRADEBUG + Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" SCID: "), 0x80); + PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR(" Identifier: "), 0x80); + PrintHex (l2capinbuf[9], 0x80); +#endif + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + identifier = l2capinbuf[9]; + control_scid[0] = l2capinbuf[14]; + control_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_CONTROL_REQUEST; + } else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { + identifier = l2capinbuf[9]; + interrupt_scid[0] = l2capinbuf[14]; + interrupt_scid[1] = l2capinbuf[15]; + l2cap_event_flag |= L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST; + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { + if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { + //Serial.print("\r\nHID Control Configuration Complete"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS; + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Serial.print("\r\nHID Interrupt Configuration Complete"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS; + } + } + } else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { + //Serial.print("\r\nHID Control Configuration Request"); + pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Serial.print("\r\nHID Interrupt Configuration Request"); + pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid); + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { + if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { +#ifdef DEBUG + 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 + Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80); +#endif + identifier = l2capinbuf[9]; + pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid); + Reset(); + } + } else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { + if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { + //Serial.print("\r\nDisconnect Response: Control Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE; + } else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { + //Serial.print("\r\nDisconnect Response: Interrupt Channel"); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE; + } + } +#ifdef EXTRADEBUG + else { + identifier = l2capinbuf[9]; + Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); + PrintHex (l2capinbuf[8], 0x80); + } +#endif + } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt + //Serial.print("\r\nL2CAP Interrupt"); + if (wiimoteConnected) { + if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons + if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); + else if (wiiUProControllerConnected) + ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); + else if (motionPlusConnected) { + if (l2capinbuf[20] & 0x02) // Only update the wiimote buttons, since the extension bytes are from the Motion Plus + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); + else if (nunchuckConnected) // Update if it's a report from the Nunchuck + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); + //else if(classicControllerConnected) // Update if it's a report from the Classic Controller + } else if (nunchuckConnected) // The Nunchuck is directly connected + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16)); + //else if(classicControllerConnected) // The Classic Controller is directly connected + else if (!unknownExtensionConnected) + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); #ifdef PRINTREPORT - Notify(PSTR("ButtonState: ")); - PrintHex(ButtonState); - Notify(PSTR("\r\n")); + Notify(PSTR("ButtonState: "), 0x80); + PrintHex (ButtonState, 0x80); + Notify(PSTR("\r\n"), 0x80); #endif - if(ButtonState != OldButtonState) { - ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable - OldButtonState = ButtonState; - } - } - if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer - accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5))-500; - accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4))-500; - accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5))-500; - wiimotePitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG; - wiimoteRoll = (atan2(accX,accZ)+PI)*RAD_TO_DEG; - } - switch (l2capinbuf[9]) { - case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV - wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) - batteryLevel = l2capinbuf[15]; // Update battery level - if(l2capinbuf[12] & 0x01) { + if (ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + } + } + if (l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer + accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500; + accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500; + accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500; + wiimotePitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + wiimoteRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + } + switch (l2capinbuf[9]) { + case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV + wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) + batteryLevel = l2capinbuf[15]; // Update battery level + if (l2capinbuf[12] & 0x01) { #ifdef DEBUG - Notify(PSTR("\r\nWARNING: Battery is nearly empty")); -#endif - } - if(l2capinbuf[12] & 0x02) { // Check if a extension is connected -#ifdef DEBUG - if(!unknownExtensionConnected) - Notify(PSTR("\r\nExtension connected")); + Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80); #endif - unknownExtensionConnected = true; + } + if (l2capinbuf[12] & 0x02) { // Check if a extension is connected +#ifdef DEBUG + if (!unknownExtensionConnected) + Notify(PSTR("\r\nExtension connected"), 0x80); +#endif + unknownExtensionConnected = true; #ifdef WIICAMERA - if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera -#endif - setReportMode(false,0x35); // Also read the extension - } - else { -#ifdef DEBUG - Notify(PSTR("\r\nExtension disconnected")); + if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera #endif - if(motionPlusConnected) { + setReportMode(false, 0x35); // Also read the extension + } else { #ifdef DEBUG - Notify(PSTR(" - from Motion Plus")); + Notify(PSTR("\r\nExtension disconnected"), 0x80); #endif - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - if(!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false - nunchuckConnected = false; - //else if(classicControllerConnected) - } - else if(nunchuckConnected) { + if (motionPlusConnected) { #ifdef DEBUG - Notify(PSTR(" - Nunchuck")); + Notify(PSTR(" - from Motion Plus"), 0x80); #endif - nunchuckConnected = false; // It must be the Nunchuck controller then - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - setLedStatus(); - setReportMode(false,0x31); // If there is no extension connected we will read the button and accelerometer - } else { - setReportMode(false,0x31); // If there is no extension connected we will read the button and accelerometer - } - } - break; - case 0x21: // Read Memory Data - if((l2capinbuf[12] & 0x0F) == 0) { // No error - // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers - if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + if (!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false + nunchuckConnected = false; + //else if(classicControllerConnected) + } else if (nunchuckConnected) { #ifdef DEBUG - Notify(PSTR("\r\nNunchuck connected")); + Notify(PSTR(" - Nunchuck"), 0x80); #endif - l2cap_event_flag |= WII_FLAG_NUNCHUCK_CONNECTED; - } else if(l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) { + nunchuckConnected = false; // It must be the Nunchuck controller then + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + setLedStatus(); + setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer + } else { + setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer + } + } + break; + case 0x21: // Read Memory Data + if ((l2capinbuf[12] & 0x0F) == 0) { // No error + // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers + if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { #ifdef DEBUG - Notify(PSTR("\r\nMotion Plus connected")); + Notify(PSTR("\r\nNunchuck connected"), 0x80); #endif - l2cap_event_flag |= WII_FLAG_MOTION_PLUS_CONNECTED; - } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) { + l2cap_event_flag |= WII_FLAG_NUNCHUCK_CONNECTED; + } else if (l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) { #ifdef DEBUG - Notify(PSTR("\r\nMotion Plus activated in normal mode")); + Notify(PSTR("\r\nMotion Plus connected"), 0x80); #endif - motionPlusConnected = true; - } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { + l2cap_event_flag |= WII_FLAG_MOTION_PLUS_CONNECTED; + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) { #ifdef DEBUG - Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode")); + Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80); #endif - activateNunchuck = false; - motionPlusConnected = true; - nunchuckConnected = true; - } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) { + motionPlusConnected = true; + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { #ifdef DEBUG - Notify(PSTR("\r\nInactive Wii Motion Plus")); - Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension")); + Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80); #endif - stateCounter = 300; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE" - } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) { + activateNunchuck = false; + motionPlusConnected = true; + nunchuckConnected = true; + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) { #ifdef DEBUG - Notify(PSTR("\r\nWii U Pro Controller connected")); + Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80); + Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80); #endif - wiiUProControllerConnected = true; - } + stateCounter = 300; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE" + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) { #ifdef DEBUG - else { - Notify(PSTR("\r\nUnknown Device: ")); - PrintHex(l2capinbuf[13]); - PrintHex(l2capinbuf[14]); - Notify(PSTR("\r\nData: ")); - for(uint8_t i = 0; i < ((l2capinbuf[12] >> 4)+1); i++) { // bit 4-7 is the length-1 - PrintHex(l2capinbuf[15+i]); - Notify(PSTR(" ")); - } - } + Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80); #endif - } + wiiUProControllerConnected = true; + } +#ifdef DEBUG + else { + Notify(PSTR("\r\nUnknown Device: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR("\r\nData: "), 0x80); + for (uint8_t i = 0; i < ((l2capinbuf[12] >> 4) + 1); i++) { // bit 4-7 is the length-1 + PrintHex (l2capinbuf[15 + i], 0x80); + Notify(PSTR(" "), 0x80); + } + } +#endif + } #ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nReport Error: ")); - PrintHex(l2capinbuf[13]); - PrintHex(l2capinbuf[14]); - } + else { + Notify(PSTR("\r\nReport Error: "), 0x80); + PrintHex (l2capinbuf[13], 0x80); + PrintHex (l2capinbuf[14], 0x80); + } #endif - break; - case 0x22: // Acknowledge output report, return function result + break; + case 0x22: // Acknowledge output report, return function result #ifdef DEBUG - if(l2capinbuf[13] != 0x00) { // Check if there is an error - Notify(PSTR("\r\nCommand failed: ")); - PrintHex(l2capinbuf[12]); - } -#endif - break; - case 0x30: // Core buttons - (a1) 30 BB BB - break; - case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected - roll = wiimoteRoll; - break; - case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE - break; - case 0x33: // Core Buttons with Accelerometer and 12 IR bytes - (a1) 33 BB BB AA AA AA II II II II II II II II II II II II - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus data available - roll = wiimoteRoll; + if (l2capinbuf[13] != 0x00) { // Check if there is an error + Notify(PSTR("\r\nCommand failed: "), 0x80); + PrintHex (l2capinbuf[12], 0x80); + } +#endif + break; + case 0x30: // Core buttons - (a1) 30 BB BB + break; + case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected + roll = wiimoteRoll; + break; + case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE + break; + case 0x33: // Core Buttons with Accelerometer and 12 IR bytes - (a1) 33 BB BB AA AA AA II II II II II II II II II II II II + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus data available + roll = wiimoteRoll; #ifdef WIICAMERA - // Read the IR data - IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position - IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position - IR_object_s1 = (l2capinbuf[17] & 0x0F); // size value, 0-15 + // Read the IR data + IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position + IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position + IR_object_s1 = (l2capinbuf[17] & 0x0F); // size value, 0-15 - IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); - IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); - IR_object_s2 = (l2capinbuf[20] & 0x0F); + IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); + IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); + IR_object_s2 = (l2capinbuf[20] & 0x0F); - IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4)); - IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2)); - IR_object_s3 = (l2capinbuf[23] & 0x0F); + IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4)); + IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2)); + IR_object_s3 = (l2capinbuf[23] & 0x0F); - IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4)); - IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2)); - IR_object_s4 = (l2capinbuf[26] & 0x0F); + IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4)); + IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2)); + IR_object_s4 = (l2capinbuf[26] & 0x0F); #endif - break; - case 0x34: // Core Buttons with 19 Extension bytes - (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE - break; - /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */ - case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes - // (a1) 31 BB BB AA AA AA II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II - // corresponds to output report mode 0x3e + break; + case 0x34: // Core Buttons with 19 Extension bytes - (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE + break; + /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */ + case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes + // (a1) 31 BB BB AA AA AA II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II + // corresponds to output report mode 0x3e - /**** for reading in full mode: DOES NOT WORK YET ****/ - /* When it works it will also have intensity and bounding box data */ - /* - IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); - IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); - IR_object_s1 = (l2capinbuf[15] & 0x0F); - */ - break; - case 0x3F: - /* - IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); - IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); - IR_object_s1 = (l2capinbuf[15] & 0x0F); - */ - break; - case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes - // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE - if(motionPlusConnected) { - if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension - if(motionValuesReset) { // We will only use the values when the gyro value has been set - gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6))-gyroYawZero); - gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6))-gyroRollZero); - gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6))-gyroPitchZero); + /**** for reading in full mode: DOES NOT WORK YET ****/ + /* When it works it will also have intensity and bounding box data */ + /* + IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); + IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); + IR_object_s1 = (l2capinbuf[15] & 0x0F); + */ + break; + case 0x3F: + /* + IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); + IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); + IR_object_s1 = (l2capinbuf[15] & 0x0F); + */ + break; + case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes + // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE + if (motionPlusConnected) { + if (l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension + if (motionValuesReset) { // We will only use the values when the gyro value has been set + gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero); + gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero); + gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero); - yawGyroSpeed = (double)gyroYawRaw/((double)gyroYawZero/yawGyroScale); - rollGyroSpeed = -(double)gyroRollRaw/((double)gyroRollZero/rollGyroScale); // We invert these values so they will fit the acc values - pitchGyroSpeed = (double)gyroPitchRaw/((double)gyroPitchZero/pitchGyroScale); - - /* The onboard gyro has two ranges for slow and fast mode */ - if(!(l2capinbuf[18] & 0x02)) // Check if fast more is used - yawGyroSpeed *= 4.545; - if(!(l2capinbuf[18] & 0x01)) // Check if fast more is used - pitchGyroSpeed *= 4.545; - if(!(l2capinbuf[19] & 0x02)) // Check if fast more is used - rollGyroSpeed *= 4.545; - - pitch = (0.93*(pitch+(pitchGyroSpeed*(double)(micros()-timer)/1000000)))+(0.07*wiimotePitch); // Use a complimentary filter to calculate the angle - roll = (0.93*(roll+(rollGyroSpeed*(double)(micros()-timer)/1000000)))+(0.07*wiimoteRoll); - - gyroYaw += (yawGyroSpeed*((double)(micros()-timer)/1000000)); - gyroRoll += (rollGyroSpeed*((double)(micros()-timer)/1000000)); - gyroPitch += (pitchGyroSpeed*((double)(micros()-timer)/1000000)); - timer = micros(); - /* - // Uncomment these lines to tune the gyro scale variabels - Serial.print("\r\ngyroYaw: "); - Serial.print(gyroYaw); - Serial.print("\tgyroRoll: "); - Serial.print(gyroRoll); - Serial.print("\tgyroPitch: "); - Serial.print(gyroPitch); - */ - /* - Serial.print("\twiimoteRoll: "); - Serial.print(wiimoteRoll); - Serial.print("\twiimotePitch: "); - Serial.print(wiimotePitch); - */ - } else { - if((micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values + yawGyroSpeed = (double)gyroYawRaw / ((double)gyroYawZero / yawGyroScale); + rollGyroSpeed = -(double)gyroRollRaw / ((double)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values + pitchGyroSpeed = (double)gyroPitchRaw / ((double)gyroPitchZero / pitchGyroScale); + + /* The onboard gyro has two ranges for slow and fast mode */ + if (!(l2capinbuf[18] & 0x02)) // Check if fast more is used + yawGyroSpeed *= 4.545; + if (!(l2capinbuf[18] & 0x01)) // Check if fast more is used + pitchGyroSpeed *= 4.545; + if (!(l2capinbuf[19] & 0x02)) // Check if fast more is used + rollGyroSpeed *= 4.545; + + pitch = (0.93 * (pitch + (pitchGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimotePitch); // Use a complimentary filter to calculate the angle + roll = (0.93 * (roll + (rollGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimoteRoll); + + gyroYaw += (yawGyroSpeed * ((double)(micros() - timer) / 1000000)); + gyroRoll += (rollGyroSpeed * ((double)(micros() - timer) / 1000000)); + gyroPitch += (pitchGyroSpeed * ((double)(micros() - timer) / 1000000)); + timer = micros(); + /* + // Uncomment these lines to tune the gyro scale variabels + Serial.print("\r\ngyroYaw: "); + Serial.print(gyroYaw); + Serial.print("\tgyroRoll: "); + Serial.print(gyroRoll); + Serial.print("\tgyroPitch: "); + Serial.print(gyroPitch); + */ + /* + Serial.print("\twiimoteRoll: "); + Serial.print(wiimoteRoll); + Serial.print("\twiimotePitch: "); + Serial.print(wiimotePitch); + */ + } else { + if ((micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values #ifdef DEBUG - Notify(PSTR("\r\nThe gyro values has been reset")); + Notify(PSTR("\r\nThe gyro values has been reset"), 0x80); #endif - gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)); - gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)); - gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)); - - rollGyroScale = 500; // You might need to adjust these - pitchGyroScale = 400; - yawGyroScale = 415; + gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)); + gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)); + gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)); - gyroYaw = 0; - gyroRoll = 0; - gyroPitch = 0; - - motionValuesReset = true; - timer = micros(); - } - } - } else { - if(nunchuckConnected) { - hatValues[HatX] = l2capinbuf[15]; - hatValues[HatY] = l2capinbuf[16]; - accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3))-416; - accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4))-416; - accZ = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5))-416; - nunchuckPitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG; - nunchuckRoll = (atan2(accX,accZ)+PI)*RAD_TO_DEG; - } - //else if(classicControllerConnected) { } + rollGyroScale = 500; // You might need to adjust these + pitchGyroScale = 400; + yawGyroScale = 415; + + gyroYaw = 0; + gyroRoll = 0; + gyroPitch = 0; + + motionValuesReset = true; + timer = micros(); + } + } + } else { + if (nunchuckConnected) { + hatValues[HatX] = l2capinbuf[15]; + hatValues[HatY] = l2capinbuf[16]; + accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416; + accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416; + accZ = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416; + nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + } + //else if(classicControllerConnected) { } + } + if (l2capinbuf[19] & 0x01) { + if (!extensionConnected) { + extensionConnected = true; + unknownExtensionConnected = true; +#ifdef DEBUG + Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80); +#endif + } + } else { + if (extensionConnected && !unknownExtensionConnected) { + extensionConnected = false; + unknownExtensionConnected = true; +#ifdef DEBUG + Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80); +#endif + nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent + } + } + + } else if (nunchuckConnected) { + hatValues[HatX] = l2capinbuf[15]; + hatValues[HatY] = l2capinbuf[16]; + accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416; + accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416; + accZ = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416; + nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected + roll = wiimoteRoll; + } else if (wiiUProControllerConnected) { + hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8); + hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8); + hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); + hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); + } + break; +#ifdef DEBUG + default: + Notify(PSTR("\r\nUnknown Report type: "), 0x80); + Serial.print(l2capinbuf[9], HEX); + break; +#endif + } } - if(l2capinbuf[19] & 0x01) { - if(!extensionConnected) { - extensionConnected = true; - unknownExtensionConnected = true; -#ifdef DEBUG - Notify(PSTR("\r\nExtension connected to Motion Plus")); -#endif - } - } - else { - if(extensionConnected && !unknownExtensionConnected) { - extensionConnected = false; - unknownExtensionConnected = true; -#ifdef DEBUG - Notify(PSTR("\r\nExtension disconnected from Motion Plus")); -#endif - nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent - } - } - - } else if(nunchuckConnected) { - hatValues[HatX] = l2capinbuf[15]; - hatValues[HatY] = l2capinbuf[16]; - accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2))-416; - accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4))-416; - accZ = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6))-416; - nunchuckPitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG; - nunchuckRoll = (atan2(accX,accZ)+PI)*RAD_TO_DEG; - - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected - roll = wiimoteRoll; - } else if(wiiUProControllerConnected) { - hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8); - hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8); - hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); - hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); - } - break; -#ifdef DEBUG - default: - Notify(PSTR("\r\nUnknown Report type: ")); - Serial.print(l2capinbuf[9],HEX); - break; -#endif - } + } } - } + L2CAP_task(); } - L2CAP_task(); - } } -void WII::L2CAP_task() { - switch (l2cap_state) { - /* These states are used if the Wiimote is the host */ - case L2CAP_CONTROL_SUCCESS: - if (l2cap_config_success_control_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nHID Control Successfully Configured")); -#endif - l2cap_state = L2CAP_INTERRUPT_SETUP; - } - break; - - case L2CAP_INTERRUPT_SETUP: - if (l2cap_connection_request_interrupt_flag) { -#ifdef DEBUG - Notify(PSTR("\r\nHID Interrupt Incoming Connection Request")); -#endif - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, interrupt_scid); - - l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; - } - break; - /* These states are used if the Arduino is the host */ - case L2CAP_CONTROL_CONNECT_REQUEST: - if (l2cap_connected_control_flag) { +void WII::L2CAP_task() { + switch (l2cap_state) { + /* These states are used if the Wiimote is the host */ + case L2CAP_CONTROL_SUCCESS: + if (l2cap_config_success_control_flag) { #ifdef DEBUG - Notify(PSTR("\r\nSend HID Control Config Request")); + Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); #endif - identifier++; - pBtd->l2cap_config_request(hci_handle, identifier, control_scid); - l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST; - } - break; - - case L2CAP_CONTROL_CONFIG_REQUEST: - if(l2cap_config_success_control_flag) { + l2cap_state = L2CAP_INTERRUPT_SETUP; + } + break; + + case L2CAP_INTERRUPT_SETUP: + if (l2cap_connection_request_interrupt_flag) { #ifdef DEBUG - Notify(PSTR("\r\nSend HID Interrupt Connection Request")); + Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80); #endif - identifier++; - pBtd->l2cap_connection_request(hci_handle,identifier,interrupt_dcid,HID_INTR_PSM); - l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST; - } - break; - - case L2CAP_INTERRUPT_CONNECT_REQUEST: - if(l2cap_connected_interrupt_flag) { + pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); + + l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; + } + break; + + /* These states are used if the Arduino is the host */ + case L2CAP_CONTROL_CONNECT_REQUEST: + if (l2cap_connected_control_flag) { #ifdef DEBUG - Notify(PSTR("\r\nSend HID Interrupt Config Request")); + Notify(PSTR("\r\nSend HID Control Config Request"), 0x80); #endif - identifier++; - pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); - l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; - } - break; - - case L2CAP_INTERRUPT_CONFIG_REQUEST: - if(l2cap_config_success_interrupt_flag) { // Now the HID channels is established + identifier++; + pBtd->l2cap_config_request(hci_handle, identifier, control_scid); + l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST; + } + break; + + case L2CAP_CONTROL_CONFIG_REQUEST: + if (l2cap_config_success_control_flag) { #ifdef DEBUG - Notify(PSTR("\r\nHID Channels Established")); + Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); #endif - pBtd->connectToWii = false; - pBtd->pairWithWii = false; - wiimoteConnected = true; - stateCounter = 0; - l2cap_state = L2CAP_CHECK_MOTION_PLUS_STATE; - } - break; - - /* The next states are in run() */ - - case L2CAP_INTERRUPT_DISCONNECT: - if (l2cap_disconnect_response_interrupt_flag) { + identifier++; + pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM); + l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST; + } + break; + + case L2CAP_INTERRUPT_CONNECT_REQUEST: + if (l2cap_connected_interrupt_flag) { #ifdef DEBUG - Notify(PSTR("\r\nDisconnected Interrupt Channel")); + Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80); #endif - identifier++; - pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); - l2cap_state = L2CAP_CONTROL_DISCONNECT; - } - break; - - case L2CAP_CONTROL_DISCONNECT: - if (l2cap_disconnect_response_control_flag) { + identifier++; + pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); + l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; + } + break; + + case L2CAP_INTERRUPT_CONFIG_REQUEST: + if (l2cap_config_success_interrupt_flag) { // Now the HID channels is established #ifdef DEBUG - Notify(PSTR("\r\nDisconnected Control Channel")); + Notify(PSTR("\r\nHID Channels Established"), 0x80); #endif - pBtd->hci_disconnect(hci_handle); - hci_handle = -1; // Reset handle - l2cap_event_flag = 0; // Reset flags - l2cap_state = L2CAP_WAIT; - } - break; - } + pBtd->connectToWii = false; + pBtd->pairWithWii = false; + wiimoteConnected = true; + stateCounter = 0; + l2cap_state = L2CAP_CHECK_MOTION_PLUS_STATE; + } + break; + + /* The next states are in run() */ + + case L2CAP_INTERRUPT_DISCONNECT: + if (l2cap_disconnect_response_interrupt_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); +#endif + identifier++; + pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); + l2cap_state = L2CAP_CONTROL_DISCONNECT; + } + break; + + case L2CAP_CONTROL_DISCONNECT: + if (l2cap_disconnect_response_control_flag) { +#ifdef DEBUG + Notify(PSTR("\r\nDisconnected Control Channel"), 0x80); +#endif + pBtd->hci_disconnect(hci_handle); + hci_handle = -1; // Reset handle + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; + } + break; + } } + void WII::Run() { - switch (l2cap_state) { - case L2CAP_WAIT: - if(pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) { - pBtd->l2capConnectionClaimed = true; - activeConnection = true; + switch (l2cap_state) { + case L2CAP_WAIT: + if (pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) { + pBtd->l2capConnectionClaimed = true; + activeConnection = true; #ifdef DEBUG - Notify(PSTR("\r\nSend HID Control Connection Request")); + Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80); #endif - hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection - l2cap_event_flag = 0; // Reset flags - identifier = 0; - pBtd->l2cap_connection_request(hci_handle,identifier,control_dcid,HID_CTRL_PSM); - l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST; - } else if (l2cap_connection_request_control_flag) { + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + l2cap_event_flag = 0; // Reset flags + identifier = 0; + pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM); + l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST; + } else if (l2cap_connection_request_control_flag) { #ifdef DEBUG - Notify(PSTR("\r\nHID Control Incoming Connection Request")); + Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80); #endif - pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, PENDING); - delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, control_dcid, control_scid, SUCCESSFUL); - identifier++; - delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, control_scid); - l2cap_state = L2CAP_CONTROL_SUCCESS; - } - break; - - case L2CAP_CHECK_MOTION_PLUS_STATE: + pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, control_scid); + l2cap_state = L2CAP_CONTROL_SUCCESS; + } + break; + + case L2CAP_CHECK_MOTION_PLUS_STATE: #ifdef DEBUG - if(stateCounter == 0) // Only print onnce - Notify(PSTR("\r\nChecking if a Motion Plus is connected")); + if (stateCounter == 0) // Only print onnce + Notify(PSTR("\r\nChecking if a Motion Plus is connected"), 0x80); #endif - stateCounter++; - if(stateCounter%200 == 0) - checkMotionPresent(); // Check if there is a motion plus connected - if(motion_plus_connected_flag) { - stateCounter = 0; - l2cap_state = L2CAP_INIT_MOTION_PLUS_STATE; - timer = micros(); - - if(unknownExtensionConnected) { + stateCounter++; + if (stateCounter % 200 == 0) + checkMotionPresent(); // Check if there is a motion plus connected + if (motion_plus_connected_flag) { + stateCounter = 0; + l2cap_state = L2CAP_INIT_MOTION_PLUS_STATE; + timer = micros(); + + if (unknownExtensionConnected) { #ifdef DEBUG - Notify(PSTR("\r\nA extension is also connected")); + Notify(PSTR("\r\nA extension is also connected"), 0x80); #endif - activateNunchuck = true; // For we will just set this to true as this the only extension supported so far - } - - } - else if(stateCounter == 601) { // We will try three times to check for the motion plus -#ifdef DEBUG - Notify(PSTR("\r\nNo Motion Plus was detected")); -#endif - stateCounter = 0; - l2cap_state = L2CAP_CHECK_EXTENSION_STATE; - } - break; - - case L2CAP_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port + activateNunchuck = true; // For we will just set this to true as this the only extension supported so far + } + + } else if (stateCounter == 601) { // We will try three times to check for the motion plus #ifdef DEBUG - if(stateCounter == 0) // Only print onnce - Notify(PSTR("\r\nChecking if there is any extension connected")); + Notify(PSTR("\r\nNo Motion Plus was detected"), 0x80); #endif - stateCounter++; // We use this counter as there has to be a short delay between the commands - if(stateCounter == 1) - statusRequest(); // See if a new device has connected - if(stateCounter == 100) { - if(unknownExtensionConnected) // Check if there is a extension is connected to the port - initExtension1(); - else - stateCounter = 399; - } else if(stateCounter == 200) - initExtension2(); - else if(stateCounter == 300) { - readExtensionType(); - unknownExtensionConnected = false; - } else if(stateCounter == 400) { - stateCounter = 0; - l2cap_state = L2CAP_LED_STATE; - } - break; - - case L2CAP_INIT_MOTION_PLUS_STATE: - stateCounter++; - if(stateCounter == 1) - initMotionPlus(); - else if(stateCounter == 100) - activateMotionPlus(); - else if(stateCounter == 200) - readExtensionType(); // Check if it has been activated - else if(stateCounter == 300) { - stateCounter = 0; - unknownExtensionConnected = false; // The motion plus will send a status report when it's activated, we will set this to false so it doesn't reinitialize the Motion Plus - l2cap_state = L2CAP_LED_STATE; - } - break; - - case L2CAP_LED_STATE: - if(nunchuck_connected_flag) - nunchuckConnected = true; - setLedStatus(); - l2cap_state = L2CAP_DONE; - break; - - case L2CAP_DONE: - if(unknownExtensionConnected) { + stateCounter = 0; + l2cap_state = L2CAP_CHECK_EXTENSION_STATE; + } + break; + + case L2CAP_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port #ifdef DEBUG - if(stateCounter == 0) // Only print once - Notify(PSTR("\r\nChecking extension port")); + if (stateCounter == 0) // Only print onnce + Notify(PSTR("\r\nChecking if there is any extension connected"), 0x80); #endif - stateCounter++; // We will use this counter as there has to be a short delay between the commands - if(stateCounter == 50) - statusRequest(); - else if(stateCounter == 100) - initExtension1(); - else if(stateCounter == 150) - if((extensionConnected && motionPlusConnected) || (unknownExtensionConnected && !motionPlusConnected)) - initExtension2(); - else - stateCounter = 299; // There is no extension connected - else if(stateCounter == 200) - readExtensionType(); - else if(stateCounter == 250) { - if(nunchuck_connected_flag) { + stateCounter++; // We use this counter as there has to be a short delay between the commands + if (stateCounter == 1) + statusRequest(); // See if a new device has connected + if (stateCounter == 100) { + if (unknownExtensionConnected) // Check if there is a extension is connected to the port + initExtension1(); + else + stateCounter = 399; + } else if (stateCounter == 200) + initExtension2(); + else if (stateCounter == 300) { + readExtensionType(); + unknownExtensionConnected = false; + } else if (stateCounter == 400) { + stateCounter = 0; + l2cap_state = L2CAP_LED_STATE; + } + break; + + case L2CAP_INIT_MOTION_PLUS_STATE: + stateCounter++; + if (stateCounter == 1) + initMotionPlus(); + else if (stateCounter == 100) + activateMotionPlus(); + else if (stateCounter == 200) + readExtensionType(); // Check if it has been activated + else if (stateCounter == 300) { + stateCounter = 0; + unknownExtensionConnected = false; // The motion plus will send a status report when it's activated, we will set this to false so it doesn't reinitialize the Motion Plus + l2cap_state = L2CAP_LED_STATE; + } + break; + + case L2CAP_LED_STATE: + if (nunchuck_connected_flag) + nunchuckConnected = true; + setLedStatus(); + l2cap_state = L2CAP_DONE; + break; + + case L2CAP_DONE: + if (unknownExtensionConnected) { #ifdef DEBUG - Notify(PSTR("\r\nNunchuck was reconnected")); + if (stateCounter == 0) // Only print once + Notify(PSTR("\r\nChecking extension port"), 0x80); #endif - activateNunchuck = true; - nunchuckConnected = true; - } - if(!motionPlusConnected) - stateCounter = 449; - } - else if (stateCounter == 300) { - if(motionPlusConnected) { + stateCounter++; // We will use this counter as there has to be a short delay between the commands + if (stateCounter == 50) + statusRequest(); + else if (stateCounter == 100) + initExtension1(); + else if (stateCounter == 150) + if ((extensionConnected && motionPlusConnected) || (unknownExtensionConnected && !motionPlusConnected)) + initExtension2(); + else + stateCounter = 299; // There is no extension connected + else if (stateCounter == 200) + readExtensionType(); + else if (stateCounter == 250) { + if (nunchuck_connected_flag) { #ifdef DEBUG - Notify(PSTR("\r\nReactivating the Motion Plus")); + Notify(PSTR("\r\nNunchuck was reconnected"), 0x80); #endif - initMotionPlus(); - } else - stateCounter = 449; - } - else if(stateCounter == 350) - activateMotionPlus(); - else if(stateCounter == 400) - readExtensionType(); // Check if it has been activated - else if(stateCounter == 450) { - setLedStatus(); - stateCounter = 0; - unknownExtensionConnected = false; - } - } else - stateCounter = 0; - break; - } + activateNunchuck = true; + nunchuckConnected = true; + } + if (!motionPlusConnected) + stateCounter = 449; + } else if (stateCounter == 300) { + if (motionPlusConnected) { +#ifdef DEBUG + Notify(PSTR("\r\nReactivating the Motion Plus"), 0x80); +#endif + initMotionPlus(); + } else + stateCounter = 449; + } else if (stateCounter == 350) + activateMotionPlus(); + else if (stateCounter == 400) + readExtensionType(); // Check if it has been activated + else if (stateCounter == 450) { + setLedStatus(); + stateCounter = 0; + unknownExtensionConnected = false; + } + } else + stateCounter = 0; + break; + } } /************************************************************/ /* HID Commands */ + /************************************************************/ void WII::HID_Command(uint8_t* data, uint8_t nbytes) { - if(pBtd->motionPlusInside) - pBtd->L2CAP_Command(hci_handle,data,nbytes,interrupt_scid[0],interrupt_scid[1]); // It's the new wiimote with the Motion Plus Inside - else - pBtd->L2CAP_Command(hci_handle,data,nbytes,control_scid[0],control_scid[1]); + if (pBtd->motionPlusInside) + pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // It's the new wiimote with the Motion Plus Inside + else + pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); } -void WII::setAllOff() { - HIDBuffer[1] = 0x11; - HIDBuffer[2] = 0x00; - HID_Command(HIDBuffer, 3); -} -void WII::setRumbleOff() { - HIDBuffer[1] = 0x11; - HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble - HID_Command(HIDBuffer, 3); -} -void WII::setRumbleOn() { - HIDBuffer[1] = 0x11; - HIDBuffer[2] |= 0x01; // Bit 0 control the rumble - HID_Command(HIDBuffer, 3); -} -void WII::setRumbleToggle() { - HIDBuffer[1] = 0x11; - HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble - HID_Command(HIDBuffer, 3); -} -void WII::setLedOff(LED a) { - HIDBuffer[1] = 0x11; - HIDBuffer[2] &= ~(pgm_read_byte(&LEDS[(uint8_t)a])); - HID_Command(HIDBuffer, 3); -} -void WII::setLedOn(LED a) { - HIDBuffer[1] = 0x11; - HIDBuffer[2] |= pgm_read_byte(&LEDS[(uint8_t)a]); - HID_Command(HIDBuffer, 3); -} -void WII::setLedToggle(LED a) { - HIDBuffer[1] = 0x11; - HIDBuffer[2] ^= pgm_read_byte(&LEDS[(uint8_t)a]); - HID_Command(HIDBuffer, 3); -} -void WII::setLedStatus() { - HIDBuffer[1] = 0x11; - HIDBuffer[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit - if(wiimoteConnected) - HIDBuffer[2] |= 0x10; // If it's connected LED1 will light up - if(motionPlusConnected) - HIDBuffer[2] |= 0x20; // If it's connected LED2 will light up - if(nunchuckConnected) - HIDBuffer[2] |= 0x40; // If it's connected LED3 will light up - HID_Command(HIDBuffer, 3); +void WII::setAllOff() { + HIDBuffer[1] = 0x11; + HIDBuffer[2] = 0x00; + HID_Command(HIDBuffer, 3); } + +void WII::setRumbleOff() { + HIDBuffer[1] = 0x11; + HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble + HID_Command(HIDBuffer, 3); +} + +void WII::setRumbleOn() { + HIDBuffer[1] = 0x11; + HIDBuffer[2] |= 0x01; // Bit 0 control the rumble + HID_Command(HIDBuffer, 3); +} + +void WII::setRumbleToggle() { + HIDBuffer[1] = 0x11; + HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble + HID_Command(HIDBuffer, 3); +} + +void WII::setLedOff(LED a) { + HIDBuffer[1] = 0x11; + HIDBuffer[2] &= ~(pgm_read_byte(&LEDS[(uint8_t)a])); + HID_Command(HIDBuffer, 3); +} + +void WII::setLedOn(LED a) { + HIDBuffer[1] = 0x11; + HIDBuffer[2] |= pgm_read_byte(&LEDS[(uint8_t)a]); + HID_Command(HIDBuffer, 3); +} + +void WII::setLedToggle(LED a) { + HIDBuffer[1] = 0x11; + HIDBuffer[2] ^= pgm_read_byte(&LEDS[(uint8_t)a]); + HID_Command(HIDBuffer, 3); +} + +void WII::setLedStatus() { + HIDBuffer[1] = 0x11; + HIDBuffer[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit + if (wiimoteConnected) + HIDBuffer[2] |= 0x10; // If it's connected LED1 will light up + if (motionPlusConnected) + HIDBuffer[2] |= 0x20; // If it's connected LED2 will light up + if (nunchuckConnected) + HIDBuffer[2] |= 0x40; // If it's connected LED3 will light up + + HID_Command(HIDBuffer, 3); +} + void WII::setReportMode(bool continuous, uint8_t mode) { - uint8_t cmd_buf[4]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x12; - if(continuous) - cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit - else - cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Keep the rumble bit - cmd_buf[3] = mode; - HID_Command(cmd_buf, 4); + uint8_t cmd_buf[4]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x12; + if (continuous) + cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit + else + cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Keep the rumble bit + cmd_buf[3] = mode; + HID_Command(cmd_buf, 4); } + void WII::statusRequest() { - uint8_t cmd_buf[3]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x15; - cmd_buf[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit - HID_Command(cmd_buf, 3); + uint8_t cmd_buf[3]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x15; + cmd_buf[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit + HID_Command(cmd_buf, 3); } /************************************************************/ /* Memmory Commands */ + /************************************************************/ void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) { - uint8_t cmd_buf[23]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x16; // Write data - cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Write to memory, clear bit 2 to write to EEPROM - cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); - cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); - cmd_buf[5] = (uint8_t)(offset & 0xFF); - cmd_buf[6] = size; - uint8_t i = 0; - for(; i < size; i++) - cmd_buf[7+i] = data[i]; - for(; i < 16; i++) // Set the rest to zero - cmd_buf[7+i] = 0x00; - HID_Command(cmd_buf,23); + uint8_t cmd_buf[23]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x16; // Write data + cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Write to memory, clear bit 2 to write to EEPROM + cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); + cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); + cmd_buf[5] = (uint8_t)(offset & 0xFF); + cmd_buf[6] = size; + uint8_t i = 0; + for (; i < size; i++) + cmd_buf[7 + i] = data[i]; + for (; i < 16; i++) // Set the rest to zero + cmd_buf[7 + i] = 0x00; + HID_Command(cmd_buf, 23); } + void WII::initExtension1() { - uint8_t buf[1]; - buf[0] = 0x55; - writeData(0xA400F0,1,buf); + uint8_t buf[1]; + buf[0] = 0x55; + writeData(0xA400F0, 1, buf); } + void WII::initExtension2() { - uint8_t buf[1]; - buf[0] = 0x00; - writeData(0xA400FB,1,buf); + uint8_t buf[1]; + buf[0] = 0x00; + writeData(0xA400FB, 1, buf); } + void WII::initMotionPlus() { - uint8_t buf[1]; - buf[0] = 0x55; - writeData(0xA600F0,1,buf); + uint8_t buf[1]; + buf[0] = 0x55; + writeData(0xA600F0, 1, buf); } + void WII::activateMotionPlus() { - uint8_t buf[1]; - if(pBtd->wiiUProController) { + uint8_t buf[1]; + if (pBtd->wiiUProController) { #ifdef DEBUG - Notify(PSTR("\r\nActivating Wii U Pro Controller")); + Notify(PSTR("\r\nActivating Wii U Pro Controller"), 0x80); #endif - buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07 - } else if(activateNunchuck) { + buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07 + } else if (activateNunchuck) { #ifdef DEBUG - Notify(PSTR("\r\nActivating Motion Plus in pass-through mode")); + Notify(PSTR("\r\nActivating Motion Plus in pass-through mode"), 0x80); #endif - buf[0] = 0x05; // Activate nunchuck pass-through mode - } - //else if(classicControllerConnected && extensionConnected) - //buf[0] = 0x07; - else { + buf[0] = 0x05; // Activate nunchuck pass-through mode + } //else if(classicControllerConnected && extensionConnected) + //buf[0] = 0x07; + else { #ifdef DEBUG - Notify(PSTR("\r\nActivating Motion Plus in normal mode")); + Notify(PSTR("\r\nActivating Motion Plus in normal mode"), 0x80); #endif - buf[0] = 0x04; // Don't use any extension - } - writeData(0xA600FE,1,buf); + buf[0] = 0x04; // Don't use any extension + } + writeData(0xA600FE, 1, buf); } + void WII::readData(uint32_t offset, uint16_t size, bool EEPROM) { - uint8_t cmd_buf[8]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x17; // Read data - if(EEPROM) - cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Read from EEPROM - else - cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Read from memory - cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); - cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); - cmd_buf[5] = (uint8_t)(offset & 0xFF); - cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8); - cmd_buf[7] = (uint8_t)(size & 0xFF); - - HID_Command(cmd_buf,8); + uint8_t cmd_buf[8]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x17; // Read data + if (EEPROM) + cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Read from EEPROM + else + cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Read from memory + cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); + cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); + cmd_buf[5] = (uint8_t)(offset & 0xFF); + cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8); + cmd_buf[7] = (uint8_t)(size & 0xFF); + + HID_Command(cmd_buf, 8); } + void WII::readExtensionType() { - readData(0xA400FA,6,false); + readData(0xA400FA, 6, false); } + void WII::readCalData() { - readData(0x0016,8,true); + readData(0x0016, 8, true); } + void WII::checkMotionPresent() { - readData(0xA600FA,6,false); + readData(0xA600FA, 6, false); } /************************************************************/ /* WII Commands */ + /************************************************************/ bool WII::getButtonPress(Button b) { // Return true when a button is pressed - if(wiiUProControllerConnected) - return (ButtonState & pgm_read_dword(&PROCONTROLLERBUTTONS[(uint8_t)b])); - else - return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); + if (wiiUProControllerConnected) + return (ButtonState & pgm_read_dword(&PROCONTROLLERBUTTONS[(uint8_t)b])); + else + return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b])); } + bool WII::getButtonClick(Button b) { // Only return true when a button is clicked - uint32_t button; - if(wiiUProControllerConnected) - button = pgm_read_dword(&PROCONTROLLERBUTTONS[(uint8_t)b]); - else - button = pgm_read_dword(&BUTTONS[(uint8_t)b]); - bool click = (ButtonClickState & button); - ButtonClickState &= ~button; // clear "click" event - return click; + uint32_t button; + if (wiiUProControllerConnected) + button = pgm_read_dword(&PROCONTROLLERBUTTONS[(uint8_t)b]); + else + button = pgm_read_dword(&BUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; } + uint8_t WII::getAnalogHat(Hat a) { - if(!nunchuckConnected) - return 127; // Return center position - else { - uint8_t output = hatValues[(uint8_t)a]; - if(output == 0xFF || output == 0x00) // The joystick will only read 255 or 0 when the cable is unplugged or initializing, so we will just return the center position - return 127; - else - return output; - } + if (!nunchuckConnected) + return 127; // Return center position + else { + uint8_t output = hatValues[(uint8_t)a]; + if (output == 0xFF || output == 0x00) // The joystick will only read 255 or 0 when the cable is unplugged or initializing, so we will just return the center position + return 127; + else + return output; + } } + uint16_t WII::getAnalogHat(AnalogHat a) { - if(!wiiUProControllerConnected) - return 2000; - else { - uint16_t output = hatValues[(uint8_t)a]; - if(output == 0x00) // The joystick will only read 0 when it is first initializing, so we will just return the center position - return 2000; - else - return output; - } + if (!wiiUProControllerConnected) + return 2000; + else { + uint16_t output = hatValues[(uint8_t)a]; + if (output == 0x00) // The joystick will only read 0 when it is first initializing, so we will just return the center position + return 2000; + else + return output; + } } /************************************************************/ /* The following functions are for the IR camera */ @@ -1056,110 +1063,110 @@ uint16_t WII::getAnalogHat(AnalogHat a) { #ifdef WIICAMERA -void WII::IRinitialize(){ // Turns on and initialises the IR camera - +void WII::IRinitialize() { // Turns on and initialises the IR camera + enableIRCamera1(); #ifdef DEBUG - Notify(PSTR("\r\nEnable IR Camera1 Complete")); + Notify(PSTR("\r\nEnable IR Camera1 Complete"), 0x80); #endif delay(80); - + enableIRCamera2(); #ifdef DEBUG - Notify(PSTR("\r\nEnable IR Camera2 Complete")); + Notify(PSTR("\r\nEnable IR Camera2 Complete"), 0x80); #endif delay(80); - + write0x08Value(); #ifdef DEBUG - Notify(PSTR("\r\nWrote hex number 0x08")); + Notify(PSTR("\r\nWrote hex number 0x08"), 0x80); #endif delay(80); - + writeSensitivityBlock1(); #ifdef DEBUG - Notify(PSTR("\r\nWrote Sensitivity Block 1")); + Notify(PSTR("\r\nWrote Sensitivity Block 1"), 0x80); #endif delay(80); - + writeSensitivityBlock2(); #ifdef DEBUG - Notify(PSTR("\r\nWrote Sensitivity Block 2")); + Notify(PSTR("\r\nWrote Sensitivity Block 2"), 0x80); #endif delay(80); uint8_t mode_num = 0x03; setWiiModeNumber(mode_num); // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05 #ifdef DEBUG - Notify(PSTR("\r\nSet Wii Mode Number To 0x")); - PrintHex(mode_num); + Notify(PSTR("\r\nSet Wii Mode Number To 0x"), 0x80); + PrintHex (mode_num, 0x80); #endif delay(80); - + write0x08Value(); #ifdef DEBUG - Notify(PSTR("\r\nWrote Hex Number 0x08")); + Notify(PSTR("\r\nWrote Hex Number 0x08"), 0x80); #endif delay(80); setReportMode(false, 0x33); //setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet #ifdef DEBUG - Notify(PSTR("\r\nSet Report Mode to 0x33")); + Notify(PSTR("\r\nSet Report Mode to 0x33"), 0x80); #endif delay(80); - + statusRequest(); // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked #ifdef DEBUG - Notify(PSTR("\r\nIR Initialized")); -#endif + Notify(PSTR("\r\nIR Initialized"), 0x80); +#endif } -void WII::enableIRCamera1(){ - uint8_t cmd_buf[3]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x13; // Output report 13 - cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 - HID_Command(cmd_buf, 3); +void WII::enableIRCamera1() { + uint8_t cmd_buf[3]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x13; // Output report 13 + cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 + HID_Command(cmd_buf, 3); } -void WII::enableIRCamera2(){ - uint8_t cmd_buf[3]; - cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) - cmd_buf[1] = 0x1A; // Output report 1A - cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 - HID_Command(cmd_buf, 3); +void WII::enableIRCamera2() { + uint8_t cmd_buf[3]; + cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + cmd_buf[1] = 0x1A; // Output report 1A + cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 + HID_Command(cmd_buf, 3); } -void WII::writeSensitivityBlock1(){ - uint8_t buf[9]; - buf[0] = 0x00; - buf[1] = 0x00; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = 0x00; - buf[5] = 0x00; - buf[6] = 0x90; - buf[7] = 0x00; - buf[8] = 0x41; +void WII::writeSensitivityBlock1() { + uint8_t buf[9]; + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x90; + buf[7] = 0x00; + buf[8] = 0x41; - writeData(0xB00000, 9, buf); + writeData(0xB00000, 9, buf); } -void WII::writeSensitivityBlock2(){ - uint8_t buf[2]; - buf[0] = 0x40; - buf[1] = 0x00; +void WII::writeSensitivityBlock2() { + uint8_t buf[2]; + buf[0] = 0x40; + buf[1] = 0x00; - writeData(0xB0001A, 2, buf); + writeData(0xB0001A, 2, buf); } -void WII::write0x08Value(){ - uint8_t cmd = 0x08; - writeData(0xb00030, 1, &cmd); +void WII::write0x08Value() { + uint8_t cmd = 0x08; + writeData(0xb00030, 1, &cmd); } -void WII::setWiiModeNumber(uint8_t mode_number){ // mode_number in hex i.e. 0x03 for extended mode - writeData(0xb00033,1,&mode_number); +void WII::setWiiModeNumber(uint8_t mode_number) { // mode_number in hex i.e. 0x03 for extended mode + writeData(0xb00033, 1, &mode_number); } -#endif \ No newline at end of file +#endif diff --git a/Wii.h b/Wii.h index d6540704..6ffe6803 100755 --- a/Wii.h +++ b/Wii.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -39,7 +39,7 @@ #define L2CAP_CONTROL_CONNECT_REQUEST 3 #define L2CAP_CONTROL_CONFIG_REQUEST 4 #define L2CAP_INTERRUPT_CONNECT_REQUEST 5 - + #define L2CAP_INTERRUPT_CONFIG_REQUEST 6 #define L2CAP_CHECK_MOTION_PLUS_STATE 7 @@ -82,10 +82,10 @@ /** Enum used to read the joystick on the Nunchuck. */ enum Hat { - /** Read the x-axis on the Nunchuck joystick. */ - HatX = 0, - /** Read the y-axis on the Nunchuck joystick. */ - HatY = 1, + /** Read the x-axis on the Nunchuck joystick. */ + HatX = 0, + /** Read the y-axis on the Nunchuck joystick. */ + HatY = 1, }; /** @@ -95,347 +95,394 @@ enum Hat { */ class WII : public BluetoothService { public: - /** - * Constructor for the WII class. - * @param p Pointer to BTD class instance. - * @param pair Set this to true in order to pair with the Wiimote. If the argument is omitted then it won't pair with it. - * One can use ::PAIR to set it to true. - */ - WII(BTD *p, bool pair=false); + /** + * Constructor for the WII class. + * @param p Pointer to BTD class instance. + * @param pair Set this to true in order to pair with the Wiimote. If the argument is omitted then it won't pair with it. + * One can use ::PAIR to set it to true. + */ + WII(BTD *p, bool pair = false); - /** @name BluetoothService implementation */ - /** - * Used to pass acldata to the services. - * @param ACLData Incoming acldata. - */ - virtual void ACLData(uint8_t* ACLData); - /** Used to run part of the state maschine. */ - virtual void Run(); - /** Use this to reset the service. */ - virtual void Reset(); - /** Used this to disconnect any of the controllers. */ - virtual void disconnect(); - /**@}*/ + /** @name BluetoothService implementation */ + /** + * Used to pass acldata to the services. + * @param ACLData Incoming acldata. + */ + virtual void ACLData(uint8_t* ACLData); + /** Used to run part of the state maschine. */ + virtual void Run(); + /** Use this to reset the service. */ + virtual void Reset(); + /** Used this to disconnect any of the controllers. */ + virtual void disconnect(); + /**@}*/ - /** @name Wii 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). - */ - bool getButtonPress(Button b); - bool getButtonClick(Button b); - /**@}*/ + /** @name Wii 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). + */ + bool getButtonPress(Button b); + bool getButtonClick(Button b); + /**@}*/ - /** @name Wii Controller functions */ - /** - * Used to read the joystick of the Nunchuck. - * @param a Either ::HatX or ::HatY. - * @return Return the analog value in the range from approximately 25-230. - */ - uint8_t getAnalogHat(Hat a); - /** - * Used to read the joystick of the Wii U Pro Controller. - * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. - * @return Return the analog value in the range from approximately 800-3200. - */ - uint16_t getAnalogHat(AnalogHat a); + /** @name Wii Controller functions */ + /** + * Used to read the joystick of the Nunchuck. + * @param a Either ::HatX or ::HatY. + * @return Return the analog value in the range from approximately 25-230. + */ + uint8_t getAnalogHat(Hat a); + /** + * Used to read the joystick of the Wii U Pro Controller. + * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. + * @return Return the analog value in the range from approximately 800-3200. + */ + uint16_t getAnalogHat(AnalogHat a); - /** - * Pitch calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected. - * @return Pitch in the range from 0-360. - */ - double getPitch() { return pitch; }; - /** - * Roll calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected. - * @return Roll in the range from 0-360. - */ - double getRoll() { return roll; }; - /** - * This is the yaw calculated by the gyro. - * - * NOTE: This angle will drift a lot and is only available if the Motion Plus extension is connected. - * @return The angle calculated using the gyro. - */ - double getYaw() { return gyroYaw; }; - - /** Used to set all LEDs and rumble off. */ - void setAllOff(); - /** Turn off rumble. */ - void setRumbleOff(); - /** Turn on rumble. */ - void setRumbleOn(); - /** Toggle rumble. */ - void setRumbleToggle(); - /** - * Turn the specific ::LED off. - * @param a The ::LED to turn off. - */ - void setLedOff(LED a); - /** - * Turn the specific ::LED on. - * @param a The ::LED to turn on. - */ - void setLedOn(LED a); - /** - * Toggle the specific ::LED. - * @param a The ::LED to toggle. - */ - void setLedToggle(LED a); - /** - * This will set the LEDs, so the user can see which connections are active. - * - * The first ::LED indicate that the Wiimote is connected, - * - * the second ::LED indicate indicate that a Motion Plus is also connected - * - * the third ::LED will indicate that a Nunchuck controller is also connected. - */ - void setLedStatus(); + /** + * Pitch calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected. + * @return Pitch in the range from 0-360. + */ + double getPitch() { + return pitch; + }; - /** - * Return the battery level of the Wiimote. - * @return The battery level in the range 0-255. - */ - uint8_t getBatteryLevel() { return batteryLevel; }; - /** - * Return the Wiimote state. - * @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status. - */ - uint8_t getWiiState() { return wiiState; }; - /**@}*/ + /** + * Roll calculated from the Wiimote. A complimentary filter is used if the Motion Plus is connected. + * @return Roll in the range from 0-360. + */ + double getRoll() { + return roll; + }; - /**@{*/ - /** Variable used to indicate if a Wiimote is connected. */ - bool wiimoteConnected; - /** Variable used to indicate if a Nunchuck controller is connected. */ - bool nunchuckConnected; - /** Variable used to indicate if a Nunchuck controller is connected. */ - bool motionPlusConnected; - /** Variable used to indicate if a Wii U Pro controller is connected. */ - bool wiiUProControllerConnected; - /**@}*/ - - /* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */ - - /**@{*/ - /** Pitch and roll calculated from the accelerometer inside the Wiimote. */ - double wiimotePitch; - double wiimoteRoll; - /**@}*/ + /** + * This is the yaw calculated by the gyro. + * + * NOTE: This angle will drift a lot and is only available if the Motion Plus extension is connected. + * @return The angle calculated using the gyro. + */ + double getYaw() { + return gyroYaw; + }; - /**@{*/ - /** Pitch and roll calculated from the accelerometer inside the Nunchuck. */ - double nunchuckPitch; - double nunchuckRoll; - /**@}*/ + /** Used to set all LEDs and rumble off. */ + void setAllOff(); + /** Turn off rumble. */ + void setRumbleOff(); + /** Turn on rumble. */ + void setRumbleOn(); + /** Toggle rumble. */ + void setRumbleToggle(); + /** + * Turn the specific ::LED off. + * @param a The ::LED to turn off. + */ + void setLedOff(LED a); + /** + * Turn the specific ::LED on. + * @param a The ::LED to turn on. + */ + void setLedOn(LED a); + /** + * Toggle the specific ::LED. + * @param a The ::LED to toggle. + */ + void setLedToggle(LED a); + /** + * This will set the LEDs, so the user can see which connections are active. + * + * The first ::LED indicate that the Wiimote is connected, + * + * the second ::LED indicate indicate that a Motion Plus is also connected + * + * the third ::LED will indicate that a Nunchuck controller is also connected. + */ + void setLedStatus(); - /**@{*/ - /** Accelerometer values used to calculate pitch and roll. */ - int16_t accX; - int16_t accY; - int16_t accZ; - /**@}*/ + /** + * Return the battery level of the Wiimote. + * @return The battery level in the range 0-255. + */ + uint8_t getBatteryLevel() { + return batteryLevel; + }; - /* Variables for the gyro inside the Motion Plus */ - /** This is the pitch calculated by the gyro - use this to tune WII#pitchGyroScale. */ - double gyroPitch; - /** This is the roll calculated by the gyro - use this to tune WII#rollGyroScale. */ - double gyroRoll; - /** This is the yaw calculated by the gyro - use this to tune WII#yawGyroScale. */ - double gyroYaw; + /** + * Return the Wiimote state. + * @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status. + */ + uint8_t getWiiState() { + return wiiState; + }; + /**@}*/ - /**@{*/ - /** The speed in deg/s from the gyro. */ - double pitchGyroSpeed; - double rollGyroSpeed; - double yawGyroSpeed; - /**@}*/ - - /**@{*/ - /** You might need to fine-tune these values. */ - uint16_t pitchGyroScale; - uint16_t rollGyroScale; - uint16_t yawGyroScale; - /**@}*/ - - /**@{*/ - /** Raw value read directly from the Motion Plus. */ - int16_t gyroYawRaw; - int16_t gyroRollRaw; - int16_t gyroPitchRaw; - /**@}*/ - - /**@{*/ - /** These values are set when the controller is first initialized. */ - int16_t gyroYawZero; - int16_t gyroRollZero; - int16_t gyroPitchZero; - /**@}*/ + /**@{*/ + /** Variable used to indicate if a Wiimote is connected. */ + bool wiimoteConnected; + /** Variable used to indicate if a Nunchuck controller is connected. */ + bool nunchuckConnected; + /** Variable used to indicate if a Nunchuck controller is connected. */ + bool motionPlusConnected; + /** Variable used to indicate if a Wii U Pro controller is connected. */ + bool wiiUProControllerConnected; + /**@}*/ + + /* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */ + + /**@{*/ + /** Pitch and roll calculated from the accelerometer inside the Wiimote. */ + double wiimotePitch; + double wiimoteRoll; + /**@}*/ + + /**@{*/ + /** Pitch and roll calculated from the accelerometer inside the Nunchuck. */ + double nunchuckPitch; + double nunchuckRoll; + /**@}*/ + + /**@{*/ + /** Accelerometer values used to calculate pitch and roll. */ + int16_t accX; + int16_t accY; + int16_t accZ; + /**@}*/ + + /* Variables for the gyro inside the Motion Plus */ + /** This is the pitch calculated by the gyro - use this to tune WII#pitchGyroScale. */ + double gyroPitch; + /** This is the roll calculated by the gyro - use this to tune WII#rollGyroScale. */ + double gyroRoll; + /** This is the yaw calculated by the gyro - use this to tune WII#yawGyroScale. */ + double gyroYaw; + + /**@{*/ + /** The speed in deg/s from the gyro. */ + double pitchGyroSpeed; + double rollGyroSpeed; + double yawGyroSpeed; + /**@}*/ + + /**@{*/ + /** You might need to fine-tune these values. */ + uint16_t pitchGyroScale; + uint16_t rollGyroScale; + uint16_t yawGyroScale; + /**@}*/ + + /**@{*/ + /** Raw value read directly from the Motion Plus. */ + int16_t gyroYawRaw; + int16_t gyroRollRaw; + int16_t gyroPitchRaw; + /**@}*/ + + /**@{*/ + /** These values are set when the controller is first initialized. */ + int16_t gyroYawZero; + int16_t gyroRollZero; + int16_t gyroPitchZero; + /**@}*/ #ifdef WIICAMERA - /** @name Wiimote IR camera functions - * You will have to uncomment #WIICAMERA in Wii.h to use the IR camera. - */ - /** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */ - void IRinitialize(); + /** @name Wiimote IR camera functions + * You will have to uncomment #WIICAMERA in Wii.h to use the IR camera. + */ + /** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */ + void IRinitialize(); - /** - * IR object 1 x-position read from the Wii IR camera. - * @return The x-position of the object in the range 0-1023. - */ - uint16_t getIRx1() { return IR_object_x1; }; - /** - * IR object 1 y-position read from the Wii IR camera. - * @return The y-position of the object in the range 0-767. - */ - uint16_t getIRy1() { return IR_object_y1; }; - /** - * IR object 1 size read from the Wii IR camera. - * @return The size of the object in the range 0-15. - */ - uint8_t getIRs1() { return IR_object_s1; }; + /** + * IR object 1 x-position read from the Wii IR camera. + * @return The x-position of the object in the range 0-1023. + */ + uint16_t getIRx1() { + return IR_object_x1; + }; - /** - * IR object 2 x-position read from the Wii IR camera. - * @return The x-position of the object in the range 0-1023. - */ - uint16_t getIRx2() { return IR_object_x2; }; - /** - * IR object 2 y-position read from the Wii IR camera. - * @return The y-position of the object in the range 0-767. - */ - uint16_t getIRy2() { return IR_object_y2; }; - /** - * IR object 2 size read from the Wii IR camera. - * @return The size of the object in the range 0-15. - */ - uint8_t getIRs2() { return IR_object_s2; }; + /** + * IR object 1 y-position read from the Wii IR camera. + * @return The y-position of the object in the range 0-767. + */ + uint16_t getIRy1() { + return IR_object_y1; + }; - /** - * IR object 3 x-position read from the Wii IR camera. - * @return The x-position of the object in the range 0-1023. - */ - uint16_t getIRx3() { return IR_object_x3; }; - /** - * IR object 3 y-position read from the Wii IR camera. - * @return The y-position of the object in the range 0-767. - */ - uint16_t getIRy3() { return IR_object_y3; }; - /** - * IR object 3 size read from the Wii IR camera. - * @return The size of the object in the range 0-15. - */ - uint8_t getIRs3() { return IR_object_s3; }; + /** + * IR object 1 size read from the Wii IR camera. + * @return The size of the object in the range 0-15. + */ + uint8_t getIRs1() { + return IR_object_s1; + }; - /** - * IR object 4 x-position read from the Wii IR camera. - * @return The x-position of the object in the range 0-1023. - */ - uint16_t getIRx4() { return IR_object_x4; }; - /** - * IR object 4 y-position read from the Wii IR camera. - * @return The y-position of the object in the range 0-767. - */ - uint16_t getIRy4() { return IR_object_y4; }; - /** - * IR object 4 size read from the Wii IR camera. - * @return The size of the object in the range 0-15. - */ - uint8_t getIRs4() { return IR_object_s4; }; + /** + * IR object 2 x-position read from the Wii IR camera. + * @return The x-position of the object in the range 0-1023. + */ + uint16_t getIRx2() { + return IR_object_x2; + }; - /** - * Use this to check if the camera is enabled or not. - * If not call WII#IRinitialize to initialize the IR camera. - * @return True if it's enabled, false if not. - */ - bool isIRCameraEnabled() { return (wiiState & 0x08); }; - /**@}*/ + /** + * IR object 2 y-position read from the Wii IR camera. + * @return The y-position of the object in the range 0-767. + */ + uint16_t getIRy2() { + return IR_object_y2; + }; + + /** + * IR object 2 size read from the Wii IR camera. + * @return The size of the object in the range 0-15. + */ + uint8_t getIRs2() { + return IR_object_s2; + }; + + /** + * IR object 3 x-position read from the Wii IR camera. + * @return The x-position of the object in the range 0-1023. + */ + uint16_t getIRx3() { + return IR_object_x3; + }; + + /** + * IR object 3 y-position read from the Wii IR camera. + * @return The y-position of the object in the range 0-767. + */ + uint16_t getIRy3() { + return IR_object_y3; + }; + + /** + * IR object 3 size read from the Wii IR camera. + * @return The size of the object in the range 0-15. + */ + uint8_t getIRs3() { + return IR_object_s3; + }; + + /** + * IR object 4 x-position read from the Wii IR camera. + * @return The x-position of the object in the range 0-1023. + */ + uint16_t getIRx4() { + return IR_object_x4; + }; + + /** + * IR object 4 y-position read from the Wii IR camera. + * @return The y-position of the object in the range 0-767. + */ + uint16_t getIRy4() { + return IR_object_y4; + }; + + /** + * IR object 4 size read from the Wii IR camera. + * @return The size of the object in the range 0-15. + */ + uint8_t getIRs4() { + return IR_object_s4; + }; + + /** + * Use this to check if the camera is enabled or not. + * If not call WII#IRinitialize to initialize the IR camera. + * @return True if it's enabled, false if not. + */ + bool isIRCameraEnabled() { + return(wiiState & 0x08); + }; + /**@}*/ #endif - + private: - /* Mandatory members */ - BTD *pBtd; - - void L2CAP_task(); // L2CAP state machine - - /* Variables filled from HCI event management */ - uint16_t hci_handle; - bool activeConnection; // Used to indicate if it's already has established a connection - - /* variables used by high level L2CAP task */ - uint8_t l2cap_state; - uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events - - uint32_t ButtonState; - uint32_t OldButtonState; - uint32_t ButtonClickState; - uint16_t hatValues[4]; - - uint8_t HIDBuffer[3];// Used to store HID commands - - uint16_t stateCounter; - bool unknownExtensionConnected; - bool extensionConnected; - - /* L2CAP Channels */ - uint8_t control_scid[2]; // L2CAP source CID for HID_Control - uint8_t control_dcid[2]; // 0x0060 - uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt - uint8_t interrupt_dcid[2]; // 0x0061 - uint8_t identifier; // Identifier for connection - - /* HID Commands */ - void HID_Command(uint8_t* data, uint8_t nbytes); - void setReportMode(bool continuous, uint8_t mode); - void statusRequest(); - - void writeData(uint32_t offset, uint8_t size, uint8_t* data); - void initExtension1(); - void initExtension2(); - - void readData(uint32_t offset, uint16_t size, bool EEPROM); - void readExtensionType(); - void readCalData(); - - void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote - void initMotionPlus(); - void activateMotionPlus(); + /* Mandatory members */ + BTD *pBtd; - double pitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected - double roll; // Fusioned angle using a complimentary filter if the Motion Plus is connected - - bool activateNunchuck; - bool motionValuesReset; // This bool is true when the gyro values has been reset - unsigned long timer; + void L2CAP_task(); // L2CAP state machine + + /* Variables filled from HCI event management */ + uint16_t hci_handle; + bool activeConnection; // Used to indicate if it's already has established a connection + + /* variables used by high level L2CAP task */ + uint8_t l2cap_state; + uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events + + uint32_t ButtonState; + uint32_t OldButtonState; + uint32_t ButtonClickState; + uint16_t hatValues[4]; + + uint8_t HIDBuffer[3]; // Used to store HID commands + + uint16_t stateCounter; + bool unknownExtensionConnected; + bool extensionConnected; + + /* L2CAP Channels */ + uint8_t control_scid[2]; // L2CAP source CID for HID_Control + uint8_t control_dcid[2]; // 0x0060 + uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt + uint8_t interrupt_dcid[2]; // 0x0061 + uint8_t identifier; // Identifier for connection + + /* HID Commands */ + void HID_Command(uint8_t* data, uint8_t nbytes); + void setReportMode(bool continuous, uint8_t mode); + void statusRequest(); + + void writeData(uint32_t offset, uint8_t size, uint8_t* data); + void initExtension1(); + void initExtension2(); + + void readData(uint32_t offset, uint16_t size, bool EEPROM); + void readExtensionType(); + void readCalData(); + + void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote + void initMotionPlus(); + void activateMotionPlus(); + + double pitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected + double roll; // Fusioned angle using a complimentary filter if the Motion Plus is connected + + bool activateNunchuck; + bool motionValuesReset; // This bool is true when the gyro values has been reset + unsigned long timer; + + uint8_t wiiState; // Stores the value in l2capinbuf[12] - (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) + uint8_t batteryLevel; - uint8_t wiiState; // Stores the value in l2capinbuf[12] - (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) - uint8_t batteryLevel; - #ifdef WIICAMERA - /* Private function and variables for the readings from teh IR Camera */ - void enableIRCamera1(); // Sets bit 2 of output report 13 - void enableIRCamera2(); // Sets bit 2 of output report 1A - void writeSensitivityBlock1(); - void writeSensitivityBlock2(); - void write0x08Value(); - void setWiiModeNumber(uint8_t mode_number); - - uint16_t IR_object_x1; // IR x position 10 bits - uint16_t IR_object_y1; // IR y position 10 bits - uint8_t IR_object_s1; // IR size value - uint16_t IR_object_x2; - uint16_t IR_object_y2; - uint8_t IR_object_s2; - uint16_t IR_object_x3; // IR x position 10 bits - uint16_t IR_object_y3; // IR y position 10 bits - uint8_t IR_object_s3; // IR size value - uint16_t IR_object_x4; - uint16_t IR_object_y4; - uint8_t IR_object_s4; + /* Private function and variables for the readings from teh IR Camera */ + void enableIRCamera1(); // Sets bit 2 of output report 13 + void enableIRCamera2(); // Sets bit 2 of output report 1A + void writeSensitivityBlock1(); + void writeSensitivityBlock2(); + void write0x08Value(); + void setWiiModeNumber(uint8_t mode_number); + + uint16_t IR_object_x1; // IR x position 10 bits + uint16_t IR_object_y1; // IR y position 10 bits + uint8_t IR_object_s1; // IR size value + uint16_t IR_object_x2; + uint16_t IR_object_y2; + uint8_t IR_object_s2; + uint16_t IR_object_x3; // IR x position 10 bits + uint16_t IR_object_y3; // IR y position 10 bits + uint8_t IR_object_s3; // IR size value + uint16_t IR_object_x4; + uint16_t IR_object_y4; + uint8_t IR_object_s4; #endif }; #endif \ No newline at end of file diff --git a/XBOXRECV.cpp b/XBOXRECV.cpp index e4d0627a..72f34b50 100644 --- a/XBOXRECV.cpp +++ b/XBOXRECV.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -22,395 +22,411 @@ //#define EXTRADEBUG // Uncomment to get even more debugging data //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller -XBOXRECV::XBOXRECV(USB *p): +XBOXRECV::XBOXRECV(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; iRegisterDeviceClass(this); //set devConfig[] entry + 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 XBOXRECV::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(); + 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\nXBOXRECV Init")); + Notify(PSTR("\r\nXBOXRECV Init"), 0x80); #endif - // check if address has already been assigned to an instance - if (bAddress) { + // check if address has already been assigned to an instance + if (bAddress) { #ifdef DEBUG - Notify(PSTR("\r\nAddress in use")); + 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) { + 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 - Notify(PSTR("\r\nAddress not found")); + Notify(PSTR("\r\nAddress not found"), 0x80); #endif - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } - - if (!p->epinfo) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { #ifdef DEBUG - Notify(PSTR("\r\nepinfo is null")); + 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) // 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) { + 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) // 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 - Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work")); + Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80); +#endif + 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 + Notify(PSTR("\r\nsetAddr: "), 0x80); +#endif + PrintHex (rcode, 0x80); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + PrintHex (bAddress, 0x80); #endif - 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 - Notify(PSTR("\r\nsetAddr: ")); -#endif - PrintHex(rcode); - return rcode; - } -#ifdef EXTRADEBUG - Notify(PSTR("\r\nAddr: ")); - PrintHex(bAddress); -#endif - 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 XBOX360 Wireless receiver */ - - /* Initialize data structures for endpoints of device */ - epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms - epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0; - epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms - epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0; - - epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms - epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0; - epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms - epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0; - - epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms - epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0; - epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms - epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0; - - epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms - epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0; - epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms - epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = EP_INTERRUPT; - epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints - epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; - epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0; - epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0; - - rcode = pUsb->setEpInfoEntry(bAddress, 9, 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 FailSetConf; + + //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 XBOX360 Wireless receiver */ + + /* Initialize data structures for endpoints of device */ + epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms + epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0; + epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms + epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = bmRCVTOG0; + + epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms + epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0; + epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms + epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = bmRCVTOG0; + + epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms + epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0; + epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms + epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = bmRCVTOG0; + + epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms + epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0; + epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms + epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = EP_INTERRUPT; + epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints + epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; + epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = bmSNDTOG0; + epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = bmRCVTOG0; + + rcode = pUsb->setEpInfoEntry(bAddress, 9, 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 FailSetConf; #ifdef DEBUG - Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n")); + Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80); #endif - XboxReceiverConnected = true; - bPollEnable = true; - return 0; // successful configuration - - /* diagnostic messages */ + XboxReceiverConnected = true; + bPollEnable = true; + return 0; // successful configuration + + /* diagnostic messages */ FailGetDevDescr: #ifdef DEBUG - Notify(PSTR("\r\ngetDevDescr:")); + Notify(PSTR("\r\ngetDevDescr:"), 0x80); #endif - goto Fail; + goto Fail; FailSetDevTblEntry: #ifdef DEBUG - Notify(PSTR("\r\nsetDevTblEn:")); + Notify(PSTR("\r\nsetDevTblEn:"), 0x80); #endif - goto Fail; + goto Fail; FailSetConf: #ifdef DEBUG - Notify(PSTR("\r\nsetConf:")); + Notify(PSTR("\r\nsetConf:"), 0x80); #endif - goto Fail; + goto Fail; FailUnknownDevice: #ifdef DEBUG - Notify(PSTR("\r\nUnknown Device Connected - VID: ")); - PrintHex(VID); - Notify(PSTR(" PID: ")); - PrintHex(PID); + Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); + PrintHex (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + PrintHex (PID, 0x80); #endif - rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - goto Fail; + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + goto Fail; Fail: #ifdef DEBUG - Notify(PSTR("\r\nXbox 360 Init Failed, error code: ")); - Serial.print(rcode,HEX); -#endif - Release(); - return rcode; + Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80); + Serial.print(rcode, HEX); +#endif + Release(); + return rcode; } /* Performs a cleanup after failed Init() attempt */ uint8_t XBOXRECV::Release() { - XboxReceiverConnected = false; - for(uint8_t i=0;i<4;i++) - Xbox360Connected[i] = 0x00; - pUsb->GetAddressPool().FreeAddress(bAddress); - bAddress = 0; - bPollEnable = false; - return 0; + XboxReceiverConnected = false; + for (uint8_t i = 0; i < 4; i++) + Xbox360Connected[i] = 0x00; + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; + return 0; } -uint8_t XBOXRECV::Poll() { - if (!bPollEnable) - return 0; - if(!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds - timer = millis(); - checkStatus(); - } - uint8_t inputPipe; - uint16_t bufferSize; - for(uint8_t i=0;i<4;i++) { - switch (i) { - case 0: inputPipe = XBOX_INPUT_PIPE_1; break; - case 1: inputPipe = XBOX_INPUT_PIPE_2; break; - case 2: inputPipe = XBOX_INPUT_PIPE_3; break; - case 3: inputPipe = XBOX_INPUT_PIPE_4; break; + +uint8_t XBOXRECV::Poll() { + if (!bPollEnable) + return 0; + if (!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds + timer = millis(); + checkStatus(); } - bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive - pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf); - if(bufferSize > 0) { // The number of received bytes + uint8_t inputPipe; + uint16_t bufferSize; + for (uint8_t i = 0; i < 4; i++) { + switch (i) { + case 0: inputPipe = XBOX_INPUT_PIPE_1; + break; + case 1: inputPipe = XBOX_INPUT_PIPE_2; + break; + case 2: inputPipe = XBOX_INPUT_PIPE_3; + break; + case 3: inputPipe = XBOX_INPUT_PIPE_4; + break; + } + bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive + pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf); + if (bufferSize > 0) { // The number of received bytes #ifdef EXTRADEBUG - Notify(PSTR("Bytes Received: ")); - Serial.print(bufferSize); - Notify(PSTR("\r\n")); + Notify(PSTR("Bytes Received: "), 0x80); + Serial.print(bufferSize); + Notify(PSTR("\r\n"), 0x80); #endif - readReport(i); + readReport(i); #ifdef PRINTREPORT - printReport(i,bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller -#endif + printReport(i, bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller +#endif + } } - } - return 0; + return 0; } void XBOXRECV::readReport(uint8_t controller) { - if (readBuf == NULL) - return; - // This report is send when a controller is connected and disconnected - if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) { - Xbox360Connected[controller] = readBuf[1]; + if (readBuf == NULL) + return; + // 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 - Notify(PSTR("Controller ")); - Serial.print(controller); + Notify(PSTR("Controller "), 0x80); + Serial.print(controller); #endif - if(Xbox360Connected[controller]) { + if (Xbox360Connected[controller]) { #ifdef DEBUG - char* str = 0; - switch(readBuf[1]) { - case 0x80: str = PSTR(" as controller\r\n"); break; - case 0x40: str = PSTR(" as headset\r\n"); break; - case 0xC0: str = PSTR(" as controller+headset\r\n"); break; - } - Notify(PSTR(": connected")); - Notify(str); + char* str = 0; + switch (readBuf[1]) { + case 0x80: str = PSTR(" as controller\r\n"); + break; + case 0x40: str = PSTR(" as headset\r\n"); + break; + case 0xC0: str = PSTR(" as controller+headset\r\n"); + break; + } + 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(controller,led); + 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(controller, led); + } +#ifdef DEBUG + else + Notify(PSTR(": disconnected\r\n"), 0x80); +#endif + return; } -#ifdef DEBUG - else - Notify(PSTR(": disconnected\r\n")); -#endif - return; - } - // Controller status report - if(readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) { - controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4]; - return; - } - if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports - return; - - // A controller must be connected if it's sending data - if(!Xbox360Connected[controller]) - Xbox360Connected[controller] |= 0x80; + // Controller status report + if (readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) { + controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4]; + return; + } + if (readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports + return; - ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24)); - - hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); - hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); - hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]); - hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]); - - //Notify(PSTR("\r\nButtonState: ")); - //PrintHex(ButtonState[controller]); - - if(ButtonState[controller] != OldButtonState[controller]) { - buttonStateChanged[controller] = true; - ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 - if(((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons - R2Clicked[controller] = true; - if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0) - L2Clicked[controller] = true; - OldButtonState[controller] = ButtonState[controller]; - } + // A controller must be connected if it's sending data + if (!Xbox360Connected[controller]) + Xbox360Connected[controller] |= 0x80; + + ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24)); + + hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); + hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); + hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]); + hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]); + + //Notify(PSTR("\r\nButtonState: "), 0x80); + //PrintHex(ButtonState[controller], 0x80); + + if (ButtonState[controller] != OldButtonState[controller]) { + buttonStateChanged[controller] = true; + ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 + if (((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons + R2Clicked[controller] = true; + if ((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0) + L2Clicked[controller] = true; + OldButtonState[controller] = ButtonState[controller]; + } } void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller #ifdef PRINTREPORT - if (readBuf == NULL) - return; - Notify(PSTR("Controller ")); - Serial.print(controller); - Notify(PSTR(": ")); - for(uint8_t i = 0; i < nBytes;i++) { - PrintHex(readBuf[i]); - Serial.print(" "); - } - Serial.println(); + if (readBuf == NULL) + return; + Notify(PSTR("Controller "), 0x80); + Serial.print(controller); + Notify(PSTR(": "), 0x80); + for (uint8_t i = 0; i < nBytes; i++) { + PrintHex (readBuf[i], 0x80); + Serial.print(" "); + } + Serial.println(); #endif } + uint8_t XBOXRECV::getButtonPress(uint8_t controller, Button b) { - if(b == L2) // These are analog buttons - return (uint8_t)(ButtonState[controller] >> 8); - else if(b == R2) - return (uint8_t)ButtonState[controller]; - return (ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16)); + if (b == L2) // These are analog buttons + return (uint8_t)(ButtonState[controller] >> 8); + else if (b == R2) + return (uint8_t)ButtonState[controller]; + return (ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16)); } + bool XBOXRECV::getButtonClick(uint8_t controller, Button b) { - if(b == L2) { - if(L2Clicked[controller]) { - L2Clicked[controller] = false; - return true; + if (b == L2) { + if (L2Clicked[controller]) { + L2Clicked[controller] = false; + return true; + } + return false; + } else if (b == R2) { + if (R2Clicked[controller]) { + R2Clicked[controller] = false; + return true; + } + return false; } - return false; - } - else if(b == R2) { - if(R2Clicked[controller]) { - R2Clicked[controller] = false; - return true; - } - return false; - } - uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]); - bool click = (ButtonClickState[controller] & button); - ButtonClickState[controller] &= ~button; // clear "click" event - return click; + uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]); + bool click = (ButtonClickState[controller] & button); + ButtonClickState[controller] &= ~button; // clear "click" event + return click; } + int16_t XBOXRECV::getAnalogHat(uint8_t controller, AnalogHat a) { - return hatValue[controller][a]; + return hatValue[controller][a]; } + bool XBOXRECV::buttonChanged(uint8_t controller) { - bool state = buttonStateChanged[controller]; - buttonStateChanged[controller] = false; - return state; + bool state = buttonStateChanged[controller]; + buttonStateChanged[controller] = false; + return state; } + /* ControllerStatus Breakdown ControllerStatus[controller] & 0x0001 // 0 @@ -429,81 +445,90 @@ ControllerStatus Breakdown ControllerStatus[controller] & 0x2000 // 0 ControllerStatus[controller] & 0x4000 // 0 ControllerStatus[controller] & 0x8000 // 0 -*/ + */ uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) { - uint8_t batteryLevel = ((controllerStatus[controller] & 0x00C0) >> 6) * 33; - if(batteryLevel == 99) - batteryLevel = 100; - return batteryLevel; + uint8_t batteryLevel = ((controllerStatus[controller] & 0x00C0) >> 6) * 33; + if (batteryLevel == 99) + batteryLevel = 100; + return batteryLevel; } void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) { - uint8_t rcode; - uint8_t outputPipe; - switch (controller) { - case 0: outputPipe = XBOX_OUTPUT_PIPE_1; break; - case 1: outputPipe = XBOX_OUTPUT_PIPE_2; break; - case 2: outputPipe = XBOX_OUTPUT_PIPE_3; break; - case 3: outputPipe = XBOX_OUTPUT_PIPE_4; break; - } - rcode = pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data); + uint8_t rcode; + uint8_t outputPipe; + switch (controller) { + case 0: outputPipe = XBOX_OUTPUT_PIPE_1; + break; + case 1: outputPipe = XBOX_OUTPUT_PIPE_2; + break; + case 2: outputPipe = XBOX_OUTPUT_PIPE_3; + break; + case 3: outputPipe = XBOX_OUTPUT_PIPE_4; + break; + } + rcode = pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data); #ifdef EXTRADEBUG - if(rcode) - Notify(PSTR("Error sending Xbox message\r\n")); + if (rcode) + Notify(PSTR("Error sending Xbox message\r\n"), 0x80); #endif } + void XBOXRECV::setLedRaw(uint8_t controller, uint8_t value) { - writeBuf[0] = 0x00; - writeBuf[1] = 0x00; - writeBuf[2] = 0x08; - writeBuf[3] = value | 0x40; - - XboxCommand(controller, writeBuf, 4); + writeBuf[0] = 0x00; + writeBuf[1] = 0x00; + writeBuf[2] = 0x08; + writeBuf[3] = value | 0x40; + + XboxCommand(controller, writeBuf, 4); } + void XBOXRECV::setLedOn(uint8_t controller, LED led) { - if(led != ALL) // All LEDs can't be on a the same time - setLedRaw(controller,(pgm_read_byte(&XBOXLEDS[(uint8_t)led]))+4); + if (led != ALL) // All LEDs can't be on a the same time + setLedRaw(controller, (pgm_read_byte(&XBOXLEDS[(uint8_t)led])) + 4); } + void XBOXRECV::setLedBlink(uint8_t controller, LED led) { - setLedRaw(controller,pgm_read_byte(&XBOXLEDS[(uint8_t)led])); + setLedRaw(controller, pgm_read_byte(&XBOXLEDS[(uint8_t)led])); } + void XBOXRECV::setLedMode(uint8_t controller, LEDMode ledMode) { // This function is used to do some speciel LED stuff the controller supports - setLedRaw(controller,(uint8_t)ledMode); + setLedRaw(controller, (uint8_t)ledMode); } -/* PC runs this at interval of approx 2 seconds + +/* PC runs this at interval of approx 2 seconds Thanks to BusHound from Perisoft.net for the Windows USB Analysis output Found by timstamp.co.uk -*/ + */ void XBOXRECV::checkStatus() { - if(!bPollEnable) - return; - // Get controller info - writeBuf[0] = 0x08; - writeBuf[1] = 0x00; - writeBuf[2] = 0x0f; - writeBuf[3] = 0xc0; - for(uint8_t i=0; i<4; i++) { - XboxCommand(i, writeBuf, 4); - } - // Get battery status - writeBuf[0] = 0x00; - writeBuf[1] = 0x00; - writeBuf[2] = 0x00; - writeBuf[3] = 0x40; - for(uint8_t i=0; i<4; i++) { - if(Xbox360Connected[i]) - XboxCommand(i, writeBuf, 4); - } + if (!bPollEnable) + return; + // Get controller info + writeBuf[0] = 0x08; + writeBuf[1] = 0x00; + writeBuf[2] = 0x0f; + writeBuf[3] = 0xc0; + for (uint8_t i = 0; i < 4; i++) { + XboxCommand(i, writeBuf, 4); + } + // Get battery status + writeBuf[0] = 0x00; + writeBuf[1] = 0x00; + writeBuf[2] = 0x00; + writeBuf[3] = 0x40; + for (uint8_t i = 0; i < 4; i++) { + if (Xbox360Connected[i]) + XboxCommand(i, writeBuf, 4); + } } void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) { - writeBuf[0] = 0x00; - writeBuf[1] = 0x01; - writeBuf[2] = 0x0f; - writeBuf[3] = 0xc0; - writeBuf[4] = 0x00; - writeBuf[5] = lValue; // big weight - writeBuf[6] = rValue; // small weight - - XboxCommand(controller, writeBuf, 7); -} \ No newline at end of file + writeBuf[0] = 0x00; + writeBuf[1] = 0x01; + writeBuf[2] = 0x0f; + writeBuf[3] = 0xc0; + writeBuf[4] = 0x00; + writeBuf[5] = lValue; // big weight + writeBuf[6] = rValue; // small weight + + XboxCommand(controller, writeBuf, 7); +} diff --git a/XBOXRECV.h b/XBOXRECV.h index 6c7ed570..1235f201 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -27,7 +27,7 @@ #endif #include "Usb.h" -#include "xboxEnums.h" +#include "xboxEnums.h" /* Data Xbox 360 taken from descriptors */ #define EP_MAXPKTSIZE 32 // max size for data via USB @@ -62,167 +62,183 @@ */ class XBOXRECV : public USBDeviceConfig { public: - /** - * Constructor for the XBOXRECV class. - * @param pUsb Pointer to USB class instance. - */ - XBOXRECV(USB *pUsb); + /** + * Constructor for the XBOXRECV class. + * @param pUsb Pointer to USB class instance. + */ + XBOXRECV(USB *pUsb); - /** @name USBDeviceConfig implementation */ - /** - * Initialize the Xbox wireless receiver. - * @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; }; - /**@}*/ + /** @name USBDeviceConfig implementation */ + /** + * Initialize the Xbox wireless receiver. + * @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(); - /** @name Xbox Controller functions */ - /** - * getButtonPress(uint8_t controller, Button b) will return true as long as the button is held down. - * - * While getButtonClick(uint8_t controller, Button b) will only return it once. - * - * So you instance if you need to increase a variable once you would use getButtonClick(uint8_t controller, Button b), - * but if you need to drive a robot forward you would use getButtonPress(uint8_t controller, Button b). - * @param controller The controller to read from. - * @param b ::Button to read. - * @return getButtonClick(uint8_t controller, Button b) will return a bool, but getButtonPress(uint8_t controller, Button b) - * will return a byte if reading ::L2 or ::R2. - */ - uint8_t getButtonPress(uint8_t controller, Button b); - bool getButtonClick(uint8_t controller, Button b); - /**@}*/ + /** + * Get the device address. + * @return The device address. + */ + virtual uint8_t GetAddress() { + return bAddress; + }; - /** @name Xbox Controller functions */ - /** - * Return the analog value from the joysticks on the controller. - * @param controller The controller to read from. - * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. - * @return Returns a signed 16-bit integer. - */ - int16_t getAnalogHat(uint8_t controller, AnalogHat a); - /** - * Turn rumble off and all the LEDs on the specific controller. - * @param controller The controller to write to. - */ - void setAllOff(uint8_t controller) { setRumbleOn(controller,0,0); setLedOff(controller); }; - /** - * Turn rumble off the specific controller. - * @param controller The controller to write to. - */ - void setRumbleOff(uint8_t controller) { setRumbleOn(controller,0,0); }; - /** - * Turn rumble on. - * @param controller The controller to write to. - * @param lValue Left motor (big weight) inside the controller. - * @param rValue Right motor (small weight) inside the controller. - */ - void setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue); - /** - * Set LED value. Without using the ::LED or ::LEDMode enum. - * @param controller The controller to write to. - * @param value See: - * setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l), - * setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm). - */ - void setLedRaw(uint8_t controller, uint8_t value); - /** - * Turn all LEDs off the specific controller. - * @param controller The controller to write to. - */ - void setLedOff(uint8_t controller) { setLedRaw(controller,0); }; - /** - * Turn on a LED by using the ::LED enum. - * @param controller The controller to write to. - * @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. - */ - void setLedOn(uint8_t controller, LED l); - /** - * Turn on a LED by using the ::LED enum. - * @param controller The controller to write to. - * @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. - */ - void setLedBlink(uint8_t controller, LED l); - /** - * Used to set special LED modes supported by the Xbox controller. - * @param controller The controller to write to. - * @param lm See ::LEDMode. - */ - void setLedMode(uint8_t controller, LEDMode lm); - /** - * Used to get the battery level from the controller. - * @param controller The controller to read from. - * @return Returns the battery level in percentage in 33% steps. - */ - uint8_t getBatteryLevel(uint8_t controller); - /** - * Used to check if a button has changed. - * @param controller The controller to read from. - * @return True if a button has changed. - */ - bool buttonChanged(uint8_t controller); - /**@}*/ + /** + * Used to check if the controller has been initialized. + * @return True if it's ready. + */ + virtual bool isReady() { + return bPollEnable; + }; + /**@}*/ - /** True if a wireless receiver is connected. */ - bool XboxReceiverConnected; - /** Variable used to indicate if the XBOX 360 controller is successfully connected. */ - uint8_t Xbox360Connected[4]; - -protected: - /** Pointer to USB class instance. */ - USB *pUsb; - /** Device address. */ - uint8_t bAddress; - /** Endpoint info structure. */ - EpInfo epInfo[XBOX_MAX_ENDPOINTS]; - -private: - bool bPollEnable; + /** @name Xbox Controller functions */ + /** + * getButtonPress(uint8_t controller, Button b) will return true as long as the button is held down. + * + * While getButtonClick(uint8_t controller, Button b) will only return it once. + * + * So you instance if you need to increase a variable once you would use getButtonClick(uint8_t controller, Button b), + * but if you need to drive a robot forward you would use getButtonPress(uint8_t controller, Button b). + * @param controller The controller to read from. + * @param b ::Button to read. + * @return getButtonClick(uint8_t controller, Button b) will return a bool, but getButtonPress(uint8_t controller, Button b) + * will return a byte if reading ::L2 or ::R2. + */ + uint8_t getButtonPress(uint8_t controller, Button b); + bool getButtonClick(uint8_t controller, Button b); + /**@}*/ - /* Variables to store the buttons */ - uint32_t ButtonState[4]; - uint32_t OldButtonState[4]; - uint16_t ButtonClickState[4]; - int16_t hatValue[4][4]; - uint16_t controllerStatus[4]; - bool buttonStateChanged[4]; // True if a button has changed - - bool L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not - bool R2Clicked[4]; + /** @name Xbox Controller functions */ + /** + * Return the analog value from the joysticks on the controller. + * @param controller The controller to read from. + * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. + * @return Returns a signed 16-bit integer. + */ + int16_t getAnalogHat(uint8_t controller, AnalogHat a); - 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 - - void readReport(uint8_t controller); // read incoming data - void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging + /** + * Turn rumble off and all the LEDs on the specific controller. + * @param controller The controller to write to. + */ + void setAllOff(uint8_t controller) { + setRumbleOn(controller, 0, 0); + setLedOff(controller); + }; - /* Private commands */ - void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes); - void checkStatus(); + /** + * Turn rumble off the specific controller. + * @param controller The controller to write to. + */ + void setRumbleOff(uint8_t controller) { + setRumbleOn(controller, 0, 0); + }; + /** + * Turn rumble on. + * @param controller The controller to write to. + * @param lValue Left motor (big weight) inside the controller. + * @param rValue Right motor (small weight) inside the controller. + */ + void setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue); + /** + * Set LED value. Without using the ::LED or ::LEDMode enum. + * @param controller The controller to write to. + * @param value See: + * setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l), + * setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm). + */ + void setLedRaw(uint8_t controller, uint8_t value); + + /** + * Turn all LEDs off the specific controller. + * @param controller The controller to write to. + */ + void setLedOff(uint8_t controller) { + setLedRaw(controller, 0); + }; + /** + * Turn on a LED by using the ::LED enum. + * @param controller The controller to write to. + * @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. + */ + void setLedOn(uint8_t controller, LED l); + /** + * Turn on a LED by using the ::LED enum. + * @param controller The controller to write to. + * @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. + */ + void setLedBlink(uint8_t controller, LED l); + /** + * Used to set special LED modes supported by the Xbox controller. + * @param controller The controller to write to. + * @param lm See ::LEDMode. + */ + void setLedMode(uint8_t controller, LEDMode lm); + /** + * Used to get the battery level from the controller. + * @param controller The controller to read from. + * @return Returns the battery level in percentage in 33% steps. + */ + uint8_t getBatteryLevel(uint8_t controller); + /** + * Used to check if a button has changed. + * @param controller The controller to read from. + * @return True if a button has changed. + */ + bool buttonChanged(uint8_t controller); + /**@}*/ + + /** True if a wireless receiver is connected. */ + bool XboxReceiverConnected; + /** Variable used to indicate if the XBOX 360 controller is successfully connected. */ + uint8_t Xbox360Connected[4]; + +protected: + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[XBOX_MAX_ENDPOINTS]; + +private: + bool bPollEnable; + + /* Variables to store the buttons */ + uint32_t ButtonState[4]; + uint32_t OldButtonState[4]; + uint16_t ButtonClickState[4]; + int16_t hatValue[4][4]; + uint16_t controllerStatus[4]; + bool buttonStateChanged[4]; // True if a button has changed + + bool L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not + bool R2Clicked[4]; + + 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 + + void readReport(uint8_t controller); // read incoming data + void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging + + /* Private commands */ + void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes); + void checkStatus(); }; #endif \ No newline at end of file diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index c18d056f..89fdffd2 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -20,323 +20,329 @@ //#define EXTRADEBUG // Uncomment to get even more debugging data //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller -XBOXUSB::XBOXUSB(USB *p): +XBOXUSB::XBOXUSB(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; iRegisterDeviceClass(this); //set devConfig[] entry + 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 XBOXUSB::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(); + 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")); + Notify(PSTR("\r\nXBOXUSB Init"), 0x80); #endif - // check if address has already been assigned to an instance - if (bAddress) { + // check if address has already been assigned to an instance + if (bAddress) { #ifdef DEBUG - Notify(PSTR("\r\nAddress in use")); + 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) { + 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 - Notify(PSTR("\r\nAddress not found")); + Notify(PSTR("\r\nAddress not found"), 0x80); #endif - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } - - if (!p->epinfo) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { #ifdef DEBUG - Notify(PSTR("\r\nepinfo is null")); + 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) // We just check if it's a xbox controller using the Vendor ID - goto FailUnknownDevice; - if(PID == XBOX_WIRELESS_PID) { + 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) // We just check if it's a xbox controller using the Vendor ID + goto FailUnknownDevice; + if (PID == XBOX_WIRELESS_PID) { #ifdef DEBUG - Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication")); + 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) { + goto FailUnknownDevice; + } else if (PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { #ifdef DEBUG - Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB")); + Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80); +#endif + 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 + Notify(PSTR("\r\nsetAddr: "), 0x80); +#endif + PrintHex (rcode, 0x80); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + PrintHex (bAddress, 0x80); #endif - 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 - Notify(PSTR("\r\nsetAddr: ")); -#endif - PrintHex(rcode); - return rcode; - } -#ifdef EXTRADEBUG - Notify(PSTR("\r\nAddr: ")); - PrintHex(bAddress); -#endif - 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 XBOX360 Controllers */ - - /* Initialize data structures for endpoints of device */ - epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 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 360 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 FailSetConf; + + //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 XBOX360 Controllers */ + + /* Initialize data structures for endpoints of device */ + epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 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 360 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 FailSetConf; #ifdef DEBUG - Notify(PSTR("\r\nXbox 360 Controller Connected\r\n")); -#endif - setLedOn(LED1); - Xbox360Connected = true; - bPollEnable = true; - return 0; // successful configuration - - /* diagnostic messages */ + Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80); +#endif + setLedOn(LED1); + Xbox360Connected = true; + bPollEnable = true; + return 0; // successful configuration + + /* diagnostic messages */ FailGetDevDescr: #ifdef DEBUG - Notify(PSTR("\r\ngetDevDescr:")); + Notify(PSTR("\r\ngetDevDescr:"), 0x80); #endif - goto Fail; + goto Fail; FailSetDevTblEntry: #ifdef DEBUG - Notify(PSTR("\r\nsetDevTblEn:")); + Notify(PSTR("\r\nsetDevTblEn:"), 0x80); #endif - goto Fail; + goto Fail; FailSetConf: #ifdef DEBUG - Notify(PSTR("\r\nsetConf:")); + Notify(PSTR("\r\nsetConf:"), 0x80); #endif - goto Fail; + goto Fail; FailUnknownDevice: #ifdef DEBUG - Notify(PSTR("\r\nUnknown Device Connected - VID: ")); - PrintHex(VID); - Notify(PSTR(" PID: ")); - PrintHex(PID); + Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); + PrintHex (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + PrintHex (PID, 0x80); #endif - rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - goto Fail; + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + goto Fail; Fail: #ifdef DEBUG - Notify(PSTR("\r\nXbox 360 Init Failed, error code: ")); - Serial.print(rcode,HEX); -#endif - Release(); - return rcode; + Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80); + Serial.print(rcode, HEX); +#endif + Release(); + return rcode; } /* Performs a cleanup after failed Init() attempt */ uint8_t XBOXUSB::Release() { - Xbox360Connected = false; - pUsb->GetAddressPool().FreeAddress(bAddress); - bAddress = 0; - bPollEnable = false; - return 0; + Xbox360Connected = false; + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; + return 0; } -uint8_t XBOXUSB::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(); + +uint8_t XBOXUSB::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(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller + printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller #endif - return 0; + return 0; } -void XBOXUSB::readReport() { - if (readBuf == NULL) - return; - if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports - return; - } +void XBOXUSB::readReport() { + if (readBuf == NULL) + return; + if (readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports + return; + } - ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24)); - - hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]); - hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]); - hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); - hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); - - //Notify(PSTR("\r\nButtonState")); - //PrintHex(ButtonState); - - if(ButtonState != OldButtonState) { - ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 - if(((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons - R2Clicked = true; - if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0) - L2Clicked = true; - OldButtonState = ButtonState; - } -} + ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24)); + + hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]); + hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]); + hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); + hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); + + //Notify(PSTR("\r\nButtonState"), 0x80); + //PrintHex(ButtonState, 0x80); + + if (ButtonState != OldButtonState) { + ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 + if (((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons + R2Clicked = true; + if ((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0) + L2Clicked = true; + OldButtonState = ButtonState; + } +} void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller #ifdef PRINTREPORT - if (readBuf == NULL) - return; - for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE;i++) { - PrintHex(readBuf[i]); - Serial.print(" "); - } - Serial.println(); -#endif + if (readBuf == NULL) + return; + for (uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) { + PrintHex (readBuf[i], 0x80); + Serial.print(" "); + } + Serial.println(); +#endif } uint8_t XBOXUSB::getButtonPress(Button b) { - if(b == L2) // These are analog buttons - return (uint8_t)(ButtonState >> 8); - else if(b == R2) - return (uint8_t)ButtonState; - return (ButtonState & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16)); + if (b == L2) // These are analog buttons + return (uint8_t)(ButtonState >> 8); + else if (b == R2) + return (uint8_t)ButtonState; + return (ButtonState & ((uint32_t)pgm_read_word(&XBOXBUTTONS[(uint8_t)b]) << 16)); } + bool XBOXUSB::getButtonClick(Button b) { - if(b == L2) { - if(L2Clicked) { - L2Clicked = false; - return true; + if (b == L2) { + if (L2Clicked) { + L2Clicked = false; + return true; + } + return false; + } else if (b == R2) { + if (R2Clicked) { + R2Clicked = false; + return true; + } + return false; } - return false; - } - else if(b == R2) { - if(R2Clicked) { - R2Clicked = false; - return true; - } - return false; - } - uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]); - bool click = (ButtonClickState & button); - ButtonClickState &= ~button; // clear "click" event - return click; + uint16_t button = pgm_read_word(&XBOXBUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; } + int16_t XBOXUSB::getAnalogHat(AnalogHat a) { - return hatValue[a]; + return hatValue[a]; } /* Xbox Controller commands */ void XBOXUSB::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); + //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 XBOXUSB::setLedRaw(uint8_t value) { - writeBuf[0] = 0x01; - writeBuf[1] = 0x03; - writeBuf[2] = value; - - XboxCommand(writeBuf, 3); + writeBuf[0] = 0x01; + writeBuf[1] = 0x03; + writeBuf[2] = value; + + XboxCommand(writeBuf, 3); } + void XBOXUSB::setLedOn(LED led) { - if(led != ALL) // All LEDs can't be on a the same time - setLedRaw((pgm_read_byte(&XBOXLEDS[(uint8_t)led]))+4); + if (led != ALL) // All LEDs can't be on a the same time + setLedRaw((pgm_read_byte(&XBOXLEDS[(uint8_t)led])) + 4); } + void XBOXUSB::setLedBlink(LED led) { - setLedRaw(pgm_read_byte(&XBOXLEDS[(uint8_t)led])); + setLedRaw(pgm_read_byte(&XBOXLEDS[(uint8_t)led])); } + void XBOXUSB::setLedMode(LEDMode ledMode) { // This function is used to do some speciel LED stuff the controller supports - setLedRaw((uint8_t)ledMode); + setLedRaw((uint8_t)ledMode); } + void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) { - writeBuf[0] = 0x00; - writeBuf[1] = 0x08; - writeBuf[2] = 0x00; - writeBuf[3] = lValue; // big weight - writeBuf[4] = rValue; // small weight - writeBuf[5] = 0x00; - writeBuf[6] = 0x00; - writeBuf[7] = 0x00; - - XboxCommand(writeBuf, 8); -} \ No newline at end of file + writeBuf[0] = 0x00; + writeBuf[1] = 0x08; + writeBuf[2] = 0x00; + writeBuf[3] = lValue; // big weight + writeBuf[4] = rValue; // small weight + writeBuf[5] = 0x00; + writeBuf[6] = 0x00; + writeBuf[7] = 0x00; + + XboxCommand(writeBuf, 8); +} diff --git a/XBOXUSB.h b/XBOXUSB.h index ada5a48a..5f0621d3 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -25,7 +25,7 @@ #endif #include "Usb.h" -#include "xboxEnums.h" +#include "xboxEnums.h" /* Data Xbox 360 taken from descriptors */ #define EP_MAXPKTSIZE 32 // max size for data via USB @@ -58,135 +58,150 @@ /** This class implements support for a Xbox wired controller via USB. */ class XBOXUSB : public USBDeviceConfig { public: - /** - * Constructor for the XBOXUSB class. - * @param pUsb Pointer to USB class instance. - */ - XBOXUSB(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; }; - /**@}*/ - - /** @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); - /**@}*/ + /** + * Constructor for the XBOXUSB class. + * @param pUsb Pointer to USB class instance. + */ + XBOXUSB(USB *pUsb); - /** @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 and all the LEDs on the controller. */ - void setAllOff() { setRumbleOn(0,0); setLedRaw(0); }; - /** 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); - /** - * Set LED value. Without using the ::LED or ::LEDMode enum. - * @param value See: - * setLedOff(), setLedOn(LED l), - * setLedBlink(LED l), and setLedMode(LEDMode lm). - */ - void setLedRaw(uint8_t value); - /** Turn all LEDs off the controller. */ - void setLedOff() { setLedRaw(0); }; - /** - * Turn on a LED by using the ::LED enum. - * @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. - */ - void setLedOn(LED l); - /** - * Turn on a LED by using the ::LED enum. - * @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. - */ - void setLedBlink(LED l); - /** - * Used to set special LED modes supported by the Xbox controller. - * @param controller The controller to write to. - * @param lm See ::LEDMode. - */ - void setLedMode(LEDMode lm); - /**@}*/ - - /** True if a Xbox 360 controller is connected. */ - bool Xbox360Connected; - -protected: - /** Pointer to USB class instance. */ - USB *pUsb; - /** Device address. */ - uint8_t bAddress; - /** Endpoint info structure. */ - EpInfo epInfo[XBOX_MAX_ENDPOINTS]; - -private: - bool bPollEnable; + /** @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(); - /* Variables to store the buttons */ - uint32_t ButtonState; - uint32_t OldButtonState; - uint16_t ButtonClickState; - int16_t hatValue[4]; - uint16_t controllerStatus; - - bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not - bool R2Clicked; - - uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data - uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data - - void readReport(); // read incoming data - void printReport(); // print incoming date - Uncomment for debugging - - /* Private commands */ - void XboxCommand(uint8_t* data, uint16_t nbytes); + /** + * 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; + }; + /**@}*/ + + /** @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 and all the LEDs on the controller. */ + void setAllOff() { + setRumbleOn(0, 0); + setLedRaw(0); + }; + + /** 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); + /** + * Set LED value. Without using the ::LED or ::LEDMode enum. + * @param value See: + * setLedOff(), setLedOn(LED l), + * setLedBlink(LED l), and setLedMode(LEDMode lm). + */ + void setLedRaw(uint8_t value); + + /** Turn all LEDs off the controller. */ + void setLedOff() { + setLedRaw(0); + }; + /** + * Turn on a LED by using the ::LED enum. + * @param l ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. + */ + void setLedOn(LED l); + /** + * Turn on a LED by using the ::LED enum. + * @param l ::ALL, ::LED1, ::LED2, ::LED3 and ::LED4 is supported by the Xbox controller. + */ + void setLedBlink(LED l); + /** + * Used to set special LED modes supported by the Xbox controller. + * @param controller The controller to write to. + * @param lm See ::LEDMode. + */ + void setLedMode(LEDMode lm); + /**@}*/ + + /** True if a Xbox 360 controller is connected. */ + bool Xbox360Connected; + +protected: + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[XBOX_MAX_ENDPOINTS]; + +private: + bool bPollEnable; + + /* Variables to store the buttons */ + uint32_t ButtonState; + uint32_t OldButtonState; + uint16_t ButtonClickState; + int16_t hatValue[4]; + uint16_t controllerStatus; + + bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not + bool R2Clicked; + + uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data + uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data + + void readReport(); // read incoming data + void printReport(); // print incoming date - Uncomment for debugging + + /* Private commands */ + void XboxCommand(uint8_t* data, uint16_t nbytes); }; #endif diff --git a/address.h b/address.h index 19109958..b035aac6 100644 --- a/address.h +++ b/address.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ #if !defined(__ADDRESS_H__) #define __ADDRESS_H__ @@ -24,28 +24,25 @@ e-mail : support@circuitsathome.com /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */ /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */ -#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value -#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up +#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value +#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up #define USB_NAK_NOWAIT 1 //Single NAK stops transfer #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout -struct EpInfo -{ - uint8_t epAddr; // Endpoint address - uint8_t maxPktSize; // Maximum packet size +struct EpInfo { + uint8_t epAddr; // Endpoint address + uint8_t maxPktSize; // Maximum packet size - union - { - uint8_t epAttribs; + union { + uint8_t epAttribs; - struct - { - uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise - uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise - uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value - }; - }; -}; + struct { + uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise + uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise + uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value + } __attribute__((packed)); + }; +} __attribute__((packed)); // 7 6 5 4 3 2 1 0 // --------------------------------- @@ -56,40 +53,38 @@ struct EpInfo // P - parent hub address // A - device address / port number in case of hub // -struct UsbDeviceAddress -{ - union - { - struct - { - uint8_t bmAddress : 3; // device address/port number - uint8_t bmParent : 3; // parent hub address - uint8_t bmHub : 1; // hub flag - uint8_t bmReserved : 1; // reserved, must be zerro - }; - uint8_t devAddress; - }; -}; + +struct UsbDeviceAddress { + + union { + + struct { + uint8_t bmAddress : 3; // device address/port number + uint8_t bmParent : 3; // parent hub address + uint8_t bmHub : 1; // hub flag + uint8_t bmReserved : 1; // reserved, must be zerro + } __attribute__((packed)); + uint8_t devAddress; + }; +} __attribute__((packed)); #define bmUSB_DEV_ADDR_ADDRESS 0x07 #define bmUSB_DEV_ADDR_PARENT 0x38 #define bmUSB_DEV_ADDR_HUB 0x40 -struct UsbDevice -{ - EpInfo *epinfo; // endpoint info pointer - uint8_t address; // address - uint8_t epcount; // number of endpoints - bool lowspeed; // indicates if a device is the low speed one -// uint8_t devclass; // device class -}; +struct UsbDevice { + EpInfo *epinfo; // endpoint info pointer + uint8_t address; // address + uint8_t epcount; // number of endpoints + bool lowspeed; // indicates if a device is the low speed one + // uint8_t devclass; // device class +} __attribute__((packed)); -class AddressPool -{ +class AddressPool { public: - virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0; - virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0; - virtual void FreeAddress(uint8_t addr) = 0; + virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0; + virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0; + virtual void FreeAddress(uint8_t addr) = 0; }; typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); @@ -98,191 +93,180 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); #define ADDR_ERROR_INVALID_ADDRESS 0xFF template -class AddressPoolImpl : public AddressPool -{ - EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device +class AddressPoolImpl : public AddressPool { + EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device - uint8_t hubCounter; // hub counter is kept - // in order to avoid hub address duplication + uint8_t hubCounter; // hub counter is kept + // in order to avoid hub address duplication - UsbDevice thePool[MAX_DEVICES_ALLOWED]; + UsbDevice thePool[MAX_DEVICES_ALLOWED]; - // Initializes address pool entry - void InitEntry(uint8_t index) - { - thePool[index].address = 0; - thePool[index].epcount = 1; - thePool[index].lowspeed = 0; - thePool[index].epinfo = &dev0ep; - }; - // Returns thePool index for a given address - uint8_t FindAddressIndex(uint8_t address = 0) - { - for (uint8_t i=1; i=MAX_DEVICES_ALLOWED) ? 1 : start; ibmParent == addr.bmAddress) - return i; - } - return 0; - }; - // Frees address entry specified by index parameter - void FreeAddressByIndex(uint8_t index) - { - // Zerro field is reserved and should not be affected - if (index == 0) - return; + // Initializes address pool entry - // If a hub was switched off all port addresses should be freed - if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1) - { - for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); ) - FreeAddressByIndex(i); + void InitEntry(uint8_t index) { + thePool[index].address = 0; + thePool[index].epcount = 1; + thePool[index].lowspeed = 0; + thePool[index].epinfo = &dev0ep; + }; + // Returns thePool index for a given address - // If the hub had the last allocated address, hubCounter should be decremented - if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress) - hubCounter --; - } - InitEntry(index); - } - // Initializes the whole address pool at once - void InitAllAddresses() - { - for (uint8_t i=1; i= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) { + if(((UsbDeviceAddress*) & thePool[i].address)->bmParent == addr.bmAddress) + return i; + } + return 0; + }; + // Frees address entry specified by index parameter + + void FreeAddressByIndex(uint8_t index) { + // Zerro field is reserved and should not be affected + if(index == 0) + return; + + // If a hub was switched off all port addresses should be freed + if(((UsbDeviceAddress*) & thePool[index].address)->bmHub == 1) { + for(uint8_t i = 1; (i = FindChildIndex(*((UsbDeviceAddress*) & thePool[index].address), i));) + FreeAddressByIndex(i); + + // If the hub had the last allocated address, hubCounter should be decremented + if(hubCounter == ((UsbDeviceAddress*) & thePool[index].address)->bmAddress) + hubCounter--; + } + InitEntry(index); + } + // Initializes the whole address pool at once + + void InitAllAddresses() { + for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) + InitEntry(i); + + hubCounter = 0; + }; - hubCounter = 0; - }; - public: - AddressPoolImpl() : hubCounter(0) - { - // Zero address is reserved - InitEntry(0); - thePool[0].address = 0; - thePool[0].epinfo = &dev0ep; - dev0ep.epAddr = 0; - dev0ep.maxPktSize = 8; - dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0 - dev0ep.bmNakPower = USB_NAK_MAX_POWER; + AddressPoolImpl() : hubCounter(0) { + // Zero address is reserved + InitEntry(0); - InitAllAddresses(); - }; - // Returns a pointer to a specified address entry - virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) - { - if (!addr) - return thePool; + thePool[0].address = 0; + thePool[0].epinfo = &dev0ep; + dev0ep.epAddr = 0; + dev0ep.maxPktSize = 8; + dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0 + dev0ep.bmNakPower = USB_NAK_MAX_POWER; - uint8_t index = FindAddressIndex(addr); + InitAllAddresses(); + }; + // Returns a pointer to a specified address entry - return (!index) ? NULL : thePool + index; - }; - - // Performs an operation specified by pfunc for each addressed device - void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) - { - if (!pfunc) - return; + virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) { + if(!addr) + return thePool; - for (uint8_t i=1; i 127 || port > 7) - return 0; + return(!index) ? NULL : thePool + index; + }; - if (is_hub && hubCounter == 7) - return 0; + // Performs an operation specified by pfunc for each addressed device - // finds first empty address entry starting from one - uint8_t index = FindAddressIndex(0); + void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { + if(!pfunc) + return; - if (!index) // if empty entry is not found - return 0; + for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) + if(thePool[i].address) + pfunc(thePool + i); + }; + // Allocates new address - if (parent == 0) - { - if (is_hub) - { - thePool[index].address = 0x41; - hubCounter ++; - } - else - thePool[index].address = 1; + virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) { + /* if (parent != 0 && port == 0) + Serial.println("PRT:0"); */ - return thePool[index].address; - } + if(parent > 127 || port > 7) + return 0; - UsbDeviceAddress addr; + if(is_hub && hubCounter == 7) + return 0; - addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress; + // finds first empty address entry starting from one + uint8_t index = FindAddressIndex(0); - if (is_hub) - { - addr.bmHub = 1; - addr.bmAddress = ++hubCounter; - } - else - { - addr.bmHub = 0; - addr.bmAddress = port; - } - 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); -*/ - return thePool[index].address; - }; - // Empties pool entry - virtual void FreeAddress(uint8_t addr) - { - // if the root hub is disconnected all the addresses should be initialized - if (addr == 0x41) - { - InitAllAddresses(); - return; - } - uint8_t index = FindAddressIndex(addr); - FreeAddressByIndex(index); - }; - // Returns number of hubs attached - // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs. - //uint8_t GetNumHubs() - //{ - // return hubCounter; - //}; - //uint8_t GetNumDevices() - //{ - // uint8_t counter = 0; + if(!index) // if empty entry is not found + return 0; - // for (uint8_t i=1; ibmAddress; + + if(is_hub) { + addr.bmHub = 1; + addr.bmAddress = ++hubCounter; + } else { + addr.bmHub = 0; + addr.bmAddress = port; + } + 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); + */ + return thePool[index].address; + }; + // Empties pool entry + + virtual void FreeAddress(uint8_t addr) { + // if the root hub is disconnected all the addresses should be initialized + if(addr == 0x41) { + InitAllAddresses(); + return; + } + uint8_t index = FindAddressIndex(addr); + FreeAddressByIndex(index); + }; + // Returns number of hubs attached + // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs. + //uint8_t GetNumHubs() + //{ + // return hubCounter; + //}; + //uint8_t GetNumDevices() + //{ + // uint8_t counter = 0; + + // for (uint8_t i=1; iRegisterDeviceClass(this); //set devConfig[] entry - } -} - -/* 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; - 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(); -#ifdef DEBUG - USBTRACE("\r\nADK Init"); -#endif - // check if address has already been assigned to an instance - if (bAddress) { -#ifdef DEBUG - USBTRACE("\r\nAddress in use"); -#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 - USBTRACE("\r\nAddress not found"); -#endif - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } - - if (!p->epinfo) { -#ifdef DEBUG - USBTRACE("epinfo is null\r\n"); -#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 ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - if( rcode ){ - goto FailGetDevDescr; - } - - // Allocate new address according to device class - bAddress = addrPool.AllocAddress(parent, false, port); - - // 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; - //USBTRACE2("setAddr:",rcode); - return rcode; - }//if (rcode... - - //USBTRACE2("\r\nAddr:", bAddress); - - 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; - } - - //check if ADK device is already in accessory mode; if yes, configure and exit - if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID && - (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) { -#ifdef DEBUG - USBTRACE("\r\nAcc.mode device detected"); -#endif - /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */ - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - //USBTRACE2("\r\nNC:",num_of_conf); - - for (uint8_t i=0; i confDescrParser(this); - delay(1); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); -#if defined(XOOM) - //added by Jaylen Scott Vanorden - if( rcode ) { -#ifdef DEBUG - USBTRACE2("\r\nGot 1st bad code for config: ", rcode); -#endif - // Try once more - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - } -#endif - if( rcode ) { - goto FailGetConfDescr; - } - if( bNumEP > 2 ) { - break; - } - } // for (uint8_t i=0; isetEpInfoEntry(bAddress, 3, epInfo); - if (rcode) { - goto FailSetDevTblEntry; - } - } - - - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - if( rcode ){ - goto FailSetConf; - } - /* print endpoint structure */ -// USBTRACE("\r\nEndpoint Structure:"); -// USBTRACE("\r\nEP0:"); -// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr ); -// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize ); -// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs ); -// USBTRACE("\r\nEpout:"); -// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr ); -// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize ); -// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs ); -// USBTRACE("\r\nEpin:"); -// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr ); -// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize ); -// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs ); -#ifdef DEBUG - USBTRACE("\r\nConfiguration successful"); -#endif - ready = true; - return 0; //successful configuration - }//if( buf->idVendor == ADK_VID... - - //probe device - get accessory protocol revision - { - uint16_t adkproto = -1; - delay(1); - rcode = getProto((uint8_t*)&adkproto ); -#if defined(XOOM) - //added by Jaylen Scott Vanorden - if( rcode ) { -#ifdef DEBUG - USBTRACE2("\r\nGot 1st bad code for proto: ", rcode); -#endif - // Try once more - rcode = getProto((uint8_t*)&adkproto ); - } -#endif - if( rcode ){ - goto FailGetProto; //init fails - } -#ifdef DEBUG - USBTRACE2("\r\nADK protocol rev. ", adkproto ); -#endif - } - - //sending ID strings - sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer); - sendStr( ACCESSORY_STRING_MODEL, model); - sendStr( ACCESSORY_STRING_DESCRIPTION, description); - sendStr( ACCESSORY_STRING_VERSION, version); - sendStr( ACCESSORY_STRING_URI, uri); - sendStr( ACCESSORY_STRING_SERIAL, serial); - - //switch to accessory mode - //the Android phone will reset - rcode = switchAcc(); - if( rcode ) { - goto FailSwAcc; //init fails - } - rcode = -1; - goto SwAttempt; //switch to accessory mode attempted - - /* diagnostic messages */ -FailGetDevDescr: -#ifdef DEBUG - USBTRACE("\r\ngetDevDescr:"); -#endif - goto Fail; - -FailSetDevTblEntry: -#ifdef DEBUG - USBTRACE("\r\nsetDevTblEn:"); -#endif - goto Fail; - -FailGetProto: -#ifdef DEBUG - USBTRACE("\r\ngetProto:"); -#endif - goto Fail; - -FailSwAcc: -#ifdef DEBUG - USBTRACE("\r\nswAcc:"); -#endif - goto Fail; - -SwAttempt: -#ifdef DEBUG - USBTRACE("\r\nAccessory mode switch attempt"); -#endif - goto Fail; - -FailGetConfDescr: -// USBTRACE("getConf:"); - goto Fail; -// -FailSetConf: -// USBTRACE("setConf:"); - goto Fail; -// -//FailOnInit: -// USBTRACE("OnInit:"); -// goto Fail; -// -Fail: - //USBTRACE2("\r\nADK Init Failed, error code: ", rcode); - Release(); - return rcode; -} - -/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */ -void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) -{ - //ErrorMessage(PSTR("Conf.Val"), conf); - //ErrorMessage(PSTR("Iface Num"),iface); - //ErrorMessage(PSTR("Alt.Set"), alt); - - //added by Yuuichi Akagawa - if( bNumEP == 3 ) { - return; - } - - bConfNum = conf; - - uint8_t index; - - if ((pep->bmAttributes & 0x02) == 2) { - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; - } - - // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; - - bNumEP ++; - - //PrintEndpointDescriptor(pep); -} - -/* Performs a cleanup after failed Init() attempt */ -uint8_t ADK::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bNumEP = 1; //must have to be reset to 1 - - bAddress = 0; - ready = false; - return 0; -} - -uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) -{ - //USBTRACE2("\r\nAddr: ", bAddress ); - //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr); - return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); -} - -uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) -{ - return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); -} - -void ADK::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) -{ -#ifdef DEBUG - Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); - Notify(PSTR("\r\n")); -#endif -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +/* Google ADK interface */ + +#include "adk.h" + +const uint8_t ADK::epDataInIndex = 1; +const uint8_t ADK::epDataOutIndex = 2; + +ADK::ADK(USB *p, const char* manufacturer, + const char* model, + const char* description, + const char* version, + const char* uri, + const char* serial) : + +/* ADK ID Strings */ + +manufacturer(manufacturer), +model(model), +description(description), +version(version), +uri(uri), +serial(serial), +pUsb(p), //pointer to USB class instance - mandatory +bAddress(0), //device address - mandatory +bConfNum(0), //configuration number +bNumEP(1), //if config descriptor needs to be parsed +ready(false) { + // initialize endpoint data structures + for (uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2)); + }//for(uint8_t i=0; iRegisterDeviceClass(this); //set devConfig[] entry + } +} + +/* 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; + 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(); + + USBTRACE("\r\nADK Init"); + + // check if address has already been assigned to an instance + if (bAddress) { + USBTRACE("\r\nAddress in use"); + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + } + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) { + USBTRACE("\r\nAddress not found"); + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { + USBTRACE("epinfo is null\r\n"); + 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); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) { + goto FailGetDevDescr; + } + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + // 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; + //USBTRACE2("setAddr:",rcode); + return rcode; + }//if (rcode... + + //USBTRACE2("\r\nAddr:", bAddress); + + 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; + } + + //check if ADK device is already in accessory mode; if yes, configure and exit + if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID && + (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) { + USBTRACE("\r\nAcc.mode device detected"); + /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */ + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + //USBTRACE2("\r\nNC:",num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this); + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + if (rcode) { + goto FailGetConfDescr; + } + if (bNumEP > 2) { + break; + } + } // for (uint8_t i=0; isetEpInfoEntry(bAddress, 3, epInfo); + if (rcode) { + goto FailSetDevTblEntry; + } + } + + + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + if (rcode) { + goto FailSetConf; + } + /* print endpoint structure */ + // USBTRACE("\r\nEndpoint Structure:"); + // USBTRACE("\r\nEP0:"); + // USBTRACE2("\r\nAddr: ", epInfo[0].epAddr ); + // USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize ); + // USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs ); + // USBTRACE("\r\nEpout:"); + // USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr ); + // USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize ); + // USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs ); + // USBTRACE("\r\nEpin:"); + // USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr ); + // USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize ); + // USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs ); + + USBTRACE("\r\nConfiguration successful"); + ready = true; + return 0; //successful configuration + }//if( buf->idVendor == ADK_VID... + + //probe device - get accessory protocol revision + { + uint16_t adkproto = -1; + rcode = getProto((uint8_t*) & adkproto); + if (rcode) { + goto FailGetProto; //init fails + } + USBTRACE2("\r\nADK protocol rev. ", adkproto); + } + + //sending ID strings + sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer); + sendStr(ACCESSORY_STRING_MODEL, model); + sendStr(ACCESSORY_STRING_DESCRIPTION, description); + sendStr(ACCESSORY_STRING_VERSION, version); + sendStr(ACCESSORY_STRING_URI, uri); + sendStr(ACCESSORY_STRING_SERIAL, serial); + + //switch to accessory mode + //the Android phone will reset + rcode = switchAcc(); + if (rcode) { + goto FailSwAcc; //init fails + } + rcode = -1; + goto SwAttempt; //switch to accessory mode attempted + + /* diagnostic messages */ +FailGetDevDescr: + USBTRACE("\r\ngetDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("\r\nsetDevTblEn:"); + goto Fail; + +FailGetProto: + USBTRACE("\r\ngetProto:"); + goto Fail; + +FailSwAcc: + USBTRACE("\r\nswAcc:"); + goto Fail; + +SwAttempt: + USBTRACE("\r\nAccessory mode switch attempt"); + goto Fail; + +FailGetConfDescr: + // USBTRACE("getConf:"); + goto Fail; + // +FailSetConf: + // USBTRACE("setConf:"); + goto Fail; + // + //FailOnInit: + // USBTRACE("OnInit:"); + // goto Fail; + // +Fail: + //USBTRACE2("\r\nADK Init Failed, error code: ", rcode); + Release(); + return rcode; +} + +/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */ +void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { + //ErrorMessage(PSTR("Conf.Val"), conf); + //ErrorMessage(PSTR("Iface Num"),iface); + //ErrorMessage(PSTR("Alt.Set"), alt); + + //added by Yuuichi Akagawa + if (bNumEP == 3) { + return; + } + + bConfNum = conf; + + uint8_t index; + + // if ((pep->bmAttributes & 0x02) == 2) { + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + // } + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + + bNumEP++; + + //PrintEndpointDescriptor(pep); +} + +/* Performs a cleanup after failed Init() attempt */ +uint8_t ADK::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bNumEP = 1; //must have to be reset to 1 + + bAddress = 0; + ready = false; + return 0; +} + +uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { + //USBTRACE2("\r\nAddr: ", bAddress ); + //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr); + return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); +} + +uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) { + return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); +} + +void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (ep_ptr->bInterval, 0x80); + Notify(PSTR("\r\n"), 0x80); +} diff --git a/adk.h b/adk.h index 8084decb..4ea0ed63 100644 --- a/adk.h +++ b/adk.h @@ -1,145 +1,149 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ - -/* Google ADK interface support header */ - -#if !defined(_ADK_H_) -#define _ADK_H_ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#include "confdescparser.h" - -#define ADK_VID 0x18D1 -#define ADK_PID 0x2D00 -#define ADB_PID 0x2D01 - -#define XOOM //enables repeating getProto() and getConf() attempts - //necessary for slow devices such as Motorola XOOM - //defined by default, can be commented out to save memory - -/* requests */ - -#define ADK_GETPROTO 51 //check USB accessory protocol version -#define ADK_SENDSTR 52 //send identifying string -#define ADK_ACCSTART 53 //start device in accessory mode - -#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE -#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE - -#define ACCESSORY_STRING_MANUFACTURER 0 -#define ACCESSORY_STRING_MODEL 1 -#define ACCESSORY_STRING_DESCRIPTION 2 -#define ACCESSORY_STRING_VERSION 3 -#define ACCESSORY_STRING_URI 4 -#define ACCESSORY_STRING_SERIAL 5 - -#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT - -class ADK; - -class ADK : public USBDeviceConfig, public UsbConfigXtracter -{ -private: - /* ID strings */ - const char* manufacturer; - const char* model; - const char* description; - const char* version; - const char* uri; - const char* serial; - - /* ADK proprietary requests */ - uint8_t getProto( uint8_t* adkproto ); - uint8_t sendStr( uint8_t index, const char* str ); - uint8_t switchAcc( void ); - -protected: - static const uint8_t epDataInIndex; // DataIn endpoint index - static const uint8_t epDataOutIndex; // DataOUT endpoint index - - /* mandatory members */ - USB *pUsb; - uint8_t bAddress; - uint8_t bConfNum; // configuration number - - uint8_t bNumEP; // total number of EP in the configuration - bool ready; - - /* Endpoint data structure */ - EpInfo epInfo[ADK_MAX_ENDPOINTS]; - - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - -public: - ADK(USB *pUsb, const char* manufacturer, - const char* model, - const char* description, - const char* version, - const char* uri, - const char* serial); - - // Methods for receiving and sending data - uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); - uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); - - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(){}; //not implemented - virtual uint8_t GetAddress() { return bAddress; }; - virtual bool isReady() { return ready; }; - - //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 ... - -/* get ADK protocol version */ -/* returns 2 bytes in *adkproto */ -inline uint8_t ADK::getProto( uint8_t* adkproto ) -{ - return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL )); -} -/* send ADK string */ -inline uint8_t ADK::sendStr( uint8_t index, const char* str ) -{ - return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL)); -} -/* switch to accessory mode */ -inline uint8_t ADK::switchAcc( void ) -{ - return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL)); -} - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +/* Google ADK interface support header */ + +#if !defined(_ADK_H_) +#define _ADK_H_ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" + +#define ADK_VID 0x18D1 +#define ADK_PID 0x2D00 +#define ADB_PID 0x2D01 + +/* requests */ + +#define ADK_GETPROTO 51 //check USB accessory protocol version +#define ADK_SENDSTR 52 //send identifying string +#define ADK_ACCSTART 53 //start device in accessory mode + +#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE + +#define ACCESSORY_STRING_MANUFACTURER 0 +#define ACCESSORY_STRING_MODEL 1 +#define ACCESSORY_STRING_DESCRIPTION 2 +#define ACCESSORY_STRING_VERSION 3 +#define ACCESSORY_STRING_URI 4 +#define ACCESSORY_STRING_SERIAL 5 + +#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT + +class ADK; + +class ADK : public USBDeviceConfig, public UsbConfigXtracter { +private: + /* ID strings */ + const char* manufacturer; + const char* model; + const char* description; + const char* version; + const char* uri; + const char* serial; + + /* ADK proprietary requests */ + uint8_t getProto(uint8_t* adkproto); + uint8_t sendStr(uint8_t index, const char* str); + uint8_t switchAcc(void); + +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + + /* mandatory members */ + USB *pUsb; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + + uint8_t bNumEP; // total number of EP in the configuration + bool ready; + + /* Endpoint data structure */ + EpInfo epInfo[ADK_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + +public: + ADK(USB *pUsb, const char* manufacturer, + const char* model, + const char* description, + const char* version, + const char* uri, + const char* serial); + + // Methods for receiving and sending data + uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); + uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); + + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + + virtual uint8_t Poll() { + return 0; + }; + + virtual uint8_t GetAddress() { + return bAddress; + }; + + virtual bool isReady() { + return ready; + }; + + //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 ... + +/* get ADK protocol version */ + +/* returns 2 bytes in *adkproto */ +inline uint8_t ADK::getProto(uint8_t* adkproto) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL)); +} + +/* send ADK string */ +inline uint8_t ADK::sendStr(uint8_t index, const char* str) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*) str, NULL)); +} + +/* switch to accessory mode */ +inline uint8_t ADK::switchAcc(void) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL)); +} + #endif // _ADK_H_ \ No newline at end of file diff --git a/avrpins.h b/avrpins.h index f3b5ddb9..833f9f6b 100644 --- a/avrpins.h +++ b/avrpins.h @@ -13,24 +13,13 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* derived from Konstantin Chizhov's AVR port templates */ #ifndef _avrpins_h_ #define _avrpins_h_ -#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) -/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */ -//#define BOARD_MEGA_ADK -#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 #ifdef PORTA @@ -122,6 +111,7 @@ e-mail : support@circuitsathome.com }; #ifdef USE_PORTA + MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A') #endif #ifdef USE_PORTB @@ -171,238 +161,271 @@ MAKE_TCCR(TCCR1A, Tccr1a) MAKE_TCCR(TCCR2A, Tccr2a) #endif - // this class represents one pin in a IO port. - // It is fully static. - template - class TPin - { -// BOOST_STATIC_ASSERT(PIN < PORT::Width); - public: - typedef PORT Port; - enum{Number = PIN}; +// this class represents one pin in a IO port. +// It is fully static. +template +class TPin { + // BOOST_STATIC_ASSERT(PIN < PORT::Width); +public: + typedef PORT Port; - static void Set() { PORT::Set(1 << PIN); } + enum { + Number = PIN + }; - static void Set(uint8_t val){ - if(val) - Set(); - else Clear();} + static void Set() { + PORT::Set(1 << PIN); + } - static void SetDir(uint8_t val){ - if(val) - SetDirWrite(); - else SetDirRead();} + static void Set(uint8_t val) { + if(val) + Set(); + else Clear(); + } - static void Clear(){PORT::Clear(1 << PIN);} + static void SetDir(uint8_t val) { + if(val) + SetDirWrite(); + else SetDirRead(); + } - static void Toggle(){PORT::Toggle(1 << PIN);} + static void Clear() { + PORT::Clear(1 << PIN); + } - static void SetDirRead(){PORT::DirClear(1 << PIN);} + static void Toggle() { + PORT::Toggle(1 << PIN); + } - static void SetDirWrite(){PORT::DirSet(1 << PIN);} + static void SetDirRead() { + PORT::DirClear(1 << PIN); + } - static uint8_t IsSet(){return PORT::PinRead() & (uint8_t)(1 << PIN);} - - static void WaiteForSet(){ while(IsSet()==0){} } + static void SetDirWrite() { + PORT::DirSet(1 << PIN); + } - static void WaiteForClear(){ while(IsSet()){} } - }; //class TPin... + static uint8_t IsSet() { + return PORT::PinRead() & (uint8_t) (1 << PIN); + } - // this class represents one bit in TCCR port. - // used to set/clear TCCRx bits - // It is fully static. - template - class TCom - { -// BOOST_STATIC_ASSERT(PIN < PORT::Width); - public: - typedef TCCR Tccr; - enum{Com = COM}; + static void WaiteForSet() { + while(IsSet() == 0) { + } + } - static void Set() { TCCR::Set(1 << COM); } + static void WaiteForClear() { + while(IsSet()) { + } + } +}; //class TPin... - static void Clear() { TCCR::Clear(1 << COM); } +// this class represents one bit in TCCR port. +// used to set/clear TCCRx bits +// It is fully static. - static void Toggle() { TCCR::Toggle(1 << COM); } - }; //class TCom... +template +class TCom { + // BOOST_STATIC_ASSERT(PIN < PORT::Width); +public: + typedef TCCR Tccr; -//Short pin definitions + enum { + Com = COM + }; + + static void Set() { + TCCR::Set(1 << COM); + } + + static void Clear() { + TCCR::Clear(1 << COM); + } + + static void Toggle() { + TCCR::Toggle(1 << COM); + } +}; //class TCom... + +//Short pin definitions #ifdef USE_PORTA -typedef TPin Pa0; -typedef TPin Pa1; -typedef TPin Pa2; -typedef TPin Pa3; -typedef TPin Pa4; -typedef TPin Pa5; -typedef TPin Pa6; -typedef TPin Pa7; +typedef TPin Pa0; +typedef TPin Pa1; +typedef TPin Pa2; +typedef TPin Pa3; +typedef TPin Pa4; +typedef TPin Pa5; +typedef TPin Pa6; +typedef TPin Pa7; #endif #ifdef USE_PORTB -typedef TPin Pb0; -typedef TPin Pb1; -typedef TPin Pb2; -typedef TPin Pb3; -typedef TPin Pb4; -typedef TPin Pb5; -typedef TPin Pb6; -typedef TPin Pb7; +typedef TPin Pb0; +typedef TPin Pb1; +typedef TPin Pb2; +typedef TPin Pb3; +typedef TPin Pb4; +typedef TPin Pb5; +typedef TPin Pb6; +typedef TPin Pb7; #endif #ifdef USE_PORTC -typedef TPin Pc0; -typedef TPin Pc1; -typedef TPin Pc2; -typedef TPin Pc3; -typedef TPin Pc4; -typedef TPin Pc5; -typedef TPin Pc6; -typedef TPin Pc7; +typedef TPin Pc0; +typedef TPin Pc1; +typedef TPin Pc2; +typedef TPin Pc3; +typedef TPin Pc4; +typedef TPin Pc5; +typedef TPin Pc6; +typedef TPin Pc7; #endif #ifdef USE_PORTD -typedef TPin Pd0; -typedef TPin Pd1; -typedef TPin Pd2; -typedef TPin Pd3; -typedef TPin Pd4; -typedef TPin Pd5; -typedef TPin Pd6; -typedef TPin Pd7; +typedef TPin Pd0; +typedef TPin Pd1; +typedef TPin Pd2; +typedef TPin Pd3; +typedef TPin Pd4; +typedef TPin Pd5; +typedef TPin Pd6; +typedef TPin Pd7; #endif #ifdef USE_PORTE -typedef TPin Pe0; -typedef TPin Pe1; -typedef TPin Pe2; -typedef TPin Pe3; -typedef TPin Pe4; -typedef TPin Pe5; -typedef TPin Pe6; -typedef TPin Pe7; +typedef TPin Pe0; +typedef TPin Pe1; +typedef TPin Pe2; +typedef TPin Pe3; +typedef TPin Pe4; +typedef TPin Pe5; +typedef TPin Pe6; +typedef TPin Pe7; #endif #ifdef USE_PORTF -typedef TPin Pf0; -typedef TPin Pf1; -typedef TPin Pf2; -typedef TPin Pf3; -typedef TPin Pf4; -typedef TPin Pf5; -typedef TPin Pf6; -typedef TPin Pf7; +typedef TPin Pf0; +typedef TPin Pf1; +typedef TPin Pf2; +typedef TPin Pf3; +typedef TPin Pf4; +typedef TPin Pf5; +typedef TPin Pf6; +typedef TPin Pf7; #endif #ifdef USE_PORTG -typedef TPin Pg0; -typedef TPin Pg1; -typedef TPin Pg2; -typedef TPin Pg3; -typedef TPin Pg4; -typedef TPin Pg5; -typedef TPin Pg6; -typedef TPin Pg7; +typedef TPin Pg0; +typedef TPin Pg1; +typedef TPin Pg2; +typedef TPin Pg3; +typedef TPin Pg4; +typedef TPin Pg5; +typedef TPin Pg6; +typedef TPin Pg7; #endif #ifdef USE_PORTH -typedef TPin Ph0; -typedef TPin Ph1; -typedef TPin Ph2; -typedef TPin Ph3; -typedef TPin Ph4; -typedef TPin Ph5; -typedef TPin Ph6; -typedef TPin Ph7; +typedef TPin Ph0; +typedef TPin Ph1; +typedef TPin Ph2; +typedef TPin Ph3; +typedef TPin Ph4; +typedef TPin Ph5; +typedef TPin Ph6; +typedef TPin Ph7; #endif #ifdef USE_PORTJ -typedef TPin Pj0; -typedef TPin Pj1; -typedef TPin Pj2; -typedef TPin Pj3; -typedef TPin Pj4; -typedef TPin Pj5; -typedef TPin Pj6; -typedef TPin Pj7; +typedef TPin Pj0; +typedef TPin Pj1; +typedef TPin Pj2; +typedef TPin Pj3; +typedef TPin Pj4; +typedef TPin Pj5; +typedef TPin Pj6; +typedef TPin Pj7; #endif #ifdef USE_PORTK -typedef TPin Pk0; -typedef TPin Pk1; -typedef TPin Pk2; -typedef TPin Pk3; -typedef TPin Pk4; -typedef TPin Pk5; -typedef TPin Pk6; -typedef TPin Pk7; +typedef TPin Pk0; +typedef TPin Pk1; +typedef TPin Pk2; +typedef TPin Pk3; +typedef TPin Pk4; +typedef TPin Pk5; +typedef TPin Pk6; +typedef TPin Pk7; #endif #ifdef USE_PORTL -typedef TPin Pl0; -typedef TPin Pl1; -typedef TPin Pl2; -typedef TPin Pl3; -typedef TPin Pl4; -typedef TPin Pl5; -typedef TPin Pl6; -typedef TPin Pl7; +typedef TPin Pl0; +typedef TPin Pl1; +typedef TPin Pl2; +typedef TPin Pl3; +typedef TPin Pl4; +typedef TPin Pl5; +typedef TPin Pl6; +typedef TPin Pl7; #endif #ifdef USE_PORTQ -typedef TPin Pq0; -typedef TPin Pq1; -typedef TPin Pq2; -typedef TPin Pq3; -typedef TPin Pq4; -typedef TPin Pq5; -typedef TPin Pq6; -typedef TPin Pq7; +typedef TPin Pq0; +typedef TPin Pq1; +typedef TPin Pq2; +typedef TPin Pq3; +typedef TPin Pq4; +typedef TPin Pq5; +typedef TPin Pq6; +typedef TPin Pq7; #endif #ifdef USE_PORTR -typedef TPin Pr0; -typedef TPin Pr1; -typedef TPin Pr2; -typedef TPin Pr3; -typedef TPin Pr4; -typedef TPin Pr5; -typedef TPin Pr6; -typedef TPin Pr7; +typedef TPin Pr0; +typedef TPin Pr1; +typedef TPin Pr2; +typedef TPin Pr3; +typedef TPin Pr4; +typedef TPin Pr5; +typedef TPin Pr6; +typedef TPin Pr7; #endif #ifdef USE_TCCR0A -typedef TCom Tc0a; //P6 -typedef TCom Tc0b; //P5 +typedef TCom Tc0a; //P6 +typedef TCom Tc0b; //P5 #endif #ifdef USE_TCCR1A -typedef TCom Tc1a; //P9 -typedef TCom Tc1b; //P10 +typedef TCom Tc1a; //P9 +typedef TCom Tc1b; //P10 #endif #ifdef USE_TCCR2A -typedef TCom Tc2a; //P11 -typedef TCom Tc2b; //P3 +typedef TCom Tc2a; //P11 +typedef TCom Tc2b; //P3 #endif template - class Tp_Tc - { - public: - static void SetDir(uint8_t val){ - if(val) - SetDirWrite(); - else SetDirRead(); - } - static void SetDirRead(){ - Tp_pin::SetDirRead(); //set pin direction - Tc_bit::Clear(); //disconnect pin from PWM - } - static void SetDirWrite(){ - Tp_pin::SetDirWrite(); - Tc_bit::Clear(); - } - }; +class Tp_Tc { +public: + + static void SetDir(uint8_t val) { + if(val) + SetDirWrite(); + else SetDirRead(); + } + + static void SetDirRead() { + Tp_pin::SetDirRead(); //set pin direction + Tc_bit::Clear(); //disconnect pin from PWM + } + + static void SetDirWrite() { + Tp_pin::SetDirWrite(); + Tc_bit::Clear(); + } +}; /* pin definitions for cases where it's necessary to clear compare output mode bits */ @@ -416,7 +439,7 @@ template /* Arduino pin definitions */ #if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) -// "Mega" Arduino pin numbers +// "Mega" Arduino pin numbers #define P0 Pe0 #define P1 Pe1 @@ -424,7 +447,7 @@ template #define P3 Pe5 #define P4 Pg5 #define P5 Pe5 -#define P6 Ph3 +#define P6 Ph3 #define P7 Ph4 #define P8 Ph5 @@ -441,7 +464,7 @@ template #define P18 Pd3 #define P19 Pd2 #define P20 Pd1 -#define P21 Pd0 +#define P21 Pd0 #define P22 Pa0 #define P23 Pa1 @@ -476,7 +499,6 @@ template #define P51 Pb2 #define P52 Pb1 #define P53 Pb0 -#define P54 Pe6 // INT on Arduino ADK #endif //"Mega" pin numbers @@ -489,7 +511,7 @@ template #define P3 Pd3 #define P4 Pd4 #define P5 Pd5 -#define P6 Pd6 +#define P6 Pd6 #define P7 Pd7 #define P8 Pb0 @@ -508,47 +530,7 @@ template #endif // "Classic" Arduino pin numbers -#if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__) -// Arduino Leonardo pin numbers - -#define P0 Pd2 // D0 - PD2 -#define P1 Pd3 // D1 - PD3 -#define P2 Pd1 // D2 - PD1 -#define P3 Pd0 // D3 - PD0 -#define P4 Pd4 // D4 - PD4 -#define P5 Pc6 // D5 - PC6 -#define P6 Pd7 // D6 - PD7 -#define P7 Pe6 // D7 - PE6 - -#define P8 Pb4 // D8 - PB4 -#define P9 Pb5 // D9 - PB5 -#define P10 Pb6 // D10 - PB6 -#define P11 Pb7 // D11 - PB7 -#define P12 Pd6 // D12 - PD6 -#define P13 Pc7 // D13 - PC7 - -#define P14 Pb3 // D14 - MISO - PB3 -#define P15 Pb1 // D15 - SCK - PB1 -#define P16 Pb2 // D16 - MOSI - PB2 -#define P17 Pb0 // D17 - SS - PB0 - -#define P18 Pf7 // D18 - A0 - PF7 -#define P19 Pf6 // D19 - A1 - PF6 -#define P20 Pf5 // D20 - A2 - PF5 -#define P21 Pf4 // D21 - A3 - PF4 -#define P22 Pf1 // D22 - A4 - PF1 -#define P23 Pf0 // D23 - A5 - PF0 - -#define P24 Pd4 // D24 / D4 - A6 - PD4 -#define P25 Pd7 // D25 / D6 - A7 - PD7 -#define P26 Pb4 // D26 / D8 - A8 - PB4 -#define P27 Pb5 // D27 / D9 - A9 - PB5 -#define P28 Pb6 // D28 / D10 - A10 - PB6 -#define P29 Pd6 // D29 / D12 - A11 - PD6 - -#endif // Arduino Leonardo pin numbers - -#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega32U4__) // Teensy 2.0 pin numbers // http://www.pjrc.com/teensy/pinout.html #define P0 Pb0 @@ -629,45 +611,7 @@ template #define P45 Pf7 #endif // Teensy++ 2.0 -#if !defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)) -#define BOARD_BALANDUINO -// Balanduino pin numbers -// http://balanduino.net/ -#define P0 Pd0 /* 0 - PD0 */ -#define P1 Pd1 /* 1 - PD1 */ -#define P2 Pb2 /* 2 - PB2 */ -#define P3 Pd6 /* 3 - PD6 */ -#define P4 Pd7 /* 4 - PD7 */ -#define P5 Pb3 /* 5 - PB3 */ -#define P6 Pb4 /* 6 - PB4 */ -#define P7 Pa0 /* 7 - PA0 */ -#define P8 Pa1 /* 8 - PA1 */ -#define P9 Pa2 /* 9 - PA2 */ -#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 P15 Pd2 /* 15 - PD2 */ -#define P16 Pd3 /* 16 - PD3 */ -#define P17 Pd4 /* 17 - PD4 */ -#define P18 Pd5 /* 18 - PD5 */ -#define P19 Pc2 /* 19 - PC2 */ -#define P20 Pc3 /* 20 - PC3 */ -#define P21 Pc4 /* 21 - PC4 */ -#define P22 Pc5 /* 22 - PC5 */ -#define P23 Pc6 /* 23 - PC6 */ -#define P24 Pc7 /* 24 - PC7 */ -#define P25 Pb0 /* 25 - PB0 */ -#define P26 Pb1 /* 26 - PB1 */ -#define P27 Pb5 /* 27 - PB5 */ -#define P28 Pb6 /* 28 - PB6 */ -#define P29 Pb7 /* 29 - PB7 */ -#define P30 Pa6 /* 30 - PA6 */ -#define P31 Pa7 /* 31 - PA7 */ -#endif // Balanduino - -#if defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)) +#if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) // Sanguino pin numbers // http://sanguino.cc/hardware #define P0 Pb0 diff --git a/cdcacm.cpp b/cdcacm.cpp index e93e61eb..07e1e76a 100644 --- a/cdcacm.cpp +++ b/cdcacm.cpp @@ -1,359 +1,337 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "cdcacm.h" - -const uint8_t ACM::epDataInIndex = 1; -const uint8_t ACM::epDataOutIndex = 2; -const uint8_t ACM::epInterruptInIndex = 3; - -ACM::ACM(USB *p, CDCAsyncOper *pasync) : - pUsb(p), - pAsync(pasync), - bAddress(0), - qNextPollTime(0), - bPollEnable(false), - bControlIface(0), - bDataIface(0), - bNumEP(1), - ready(false) -{ - for(uint8_t i=0; iRegisterDeviceClass(this); -} - -uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); - - uint8_t buf[constBufSize]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t num_of_conf; // number of configurations - - AddressPool &addrPool = pUsb->GetAddressPool(); - - USBTRACE("ACM Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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, constBufSize, (uint8_t*)buf ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - if( rcode ) - goto FailGetDevDescr; - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - USBTRACE2("NC:", num_of_conf); - - for (uint8_t i=0; i CdcControlParser(this); - - ConfigDescParser CdcDataParser(this); - - rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser); - rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser); - - if (bNumEP > 1) - break; - } // for - - if (bNumEP < 4) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - - USBTRACE2("Conf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConf; - - rcode = pAsync->OnInit(this); - - if (rcode) - goto FailOnInit; - - USBTRACE("ACM configured\r\n"); - ready = true; - - //bPollEnable = true; - - //USBTRACE("Poll enabled\r\n"); - return 0; - -FailGetDevDescr: - USBTRACE("getDevDescr:"); - goto Fail; - -FailSetDevTblEntry: - USBTRACE("setDevTblEn:"); - goto Fail; - -FailGetConfDescr: - USBTRACE("getConf:"); - goto Fail; - -FailSetConf: - USBTRACE("setConf:"); - goto Fail; - -FailOnInit: - USBTRACE("OnInit:"); - goto Fail; - -Fail: - Serial.println(rcode, HEX); - Release(); - return rcode; -} - - -void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) -{ - //ErrorMessage(PSTR("Conf.Val"), conf); - //ErrorMessage(PSTR("Iface Num"),iface); - //ErrorMessage(PSTR("Alt.Set"), alt); - - bConfNum = conf; - - uint8_t index; - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - if ((pep->bmAttributes & 0x02) == 2) - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; - else - return; - - // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; - //epInfo[index].epAttribs = 0; - - bNumEP ++; - - //PrintEndpointDescriptor(pep); -} - -uint8_t ACM::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bControlIface = 0; - bDataIface = 0; - bNumEP = 1; - - bAddress = 0; - qNextPollTime = 0; - bPollEnable = false; - ready = false; - return 0; -} - -uint8_t ACM::Poll() -{ - uint8_t rcode = 0; - - if (!bPollEnable) - return 0; - - //uint32_t time_now = millis(); - - //if (qNextPollTime <= time_now) - //{ - // qNextPollTime = time_now + 100; - - // uint8_t rcode; - // const uint8_t constBufSize = 16; - // uint8_t buf[constBufSize]; - - // for (uint8_t i=0; i epInfo[epInterruptInIndex].maxPktSize) - // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; - // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); - - // if (rcode) - // return rcode; - - // for (uint8_t i=0; i(buf[i]); - // Serial.print(" "); - // } - // USBTRACE("\r\n"); - //} - return rcode; -} - -uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) -{ - return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); -} - -uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) -{ - return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); -} - -/* untested */ -uint8_t ACM::GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr ) -{ - return pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, bytes_rcvd, dataptr); -} - -uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL )); -} - -uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL )); -} - -uint8_t ACM::ClearCommFeature(uint16_t fid) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL )); -} - -uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); -} - -uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); -} - -uint8_t ACM::SetControlLineState(uint8_t state) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL )); -} - -uint8_t ACM::SendBreak(uint16_t duration) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL )); -} - - -void ACM::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) -{ - Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); - Notify(PSTR("\r\n")); -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "cdcacm.h" + +const uint8_t ACM::epDataInIndex = 1; +const uint8_t ACM::epDataOutIndex = 2; +const uint8_t ACM::epInterruptInIndex = 3; + +ACM::ACM(USB *p, CDCAsyncOper *pasync) : +pUsb(p), +pAsync(pasync), +bAddress(0), +bControlIface(0), +bDataIface(0), +bNumEP(1), +qNextPollTime(0), +bPollEnable(false) { + for (uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + //epInfo[i].bmNakPower = USB_NAK_NOWAIT; + epInfo[i].bmNakPower = USB_NAK_MAX_POWER; + + //if (!i) + epInfo[i].bmNakPower = USB_NAK_MAX_POWER; + } + if (pUsb) + pUsb->RegisterDeviceClass(this); +} + +uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("ACM Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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, constBufSize, (uint8_t*)buf); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) + goto FailGetDevDescr; + + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL, + CDC_SUBCLASS_ACM, + CDC_PROTOCOL_ITU_T_V_250, + CP_MASK_COMPARE_CLASS | + CP_MASK_COMPARE_SUBCLASS | + CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this); + + ConfigDescParser CdcDataParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser); + + if (rcode) + goto FailGetConfDescr; + + rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser); + + if (rcode) + goto FailGetConfDescr; + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 4) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConf; + + rcode = pAsync->OnInit(this); + + if (rcode) + goto FailOnInit; + + USBTRACE("ACM configured\r\n"); + + //bPollEnable = true; + + //USBTRACE("Poll enabled\r\n"); + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConf: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); + // Serial.println(rcode, HEX); + Release(); + return rcode; +} + +void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { + ErrorMessage (PSTR("Conf.Val"), conf); + ErrorMessage (PSTR("Iface Num"), iface); + ErrorMessage (PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if ((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + + PrintEndpointDescriptor(pep); +} + +uint8_t ACM::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bControlIface = 0; + bDataIface = 0; + bNumEP = 1; + + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +uint8_t ACM::Poll() { + uint8_t rcode = 0; + + if (!bPollEnable) + return 0; + + //uint32_t time_now = millis(); + + //if (qNextPollTime <= time_now) + //{ + // qNextPollTime = time_now + 100; + + // uint8_t rcode; + // const uint8_t constBufSize = 16; + // uint8_t buf[constBufSize]; + + // for (uint8_t i=0; i epInfo[epInterruptInIndex].maxPktSize) + // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; + // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); + + // if (rcode) + // return rcode; + + // for (uint8_t i=0; i(buf[i]); + // Serial.print(" "); + // } + // USBTRACE("\r\n"); + //} + return rcode; +} + +uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { + return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); +} + +uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) { + return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); +} + +uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL)); +} + +uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL)); +} + +uint8_t ACM::ClearCommFeature(uint16_t fid) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL)); +} + +uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL)); +} + +uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL)); +} + +uint8_t ACM::SetControlLineState(uint8_t state) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL)); +} + +uint8_t ACM::SendBreak(uint16_t duration) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL)); +} + +void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (ep_ptr->bInterval, 0x80); + Notify(PSTR("\r\n"), 0x80); +} diff --git a/cdcacm.h b/cdcacm.h index d8b8db55..34c92b93 100644 --- a/cdcacm.h +++ b/cdcacm.h @@ -1,211 +1,185 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__CDCACM_H__) -#define __CDCACM_H__ - -#include -#include -#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 -#endif - -#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 - -// CDC Subclass Constants -#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model -#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model -#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model -#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model -#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model -#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model -#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model -#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model -#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management -#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model -#define CDC_SUBCLASS_OBEX 0x0B // OBEX -#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model - -// Communication Interface Class Control Protocol Codes -#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250 -#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101 -#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O -#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07 -#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007 -#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA -#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model - -// CDC Commands defined by CDC 1.2 -#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 -#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 - -// CDC Commands defined by PSTN 1.2 -#define CDC_SET_COMM_FEATURE 0x02 -#define CDC_GET_COMM_FEATURE 0x03 -#define CDC_CLEAR_COMM_FEATURE 0x04 -#define CDC_SET_AUX_LINE_STATE 0x10 -#define CDC_SET_HOOK_STATE 0x11 -#define CDC_PULSE_SETUP 0x12 -#define CDC_SEND_PULSE 0x13 -#define CDC_SET_PULSE_TIME 0x14 -#define CDC_RING_AUX_JACK 0x15 -#define CDC_SET_LINE_CODING 0x20 -#define CDC_GET_LINE_CODING 0x21 -#define CDC_SET_CONTROL_LINE_STATE 0x22 -#define CDC_SEND_BREAK 0x23 -#define CDC_SET_RINGER_PARMS 0x30 -#define CDC_GET_RINGER_PARMS 0x31 -#define CDC_SET_OPERATION_PARMS 0x32 -#define CDC_GET_OPERATION_PARMS 0x33 -#define CDC_SET_LINE_PARMS 0x34 -#define CDC_GET_LINE_PARMS 0x35 -#define CDC_DIAL_DIGITS 0x36 - -//Class-Specific Notification Codes -#define NETWORK_CONNECTION 0x00 -#define RESPONSE_AVAILABLE 0x01 -#define AUX_JACK_HOOK_STATE 0x08 -#define RING_DETECT 0x09 -#define SERIAL_STATE 0x20 -#define CALL_STATE_CHANGE 0x28 -#define LINE_STATE_CHANGE 0x29 -#define CONNECTION_SPEED_CHANGE 0x2a - - -// CDC Functional Descriptor Structures -typedef struct -{ - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; - uint8_t bDataInterface; -} CALL_MGMNT_FUNC_DESCR; - -typedef struct -{ - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; -} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR, - TEL_CALL_STATE_REP_CPBL_FUNC_DESCR; - -typedef struct -{ - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bRingerVolSteps; - uint8_t bNumRingerPatterns; -} TEL_RINGER_FUNC_DESCR; - -typedef struct -{ - uint32_t dwDTERate; // Data Terminal Rate in bits per second - uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits - uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space - uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16) -} LINE_CODING; - -typedef struct -{ - uint8_t bmRequestType; // 0xa1 for class-specific notifications - uint8_t bNotification; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length -} CLASS_NOTIFICATION; - -class ACM; - -class CDCAsyncOper -{ -public: - virtual uint8_t OnInit(ACM *pacm) = 0; - //virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0; - //virtual void OnDisconnected(ACM *pacm) = 0; -}; - - -#define ACM_MAX_ENDPOINTS 4 - -class ACM : public USBDeviceConfig, public UsbConfigXtracter -{ -protected: - static const uint8_t epDataInIndex; // DataIn endpoint index - static const uint8_t epDataOutIndex; // DataOUT endpoint index - static const uint8_t epInterruptInIndex; // InterruptIN endpoint index - - USB *pUsb; - CDCAsyncOper *pAsync; - uint8_t bAddress; - uint8_t bConfNum; // configuration number - uint8_t bControlIface; // Control interface value - uint8_t bDataIface; // Data interface value - uint8_t bNumEP; // total number of EP in the configuration - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag - bool ready; //device ready indicator - - EpInfo epInfo[ACM_MAX_ENDPOINTS]; - - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - -public: - ACM(USB *pusb, CDCAsyncOper *pasync); - - uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); - uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); - uint8_t ClearCommFeature(uint16_t fid); - uint8_t SetLineCoding(const LINE_CODING *dataptr); - uint8_t GetLineCoding(LINE_CODING *dataptr); - uint8_t SetControlLineState(uint8_t state); - uint8_t SendBreak(uint16_t duration); - uint8_t GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr ); - - // Methods for recieving and sending data - uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); - uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; - virtual bool isReady() { return ready; }; - - // UsbConfigXtracter implementation - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); -}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__CDCACM_H__) +#define __CDCACM_H__ + +#include +#include +#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 +#endif + +#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 + +// CDC Subclass Constants +#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model +#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model +#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model +#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model +#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model +#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model +#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model +#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model +#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management +#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model +#define CDC_SUBCLASS_OBEX 0x0B // OBEX +#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model + +// Communication Interface Class Control Protocol Codes +#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250 +#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101 +#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O +#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07 +#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007 +#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA +#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model + +// CDC Commands defined by CDC 1.2 +#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 + +// CDC Commands defined by PSTN 1.2 +#define CDC_SET_COMM_FEATURE 0x02 +#define CDC_GET_COMM_FEATURE 0x03 +#define CDC_CLEAR_COMM_FEATURE 0x04 +#define CDC_SET_AUX_LINE_STATE 0x10 +#define CDC_SET_HOOK_STATE 0x11 +#define CDC_PULSE_SETUP 0x12 +#define CDC_SEND_PULSE 0x13 +#define CDC_SET_PULSE_TIME 0x14 +#define CDC_RING_AUX_JACK 0x15 +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 +#define CDC_SET_RINGER_PARMS 0x30 +#define CDC_GET_RINGER_PARMS 0x31 +#define CDC_SET_OPERATION_PARMS 0x32 +#define CDC_GET_OPERATION_PARMS 0x33 +#define CDC_SET_LINE_PARMS 0x34 +#define CDC_GET_LINE_PARMS 0x35 +#define CDC_DIAL_DIGITS 0x36 + +// CDC Functional Descriptor Structures + +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; +} CALL_MGMNT_FUNC_DESCR; + +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; +} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR, +TEL_CALL_STATE_REP_CPBL_FUNC_DESCR; + +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bRingerVolSteps; + uint8_t bNumRingerPatterns; +} TEL_RINGER_FUNC_DESCR; + +typedef struct { + uint32_t dwDTERate; // Data Terminal Rate in bits per second + uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits + uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space + uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16) +} LINE_CODING; + +class ACM; + +class CDCAsyncOper { +public: + virtual uint8_t OnInit(ACM *pacm) = 0; + //virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0; + //virtual void OnDisconnected(ACM *pacm) = 0; +}; + + +#define ACM_MAX_ENDPOINTS 4 + +class ACM : public USBDeviceConfig, public UsbConfigXtracter { +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + USB *pUsb; + CDCAsyncOper *pAsync; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bControlIface; // Control interface value + uint8_t bDataIface; // Data interface value + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + EpInfo epInfo[ACM_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + +public: + ACM(USB *pusb, CDCAsyncOper *pasync); + + uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); + uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); + uint8_t ClearCommFeature(uint16_t fid); + uint8_t SetLineCoding(const LINE_CODING *dataptr); + uint8_t GetLineCoding(LINE_CODING *dataptr); + uint8_t SetControlLineState(uint8_t state); + uint8_t SendBreak(uint16_t duration); + + // Methods for recieving and sending data + uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); + uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; + #endif // __CDCACM_H__ \ No newline at end of file diff --git a/cdcftdi.cpp b/cdcftdi.cpp index 4dbbc267..65f26cb5 100644 --- a/cdcftdi.cpp +++ b/cdcftdi.cpp @@ -1,348 +1,332 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "cdcftdi.h" - -const uint8_t FTDI::epDataInIndex = 1; -const uint8_t FTDI::epDataOutIndex = 2; -const uint8_t FTDI::epInterruptInIndex = 3; - -FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) : - pAsync(pasync), - pUsb(p), - bAddress(0), - bNumEP(1), - wFTDIType(0) -{ - for(uint8_t i=0; iRegisterDeviceClass(this); -} - -uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); - - uint8_t buf[constBufSize]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t len = 0; - uint16_t cd_len = 0; - - uint8_t num_of_conf; // number of configurations - uint8_t num_of_intf; // number of interfaces - - AddressPool &addrPool = pUsb->GetAddressPool(); - - USBTRACE("FTDI Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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 ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - if( rcode ) - goto FailGetDevDescr; - - if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - // Save type of FTDI chip - wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice; - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - USBTRACE2("NC:", num_of_conf); - - for (uint8_t i=0; i HexDump; - ConfigDescParser<0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this); - - rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - - if (bNumEP > 1) - break; - } // for - - if (bNumEP < 2) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - USBTRACE2("NumEP:", bNumEP); - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - - USBTRACE2("Conf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConfDescr; - - rcode = pAsync->OnInit(this); - - if (rcode) - goto FailOnInit; - - USBTRACE("FTDI configured\r\n"); - - bPollEnable = true; - return 0; - -FailGetDevDescr: - USBTRACE("getDevDescr:"); - goto Fail; - -FailSetDevTblEntry: - USBTRACE("setDevTblEn:"); - goto Fail; - -FailGetConfDescr: - USBTRACE("getConf:"); - goto Fail; - -FailSetConfDescr: - USBTRACE("setConf:"); - goto Fail; - -FailSetBaudRate: - USBTRACE("SetBaudRate:"); - goto Fail; - -FailSetFlowControl: - USBTRACE("SetFlowControl:"); - goto Fail; - -FailOnInit: - USBTRACE("OnInit:"); - goto Fail; - -Fail: - Serial.println(rcode, HEX); - Release(); - return rcode; -} - - -void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) -{ - ErrorMessage(PSTR("Conf.Val"), conf); - ErrorMessage(PSTR("Iface Num"),iface); - ErrorMessage(PSTR("Alt.Set"), alt); - - bConfNum = conf; - - uint8_t index; - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - if ((pep->bmAttributes & 0x02) == 2) - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; - else - return; - - // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; - //epInfo[index].epAttribs = 0; - - bNumEP ++; - - PrintEndpointDescriptor(pep); -} - -uint8_t FTDI::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bAddress = 0; - bNumEP = 1; - qNextPollTime = 0; - bPollEnable = false; - return 0; -} - -uint8_t FTDI::Poll() -{ - uint8_t rcode = 0; - - //if (!bPollEnable) - // return 0; - - //if (qNextPollTime <= millis()) - //{ - // Serial.println(bAddress, HEX); - - // qNextPollTime = millis() + 100; - //} - return rcode; -} - -uint8_t FTDI::SetBaudRate(uint32_t baud) -{ - uint16_t baud_value, baud_index = 0; - uint32_t divisor3; - - divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left - - if (wFTDIType == FT232AM) - { - if ((divisor3 & 0x7) == 7) - divisor3 ++; // round x.7/8 up to x+1 - - baud_value = divisor3 >> 3; - divisor3 &= 0x7; - - if (divisor3 == 1) baud_value |= 0xc000; else // 0.125 - if (divisor3 >= 4) baud_value |= 0x4000; else // 0.5 - if (divisor3 != 0) baud_value |= 0x8000; // 0.25 - if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */ - } - else - { - static const unsigned char divfrac [8] = { 0, 3, 2, 0, 1, 1, 2, 3 }; - static const unsigned char divindex[8] = { 0, 0, 0, 1, 0, 1, 1, 1 }; - - baud_value = divisor3 >> 3; - baud_value |= divfrac [divisor3 & 0x7] << 14; - baud_index = divindex[divisor3 & 0x7]; - - /* Deal with special cases for highest baud rates. */ - if (baud_value == 1) baud_value = 0; else // 1.0 - if (baud_value == 0x4001) baud_value = 1; // 1.5 - } - USBTRACE2("baud_value:", baud_value); - USBTRACE2("baud_index:", baud_index); - return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL ); -} - -uint8_t FTDI::SetModemControl(uint16_t signal) -{ - return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL); -} - -uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) -{ - return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL); -} - -uint8_t FTDI::SetData(uint16_t databm) -{ - return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL); -} - -uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) -{ - return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); -} - -uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) -{ - return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); -} - -void FTDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) -{ - Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); - Notify(PSTR("\r\n")); -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "cdcftdi.h" + +const uint8_t FTDI::epDataInIndex = 1; +const uint8_t FTDI::epDataOutIndex = 2; +const uint8_t FTDI::epInterruptInIndex = 3; + +FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) : +pAsync(pasync), +pUsb(p), +bAddress(0), +bNumEP(1), +wFTDIType(0) { + for (uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + + //if (!i) + epInfo[i].bmNakPower = USB_NAK_MAX_POWER; + } + if (pUsb) + pUsb->RegisterDeviceClass(this); +} + +uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + //uint8_t len = 0; + //uint16_t cd_len = 0; + + uint8_t num_of_conf; // number of configurations + //uint8_t num_of_intf; // number of interfaces + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("FTDI Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) + goto FailGetDevDescr; + + if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Save type of FTDI chip + wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice; + + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + HexDumper HexDump; + ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + + if (rcode) + goto FailGetConfDescr; + + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + + if (rcode) + goto FailGetConfDescr; + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 2) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + USBTRACE2("NumEP:", bNumEP); + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConfDescr; + + rcode = pAsync->OnInit(this); + + if (rcode) + goto FailOnInit; + + USBTRACE("FTDI configured\r\n"); + + bPollEnable = true; + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConfDescr: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.println(rcode, HEX); + Release(); + return rcode; +} + +void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { + ErrorMessage (PSTR("Conf.Val"), conf); + ErrorMessage (PSTR("Iface Num"), iface); + ErrorMessage (PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if ((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + + PrintEndpointDescriptor(pep); +} + +uint8_t FTDI::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bAddress = 0; + bNumEP = 1; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +uint8_t FTDI::Poll() { + uint8_t rcode = 0; + + //if (!bPollEnable) + // return 0; + + //if (qNextPollTime <= millis()) + //{ + // Serial.println(bAddress, HEX); + + // qNextPollTime = millis() + 100; + //} + return rcode; +} + +uint8_t FTDI::SetBaudRate(uint32_t baud) { + uint16_t baud_value, baud_index = 0; + uint32_t divisor3; + + divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left + + if (wFTDIType == FT232AM) { + if ((divisor3 & 0x7) == 7) + divisor3++; // round x.7/8 up to x+1 + + baud_value = divisor3 >> 3; + divisor3 &= 0x7; + + if (divisor3 == 1) baud_value |= 0xc000; + else // 0.125 + if (divisor3 >= 4) baud_value |= 0x4000; + else // 0.5 + if (divisor3 != 0) baud_value |= 0x8000; // 0.25 + if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */ + } else { + static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3}; + static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1}; + + baud_value = divisor3 >> 3; + baud_value |= divfrac [divisor3 & 0x7] << 14; + baud_index = divindex[divisor3 & 0x7]; + + /* Deal with special cases for highest baud rates. */ + if (baud_value == 1) baud_value = 0; + else // 1.0 + if (baud_value == 0x4001) baud_value = 1; // 1.5 + } + USBTRACE2("baud_value:", baud_value); + USBTRACE2("baud_index:", baud_index); + return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL); +} + +uint8_t FTDI::SetModemControl(uint16_t signal) { + return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL); +} + +uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) { + return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL); +} + +uint8_t FTDI::SetData(uint16_t databm) { + return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL); +} + +uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { + return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); +} + +uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) { + return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); +} + +void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (ep_ptr->bInterval, 0x80); + Notify(PSTR("\r\n"), 0x80); +} diff --git a/cdcftdi.h b/cdcftdi.h index 41d0650c..1bd26430 100644 --- a/cdcftdi.h +++ b/cdcftdi.h @@ -1,150 +1,151 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__CDCFTDI_H__) -#define __CDCFTDI_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#include "confdescparser.h" - -#define bmREQ_FTDI_OUT 0x40 -#define bmREQ_FTDI_IN 0xc0 - -//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE -//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE - -#define FTDI_VID 0x0403 // FTDI VID -#define FTDI_PID 0x6001 // FTDI PID - -#define FT232AM 0x0200 -#define FT232BM 0x0400 -#define FT2232 0x0500 -#define FT232R 0x0600 - -// Commands -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ - -#define FTDI_SIO_RESET_SIO 0 -#define FTDI_SIO_RESET_PURGE_RX 1 -#define FTDI_SIO_RESET_PURGE_TX 2 - -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 ) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 ) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 ) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 ) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 ) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) - -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8)) -#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8)) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 )) -#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 )) - -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 -#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) -#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) -#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) - -#define FTDI_SIO_CTS_MASK 0x10 -#define FTDI_SIO_DSR_MASK 0x20 -#define FTDI_SIO_RI_MASK 0x40 -#define FTDI_SIO_RLSD_MASK 0x80 - -class FTDI; - -class FTDIAsyncOper -{ -public: - virtual uint8_t OnInit(FTDI *pftdi) = 0; -}; - - -// Only single port chips are currently supported by the library, -// so only three endpoints are allocated. -#define FTDI_MAX_ENDPOINTS 3 - -class FTDI : public USBDeviceConfig, public UsbConfigXtracter -{ - static const uint8_t epDataInIndex; // DataIn endpoint index - static const uint8_t epDataOutIndex; // DataOUT endpoint index - static const uint8_t epInterruptInIndex; // InterruptIN endpoint index - - FTDIAsyncOper *pAsync; - USB *pUsb; - uint8_t bAddress; - uint8_t bConfNum; // configuration number - uint8_t bNumIface; // number of interfaces in the configuration - uint8_t bNumEP; // total number of EP in the configuration - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag - uint16_t wFTDIType; // Type of FTDI chip - - EpInfo epInfo[FTDI_MAX_ENDPOINTS]; - - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - -public: - FTDI(USB *pusb, FTDIAsyncOper *pasync); - - uint8_t SetBaudRate(uint32_t baud); - uint8_t SetModemControl(uint16_t control); - uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13); - uint8_t SetData(uint16_t databm); - - // Methods for recieving and sending data - uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr); - uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; - - // UsbConfigXtracter implementation - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); -}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__CDCFTDI_H__) +#define __CDCFTDI_H__ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" + +#define bmREQ_FTDI_OUT 0x40 +#define bmREQ_FTDI_IN 0xc0 + +//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE + +#define FTDI_VID 0x0403 // FTDI VID +#define FTDI_PID 0x6001 // FTDI PID + +#define FT232AM 0x0200 +#define FT232BM 0x0400 +#define FT2232 0x0500 +#define FT232R 0x0600 + +// Commands +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ + +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 + +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) + +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 )) +#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 )) + +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) +#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) +#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) + +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 + +class FTDI; + +class FTDIAsyncOper { +public: + virtual uint8_t OnInit(FTDI *pftdi) = 0; +}; + + +// Only single port chips are currently supported by the library, +// so only three endpoints are allocated. +#define FTDI_MAX_ENDPOINTS 3 + +class FTDI : public USBDeviceConfig, public UsbConfigXtracter { + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + FTDIAsyncOper *pAsync; + USB *pUsb; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bNumIface; // number of interfaces in the configuration + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + uint16_t wFTDIType; // Type of FTDI chip + + EpInfo epInfo[FTDI_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + +public: + FTDI(USB *pusb, FTDIAsyncOper *pasync); + + uint8_t SetBaudRate(uint32_t baud); + uint8_t SetModemControl(uint16_t control); + uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13); + uint8_t SetData(uint16_t databm); + + // Methods for recieving and sending data + uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr); + uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; + #endif // __CDCFTDI_H__ \ No newline at end of file diff --git a/cdcprolific.cpp b/cdcprolific.cpp index ec27defe..139a627d 100644 --- a/cdcprolific.cpp +++ b/cdcprolific.cpp @@ -1,243 +1,201 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "cdcprolific.h" - -PL2303::PL2303(USB *p, CDCAsyncOper *pasync) : - ACM(p, pasync) - //wPLType(0) -{ -} - -uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); - - uint8_t buf[constBufSize]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t num_of_conf; // number of configurations - enum pl2303_type pltype = unknown; - - AddressPool &addrPool = pUsb->GetAddressPool(); - - USBTRACE("PL Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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 ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - if( rcode ) - goto FailGetDevDescr; - - if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID ) { - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - } - - /* determine chip variant */ - - if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x02 ) { - pltype = type_0; - } - else if (((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0 == 0x40 ) { - pltype = rev_HX; - } - else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x00) { - pltype = type_1; - } - else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0xff) { - pltype = type_1; - } - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - USBTRACE2("NC:", num_of_conf); - - for( uint8_t i=0; i HexDump; - ConfigDescParser<0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this); - - //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - - if (bNumEP > 1) - break; - } // for - - if ( bNumEP < 2 ) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry( bAddress, bNumEP, epInfo ); - - USBTRACE2("Conf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConfDescr; - -#if defined(PL2303_COMPAT) - /* shamanic dance - sending Prolific init data as-is */ - vendorRead( 0x84, 0x84, 0, buf ); - vendorWrite( 0x04, 0x04, 0 ); - vendorRead( 0x84, 0x84, 0, buf ); - vendorRead( 0x83, 0x83, 0, buf ); - vendorRead( 0x84, 0x84, 0, buf ); - vendorWrite( 0x04, 0x04, 1 ); - vendorRead( 0x84, 0x84, 0, buf); - vendorRead( 0x83, 0x83, 0, buf); - vendorWrite( 0, 0, 1 ); - vendorWrite( 1, 0, 0 ); - if ( pltype == rev_HX ) { - vendorWrite( 2, 0, 0x44 ); - vendorWrite( 0x06, 0x06, 0 ); //from W7 init - } - else { - vendorWrite( 2, 0, 0x24 ); - } - /* shamanic dance end */ -#endif - - /* calling post-init callback */ - rcode = pAsync->OnInit(this); - - if (rcode) - goto FailOnInit; - - USBTRACE("PL configured\r\n"); - - //bPollEnable = true; - ready = true; - return 0; - -FailGetDevDescr: - USBTRACE("getDevDescr:"); - goto Fail; - -FailSetDevTblEntry: - USBTRACE("setDevTblEn:"); - goto Fail; - -FailGetConfDescr: - USBTRACE("getConf:"); - goto Fail; - -FailSetConfDescr: - USBTRACE("setConf:"); - goto Fail; - -FailSetControlLineState: - USBTRACE("SetControlLineState:"); - goto Fail; - -FailSetLineCoding: - USBTRACE("SetLineCoding:"); - goto Fail; - -FailOnInit: - USBTRACE("OnInit:"); - goto Fail; - -Fail: - Serial.println(rcode, HEX); - Release(); - return rcode; -} - -//uint8_t PL::Poll() -//{ -// uint8_t rcode = 0; -// -// //if (!bPollEnable) -// // return 0; -// -// //if (qNextPollTime <= millis()) -// //{ -// // Serial.println(bAddress, HEX); -// -// // qNextPollTime = millis() + 100; -// //} -// return rcode; -//} - - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "cdcprolific.h" + +PL2303::PL2303(USB *p, CDCAsyncOper *pasync) : +ACM(p, pasync), +wPLType(0) { +} + +uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("PL Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) + goto FailGetDevDescr; + + if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Save type of PL chip + wPLType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice; + + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + HexDumper HexDump; + ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + + if (rcode) + goto FailGetConfDescr; + + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + + if (rcode) + goto FailGetConfDescr; + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 2) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConfDescr; + + rcode = pAsync->OnInit(this); + + if (rcode) + goto FailOnInit; + + USBTRACE("PL configured\r\n"); + + bPollEnable = true; + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConfDescr: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.println(rcode, HEX); + Release(); + return rcode; +} + +//uint8_t PL::Poll() +//{ +// uint8_t rcode = 0; +// +// //if (!bPollEnable) +// // return 0; +// +// //if (qNextPollTime <= millis()) +// //{ +// // Serial.println(bAddress, HEX); +// +// // qNextPollTime = millis() + 100; +// //} +// return rcode; +//} + + diff --git a/cdcprolific.h b/cdcprolific.h index 38e7d032..9d7a31ce 100644 --- a/cdcprolific.h +++ b/cdcprolific.h @@ -1,179 +1,153 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__CDCPROLIFIC_H__) -#define __CDCPROLIFIC_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#include "confdescparser.h" -#include "cdcacm.h" - -//#define PL2303_COMPAT //uncomment it if you have compatibility problems - -#define PL_VID 0x067B -#define PL_PID ( 0x2303 || 0x0609 ) - -#define PROLIFIC_REV_H 0x0202 -#define PROLIFIC_REV_X 0x0300 -#define PROLIFIC_REV_HX_CHIP_D 0x0400 -#define PROLIFIC_REV_1 0x0001 - -#define kXOnChar '\x11' -#define kXOffChar '\x13' - -#define SPECIAL_SHIFT (5) -#define SPECIAL_MASK ((1<ctrlReq(bAddress, 0, VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, val_lo, val_hi, index, 1, 1, buf, NULL )); -} - -/* vendor write request */ -inline uint8_t PL2303::vendorWrite( uint8_t val_lo, uint8_t val_hi, uint8_t index ) -{ - return( pUsb->ctrlReq(bAddress, 0, VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, val_lo, val_hi, index, 0, 0, NULL, NULL )); -} - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__CDCPROLIFIC_H__) +#define __CDCPROLIFIC_H__ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" +#include "cdcacm.h" + +#define PL_VID 0x067B +#define PL_PID ( 0x2303 || 0x0609 ) + +//#define PL_PID 0x0609 + +#define PROLIFIC_REV_H 0x0202 +#define PROLIFIC_REV_X 0x0300 +#define PROLIFIC_REV_HX_CHIP_D 0x0400 +#define PROLIFIC_REV_1 0x0001 + +#define kXOnChar '\x11' +#define kXOffChar '\x13' + +#define SPECIAL_SHIFT (5) +#define SPECIAL_MASK ((1< - -#include -#include "printhex.h" -#include "hexdump.h" -#include "message.h" -#include "parsetools.h" - -//#include "hid.h" - -class UsbConfigXtracter -{ -public: - //virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0; - //virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0; - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0; -}; - -#define CP_MASK_COMPARE_CLASS 1 -#define CP_MASK_COMPARE_SUBCLASS 2 -#define CP_MASK_COMPARE_PROTOCOL 4 -#define CP_MASK_COMPARE_ALL 7 - -// Configuration Descriptor Parser Class Template -template -class ConfigDescParser : public USBReadParser -{ - UsbConfigXtracter *theXtractor; - MultiValueBuffer theBuffer; - MultiByteValueParser valParser; - ByteSkipper theSkipper; - uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/]; - - uint8_t stateParseDescr; // ParseDescriptor state - - uint8_t dscrLen; // Descriptor length - uint8_t dscrType; // Descriptor type - - bool isGoodInterface; // Apropriate interface flag - uint8_t confValue; // Configuration value - uint8_t protoValue; // Protocol value - uint8_t ifaceNumber; // Interface number - uint8_t ifaceAltSet; // Interface alternate settings - - bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn); - - void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); - -public: - ConfigDescParser(UsbConfigXtracter *xtractor); - virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); -}; - -template -ConfigDescParser::ConfigDescParser(UsbConfigXtracter *xtractor) : - stateParseDescr(0), - dscrLen(0), - dscrType(0), - theXtractor(xtractor) -{ - theBuffer.pValue = varBuffer; - valParser.Initialize(&theBuffer); - theSkipper.Initialize(&theBuffer); -}; - -template -void ConfigDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) -{ - uint16_t cntdn = (uint16_t)len; - uint8_t *p = (uint8_t*)pbuf; - - while(cntdn) - if (!ParseDescriptor(&p, &cntdn)) - return; -} -/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and - compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ -template -bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) -{ - switch (stateParseDescr) - { - case 0: - theBuffer.valueSize = 2; - valParser.Initialize(&theBuffer); - stateParseDescr = 1; - case 1: - if (!valParser.Parse(pp, pcntdn)) - return false; - dscrLen = *((uint8_t*)theBuffer.pValue); - dscrType = *((uint8_t*)theBuffer.pValue + 1); - stateParseDescr = 2; - case 2: - // This is a sort of hack. Assuming that two bytes are already 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 - // in the buffer. - theBuffer.pValue = varBuffer + 2; - stateParseDescr = 3; - case 3: - switch (dscrType) - { - case USB_DESCRIPTOR_INTERFACE: - isGoodInterface = false; - case USB_DESCRIPTOR_CONFIGURATION: - theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2; - break; - case USB_DESCRIPTOR_ENDPOINT: - theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2; - break; - case HID_DESCRIPTOR_HID: - theBuffer.valueSize = dscrLen - 2; - break; - } - valParser.Initialize(&theBuffer); - stateParseDescr = 4; - case 4: - switch (dscrType) - { - case USB_DESCRIPTOR_CONFIGURATION: - if (!valParser.Parse(pp, pcntdn)) - return false; - confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue; - break; - case USB_DESCRIPTOR_INTERFACE: - if (!valParser.Parse(pp, pcntdn)) - return false; - if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID) - break; - if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID) - break; - if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID) - break; - - isGoodInterface = true; - ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber; - ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting; - protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol; - break; - case USB_DESCRIPTOR_ENDPOINT: - if (!valParser.Parse(pp, pcntdn)) - return false; - if (isGoodInterface) - if (theXtractor) - theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer); - break; - //case HID_DESCRIPTOR_HID: - // if (!valParser.Parse(pp, pcntdn)) - // return false; - // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); - // break; - default: - if (!theSkipper.Skip(pp, pcntdn, dscrLen-2)) - return false; - } - theBuffer.pValue = varBuffer; - stateParseDescr = 0; - } - return true; -} - -template -void ConfigDescParser::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) -{ - Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); - Notify(PSTR("bDescLength:\t\t")); - PrintHex(pDesc->bLength); - - Notify(PSTR("\r\nbDescriptorType:\t")); - PrintHex(pDesc->bDescriptorType); - - Notify(PSTR("\r\nbcdHID:\t\t\t")); - PrintHex(pDesc->bcdHID); - - Notify(PSTR("\r\nbCountryCode:\t\t")); - PrintHex(pDesc->bCountryCode); - - Notify(PSTR("\r\nbNumDescriptors:\t")); - PrintHex(pDesc->bNumDescriptors); - - //Notify(PSTR("\r\nbDescrType:\t\t")); - //PrintHex(pDesc->bDescrType); - // - //Notify(PSTR("\r\nwDescriptorLength:\t")); - //PrintHex(pDesc->wDescriptorLength); - - for (uint8_t i=0; ibNumDescriptors; i++) - { - HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType); - - Notify(PSTR("\r\nbDescrType:\t\t")); - PrintHex(pLT[i].bDescrType); - - Notify(PSTR("\r\nwDescriptorLength:\t")); - PrintHex(pLT[i].wDescriptorLength); - } - Notify(PSTR("\r\n")); -} - - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__CONFDESCPARSER_H__) +#define __CONFDESCPARSER_H__ + +#include + +#include +#include "printhex.h" +#include "hexdump.h" +#include "message.h" +#include "parsetools.h" + +//#include "hid.h" + +class UsbConfigXtracter { +public: + //virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0; + //virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0; + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0; +}; + +#define CP_MASK_COMPARE_CLASS 1 +#define CP_MASK_COMPARE_SUBCLASS 2 +#define CP_MASK_COMPARE_PROTOCOL 4 +#define CP_MASK_COMPARE_ALL 7 + +// Configuration Descriptor Parser Class Template + +template +class ConfigDescParser : public USBReadParser { + UsbConfigXtracter *theXtractor; + MultiValueBuffer theBuffer; + MultiByteValueParser valParser; + ByteSkipper theSkipper; + uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/]; + + uint8_t stateParseDescr; // ParseDescriptor state + + uint8_t dscrLen; // Descriptor length + uint8_t dscrType; // Descriptor type + + bool isGoodInterface; // Apropriate interface flag + uint8_t confValue; // Configuration value + uint8_t protoValue; // Protocol value + uint8_t ifaceNumber; // Interface number + uint8_t ifaceAltSet; // Interface alternate settings + + bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn); + + void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); + +public: + ConfigDescParser(UsbConfigXtracter *xtractor); + virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); +}; + +template +ConfigDescParser::ConfigDescParser(UsbConfigXtracter *xtractor) : +theXtractor(xtractor), +stateParseDescr(0), +dscrLen(0), +dscrType(0) { + theBuffer.pValue = varBuffer; + valParser.Initialize(&theBuffer); + theSkipper.Initialize(&theBuffer); +}; + +template +void ConfigDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) { + uint16_t cntdn = (uint16_t) len; + uint8_t *p = (uint8_t*) pbuf; + + while(cntdn) + if(!ParseDescriptor(&p, &cntdn)) + return; +} + +/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and + compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ +template +bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) { + switch(stateParseDescr) { + case 0: + theBuffer.valueSize = 2; + valParser.Initialize(&theBuffer); + stateParseDescr = 1; + case 1: + if(!valParser.Parse(pp, pcntdn)) + return false; + dscrLen = *((uint8_t*) theBuffer.pValue); + 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 + // 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 + // in the buffer. + theBuffer.pValue = varBuffer + 2; + stateParseDescr = 3; + case 3: + switch(dscrType) { + case USB_DESCRIPTOR_INTERFACE: + isGoodInterface = false; + case USB_DESCRIPTOR_CONFIGURATION: + theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2; + break; + case USB_DESCRIPTOR_ENDPOINT: + theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2; + break; + case HID_DESCRIPTOR_HID: + theBuffer.valueSize = dscrLen - 2; + break; + } + valParser.Initialize(&theBuffer); + stateParseDescr = 4; + case 4: + switch(dscrType) { + case USB_DESCRIPTOR_CONFIGURATION: + if(!valParser.Parse(pp, pcntdn)) + return false; + confValue = ((USB_CONFIGURATION_DESCRIPTOR*) varBuffer)->bConfigurationValue; + break; + case USB_DESCRIPTOR_INTERFACE: + if(!valParser.Parse(pp, pcntdn)) + return false; + if((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceClass != CLASS_ID) + break; + if((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceSubClass != SUBCLASS_ID) + break; + if((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol != PROTOCOL_ID) + break; + + isGoodInterface = true; + ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceNumber; + ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bAlternateSetting; + protoValue = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol; + break; + case USB_DESCRIPTOR_ENDPOINT: + if(!valParser.Parse(pp, pcntdn)) + return false; + if(isGoodInterface) + if(theXtractor) + theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*) varBuffer); + break; + //case HID_DESCRIPTOR_HID: + // if (!valParser.Parse(pp, pcntdn)) + // return false; + // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); + // break; + default: + if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2)) + return false; + } + theBuffer.pValue = varBuffer; + stateParseDescr = 0; + } + return true; +} + +template +void ConfigDescParser::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { + Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80); + Notify(PSTR("bDescLength:\t\t"), 0x80); + PrintHex (pDesc->bLength, 0x80); + + Notify(PSTR("\r\nbDescriptorType:\t"), 0x80); + PrintHex (pDesc->bDescriptorType, 0x80); + + Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80); + PrintHex (pDesc->bcdHID, 0x80); + + Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80); + PrintHex (pDesc->bCountryCode, 0x80); + + Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80); + PrintHex (pDesc->bNumDescriptors, 0x80); + + //Notify(PSTR("\r\nbDescrType:\t\t")); + //PrintHex(pDesc->bDescrType); + // + //Notify(PSTR("\r\nwDescriptorLength:\t")); + //PrintHex(pDesc->wDescriptorLength); + + for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) { + HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType); + + Notify(PSTR("\r\nbDescrType:\t\t"), 0x80); + PrintHex (pLT[i].bDescrType, 0x80); + + Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80); + PrintHex (pLT[i].wDescriptorLength, 0x80); + } + Notify(PSTR("\r\n"), 0x80); +} + + #endif // __CONFDESCPARSER_H__ \ No newline at end of file diff --git a/controllerEnums.h b/controllerEnums.h index 3137e730..5e35a268 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -1,15 +1,15 @@ /* 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 @@ -21,96 +21,98 @@ /* This header file is used to store different enums for the controllers, This is necessary so all the different libraries can be used at once -*/ + */ /** Enum used to turn on the LEDs on the different controllers. */ enum LED { - LED1 = 0, - LED2 = 1, - LED3 = 2, - LED4 = 3, - - LED5 = 4, - LED6 = 5, - LED7 = 6, - LED8 = 7, - LED9 = 8, - LED10 = 9, - /** Used to blink all LEDs on the Xbox controller */ - ALL = 4, + LED1 = 0, + LED2 = 1, + LED3 = 2, + LED4 = 3, + + LED5 = 4, + LED6 = 5, + LED7 = 6, + LED8 = 7, + LED9 = 8, + LED10 = 9, + /** Used to blink all LEDs on the Xbox controller */ + ALL = 4, }; + /** This enum is used to read all the different buttons on the different controllers */ enum Button { - /**@{*/ - /** These buttons are available on all the the controllers */ - UP = 0, - RIGHT = 1, - DOWN = 2, - LEFT = 3, - /**@}*/ + /**@{*/ + /** These buttons are available on all the the controllers */ + UP = 0, + RIGHT = 1, + DOWN = 2, + LEFT = 3, + /**@}*/ - /**@{*/ - /** Wii buttons */ - PLUS = 5, - TWO = 6, - ONE = 7, - MINUS = 8, - HOME = 9, - Z = 10, - C = 11, - B = 12, - A = 13, - /**@}*/ + /**@{*/ + /** Wii buttons */ + PLUS = 5, + TWO = 6, + ONE = 7, + MINUS = 8, + HOME = 9, + Z = 10, + C = 11, + B = 12, + A = 13, + /**@}*/ - /**@{*/ - /** These are only available on the Wii U Pro Controller */ - L = 16, - R = 17, - ZL = 18, - ZR = 19, - /**@}*/ + /**@{*/ + /** These are only available on the Wii U Pro Controller */ + L = 16, + R = 17, + ZL = 18, + ZR = 19, + /**@}*/ - /**@{*/ - /** PS3 controllers buttons */ - SELECT = 4, - START = 5, - L3 = 6, - R3 = 7, - - L2 = 8, - R2 = 9, - L1 = 10, - R1 = 11, - TRIANGLE = 12, - CIRCLE = 13, - CROSS = 14, - SQUARE = 15, - - PS = 16, - - MOVE = 17, // Covers 12 bits - we only need to read the top 8 - T = 18, // Covers 12 bits - we only need to read the top 8 - /**@}*/ + /**@{*/ + /** PS3 controllers buttons */ + SELECT = 4, + START = 5, + L3 = 6, + R3 = 7, - /**@{*/ - /** Xbox buttons */ - BACK = 4, - X = 14, - Y = 15, - XBOX = 16, - SYNC = 17, - /**@}*/ + L2 = 8, + R2 = 9, + L1 = 10, + R1 = 11, + TRIANGLE = 12, + CIRCLE = 13, + CROSS = 14, + SQUARE = 15, + + PS = 16, + + MOVE = 17, // Covers 12 bits - we only need to read the top 8 + T = 18, // Covers 12 bits - we only need to read the top 8 + /**@}*/ + + /**@{*/ + /** Xbox buttons */ + BACK = 4, + X = 14, + Y = 15, + XBOX = 16, + SYNC = 17, + /**@}*/ }; + /** Joysticks on the PS3 and Xbox controllers. */ -enum AnalogHat { - /** Left joystick x-axis */ - LeftHatX = 0, - /** Left joystick y-axis */ - LeftHatY = 1, - /** Right joystick x-axis */ - RightHatX = 2, - /** Right joystick y-axis */ - RightHatY = 3, +enum AnalogHat { + /** Left joystick x-axis */ + LeftHatX = 0, + /** Left joystick y-axis */ + LeftHatY = 1, + /** Right joystick x-axis */ + RightHatX = 2, + /** Right joystick y-axis */ + RightHatY = 3, }; #endif \ No newline at end of file diff --git a/gpl2.txt b/gpl2.txt index 5b6e7c66..45645b4b 100644 --- a/gpl2.txt +++ b/gpl2.txt @@ -1,340 +1,340 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/hexdump.h b/hexdump.h index e63376af..7328d6e5 100644 --- a/hexdump.h +++ b/hexdump.h @@ -1,58 +1,59 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__HEXDUMP_H__) -#define __HEXDUMP_H__ - -#include -#include -#include "printhex.h" - -template -class HexDumper : public BASE_CLASS -{ - uint8_t byteCount; - OFFSET_TYPE byteTotal; - -public: - HexDumper() : byteCount(0), byteTotal(0) {}; - void Initialize() { byteCount = 0; byteTotal = 0; }; - - virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset); -}; - -template -void HexDumper::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) -{ - for (LEN_TYPE j=0; j(byteTotal); - Serial.print(": "); - } - PrintHex(pbuf[j]); - Serial.print(" "); - - if (byteCount == 15) - { - Serial.println(""); - byteCount = 0xFF; - } - } -} - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__HEXDUMP_H__) +#define __HEXDUMP_H__ + +#include +#include +#include "printhex.h" + +template +class HexDumper : public BASE_CLASS { + uint8_t byteCount; + OFFSET_TYPE byteTotal; + +public: + + HexDumper() : byteCount(0), byteTotal(0) { + }; + + void Initialize() { + byteCount = 0; + byteTotal = 0; + }; + + virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset); +}; + +template +void HexDumper::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) { + for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) { + if(!byteCount) { + SerialPrintHex (byteTotal); + Serial.print(": "); + } + SerialPrintHex (pbuf[j]); + Serial.print(" "); + + if(byteCount == 15) { + Serial.println(""); + byteCount = 0xFF; + } + } +} + #endif // __HEXDUMP_H__ \ No newline at end of file diff --git a/hid.cpp b/hid.cpp index 4796e782..9d8fcd0f 100644 --- a/hid.cpp +++ b/hid.cpp @@ -1,84 +1,82 @@ -#include "hid.h" - -//get HID report descriptor -uint8_t HID::GetReportDescr( uint8_t ep, USBReadParser *parser ) -{ - const uint8_t constBufLen = 64; - uint8_t buf[constBufLen]; - - uint8_t rcode = pUsb->ctrlReq( bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, - HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser ); - - //return ((rcode != hrSTALL) ? rcode : 0); - return rcode; -} -//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr ) -//{ -// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr )); -//} -uint8_t HID::SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL )); -} -uint8_t HID::GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL )); -} -uint8_t HID::GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL )); -} -uint8_t HID::SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL )); -} -uint8_t HID::SetProtocol( uint8_t iface, uint8_t protocol ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL )); -} -uint8_t HID::GetProtocol( uint8_t iface, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL )); -} - -void HID::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) -{ - Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); -} - -void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) -{ - Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); - Notify(PSTR("bDescLength:\t\t")); - PrintHex(pDesc->bLength); - - Notify(PSTR("\r\nbDescriptorType:\t")); - PrintHex(pDesc->bDescriptorType); - - Notify(PSTR("\r\nbcdHID:\t\t\t")); - PrintHex(pDesc->bcdHID); - - Notify(PSTR("\r\nbCountryCode:\t\t")); - PrintHex(pDesc->bCountryCode); - - Notify(PSTR("\r\nbNumDescriptors:\t")); - PrintHex(pDesc->bNumDescriptors); - - Notify(PSTR("\r\nbDescrType:\t\t")); - PrintHex(pDesc->bDescrType); - - Notify(PSTR("\r\nwDescriptorLength:\t")); - PrintHex(pDesc->wDescriptorLength); -} +#include "hid.h" + +//get HID report descriptor + +uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) { + const uint8_t constBufLen = 64; + uint8_t buf[constBufLen]; + + uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, + HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser); + + //return ((rcode != hrSTALL) ? rcode : 0); + return rcode; +} +//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr ) +//{ +// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr )); +//} + +uint8_t HID::SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL)); +} + +uint8_t HID::GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL)); +} + +uint8_t HID::GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL)); +} + +uint8_t HID::SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL)); +} + +uint8_t HID::SetProtocol(uint8_t iface, uint8_t protocol) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL)); +} + +uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL)); +} + +void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (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 (pDesc->bLength, 0x80); + + Notify(PSTR("\r\nbDescriptorType:\t"), 0x80); + PrintHex (pDesc->bDescriptorType, 0x80); + + Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80); + PrintHex (pDesc->bcdHID, 0x80); + + Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80); + PrintHex (pDesc->bCountryCode, 0x80); + + Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80); + PrintHex (pDesc->bNumDescriptors, 0x80); + + Notify(PSTR("\r\nbDescrType:\t\t"), 0x80); + PrintHex (pDesc->bDescrType, 0x80); + + Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80); + PrintHex (pDesc->wDescriptorLength, 0x80); +} diff --git a/hid.h b/hid.h index 28ed53a6..f894a64d 100644 --- a/hid.h +++ b/hid.h @@ -1,201 +1,201 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__HID_H__) -#define __HID_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#include "confdescparser.h" -#include "hidusagestr.h" - -#define DATA_SIZE_MASK 0x03 -#define TYPE_MASK 0x0C -#define TAG_MASK 0xF0 - -#define DATA_SIZE_0 0x00 -#define DATA_SIZE_1 0x01 -#define DATA_SIZE_2 0x02 -#define DATA_SIZE_4 0x03 - -#define TYPE_MAIN 0x00 -#define TYPE_GLOBAL 0x04 -#define TYPE_LOCAL 0x08 - -#define TAG_MAIN_INPUT 0x80 -#define TAG_MAIN_OUTPUT 0x90 -#define TAG_MAIN_COLLECTION 0xA0 -#define TAG_MAIN_FEATURE 0xB0 -#define TAG_MAIN_ENDCOLLECTION 0xC0 - -#define TAG_GLOBAL_USAGEPAGE 0x00 -#define TAG_GLOBAL_LOGICALMIN 0x10 -#define TAG_GLOBAL_LOGICALMAX 0x20 -#define TAG_GLOBAL_PHYSMIN 0x30 -#define TAG_GLOBAL_PHYSMAX 0x40 -#define TAG_GLOBAL_UNITEXP 0x50 -#define TAG_GLOBAL_UNIT 0x60 -#define TAG_GLOBAL_REPORTSIZE 0x70 -#define TAG_GLOBAL_REPORTID 0x80 -#define TAG_GLOBAL_REPORTCOUNT 0x90 -#define TAG_GLOBAL_PUSH 0xA0 -#define TAG_GLOBAL_POP 0xB0 - -#define TAG_LOCAL_USAGE 0x00 -#define TAG_LOCAL_USAGEMIN 0x10 -#define TAG_LOCAL_USAGEMAX 0x20 - -/* HID requests */ -#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE -#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE -#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE - -/* HID constants. Not part of chapter 9 */ -/* Class-Specific Requests */ -#define HID_REQUEST_GET_REPORT 0x01 -#define HID_REQUEST_GET_IDLE 0x02 -#define HID_REQUEST_GET_PROTOCOL 0x03 -#define HID_REQUEST_SET_REPORT 0x09 -#define HID_REQUEST_SET_IDLE 0x0A -#define HID_REQUEST_SET_PROTOCOL 0x0B - -/* Class Descriptor Types */ -#define HID_DESCRIPTOR_HID 0x21 -#define HID_DESCRIPTOR_REPORT 0x22 -#define HID_DESRIPTOR_PHY 0x23 - -/* Protocol Selection */ -#define HID_BOOT_PROTOCOL 0x00 -#define HID_RPT_PROTOCOL 0x01 - -/* HID Interface Class Code */ -#define HID_INTF 0x03 - -/* HID Interface Class SubClass Codes */ -#define HID_BOOT_INTF_SUBCLASS 0x01 - -/* HID Interface Class Protocol Codes */ -#define HID_PROTOCOL_NONE 0x00 -#define HID_PROTOCOL_KEYBOARD 0x01 -#define HID_PROTOCOL_MOUSE 0x02 - -struct HidItemPrefix -{ - uint8_t bSize : 2; - uint8_t bType : 2; - uint8_t bTag : 4; -}; - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value - -#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask - -#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value -#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value -#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value -#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value -#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value - -#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0 -#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1 -#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2 -#define HID_MAIN_ITEM_COLLECTION_REPORT 3 -#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4 -#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5 -#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6 - -struct MainItemIOFeature -{ - uint8_t bmIsConstantOrData : 1; - uint8_t bmIsArrayOrVariable : 1; - uint8_t bmIsRelativeOrAbsolute : 1; - uint8_t bmIsWrapOrNoWrap : 1; - uint8_t bmIsNonLonearOrLinear : 1; - uint8_t bmIsNoPreferedOrPrefered : 1; - uint8_t bmIsNullOrNoNull : 1; - uint8_t bmIsVolatileOrNonVolatile : 1; -}; - -class HID; - -class HIDReportParser -{ -public: - virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0; -}; - -#define MAX_REPORT_PARSERS 2 -#define HID_MAX_HID_CLASS_DESCRIPTORS 5 - -class HID : public USBDeviceConfig, public UsbConfigXtracter -{ -protected: - USB *pUsb; // USB class instance pointer - uint8_t bAddress; // address - -protected: - static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index - static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index - - static const uint8_t maxHidInterfaces = 3; - static const uint8_t maxEpPerInterface = 2; - static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1); - - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); - - virtual HIDReportParser* GetReportParser(uint8_t id); - -public: - HID(USB *pusb) : pUsb(pusb) {}; - - const USB* GetUsb() { return pUsb; }; - virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); - - uint8_t SetProtocol( uint8_t iface, uint8_t protocol ); - uint8_t GetProtocol( uint8_t iface, uint8_t* dataptr ); - uint8_t GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr ); - uint8_t SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration ); - - uint8_t GetReportDescr( uint8_t ep, USBReadParser *parser = NULL); - - uint8_t GetHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr ); - uint8_t GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr ); - uint8_t SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr ); -}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__HID_H__) +#define __HID_H__ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" +#include "hidusagestr.h" + +#define DATA_SIZE_MASK 0x03 +#define TYPE_MASK 0x0C +#define TAG_MASK 0xF0 + +#define DATA_SIZE_0 0x00 +#define DATA_SIZE_1 0x01 +#define DATA_SIZE_2 0x02 +#define DATA_SIZE_4 0x03 + +#define TYPE_MAIN 0x00 +#define TYPE_GLOBAL 0x04 +#define TYPE_LOCAL 0x08 + +#define TAG_MAIN_INPUT 0x80 +#define TAG_MAIN_OUTPUT 0x90 +#define TAG_MAIN_COLLECTION 0xA0 +#define TAG_MAIN_FEATURE 0xB0 +#define TAG_MAIN_ENDCOLLECTION 0xC0 + +#define TAG_GLOBAL_USAGEPAGE 0x00 +#define TAG_GLOBAL_LOGICALMIN 0x10 +#define TAG_GLOBAL_LOGICALMAX 0x20 +#define TAG_GLOBAL_PHYSMIN 0x30 +#define TAG_GLOBAL_PHYSMAX 0x40 +#define TAG_GLOBAL_UNITEXP 0x50 +#define TAG_GLOBAL_UNIT 0x60 +#define TAG_GLOBAL_REPORTSIZE 0x70 +#define TAG_GLOBAL_REPORTID 0x80 +#define TAG_GLOBAL_REPORTCOUNT 0x90 +#define TAG_GLOBAL_PUSH 0xA0 +#define TAG_GLOBAL_POP 0xB0 + +#define TAG_LOCAL_USAGE 0x00 +#define TAG_LOCAL_USAGEMIN 0x10 +#define TAG_LOCAL_USAGEMAX 0x20 + +/* HID requests */ +#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE + +/* HID constants. Not part of chapter 9 */ +/* Class-Specific Requests */ +#define HID_REQUEST_GET_REPORT 0x01 +#define HID_REQUEST_GET_IDLE 0x02 +#define HID_REQUEST_GET_PROTOCOL 0x03 +#define HID_REQUEST_SET_REPORT 0x09 +#define HID_REQUEST_SET_IDLE 0x0A +#define HID_REQUEST_SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define HID_DESCRIPTOR_HID 0x21 +#define HID_DESCRIPTOR_REPORT 0x22 +#define HID_DESRIPTOR_PHY 0x23 + +/* Protocol Selection */ +#define HID_BOOT_PROTOCOL 0x00 +#define HID_RPT_PROTOCOL 0x01 + +/* HID Interface Class Code */ +#define HID_INTF 0x03 + +/* HID Interface Class SubClass Codes */ +#define HID_BOOT_INTF_SUBCLASS 0x01 + +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOARD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + +struct HidItemPrefix { + uint8_t bSize : 2; + uint8_t bType : 2; + uint8_t bTag : 4; +}; + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value + +#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask + +#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value +#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value +#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value +#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value +#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value + +#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0 +#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1 +#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2 +#define HID_MAIN_ITEM_COLLECTION_REPORT 3 +#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4 +#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5 +#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6 + +struct MainItemIOFeature { + uint8_t bmIsConstantOrData : 1; + uint8_t bmIsArrayOrVariable : 1; + uint8_t bmIsRelativeOrAbsolute : 1; + uint8_t bmIsWrapOrNoWrap : 1; + uint8_t bmIsNonLonearOrLinear : 1; + uint8_t bmIsNoPreferedOrPrefered : 1; + uint8_t bmIsNullOrNoNull : 1; + uint8_t bmIsVolatileOrNonVolatile : 1; +}; + +class HID; + +class HIDReportParser { +public: + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0; +}; + +#define MAX_REPORT_PARSERS 2 +#define HID_MAX_HID_CLASS_DESCRIPTORS 5 + +class HID : public USBDeviceConfig, public UsbConfigXtracter { +protected: + USB *pUsb; // USB class instance pointer + uint8_t bAddress; // address + +protected: + static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index + static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index + + static const uint8_t maxHidInterfaces = 3; + static const uint8_t maxEpPerInterface = 2; + static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1); + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); + + virtual HIDReportParser* GetReportParser(uint8_t id); + +public: + + HID(USB *pusb) : pUsb(pusb) { + }; + + const USB* GetUsb() { + return pUsb; + }; + virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); + + uint8_t SetProtocol(uint8_t iface, uint8_t protocol); + uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr); + uint8_t GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr); + uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration); + + uint8_t GetReportDescr(uint8_t ep, USBReadParser *parser = NULL); + + uint8_t GetHidDescr(uint8_t ep, uint16_t nbytes, uint8_t* dataptr); + uint8_t GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr); + uint8_t SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr); +}; + #endif // __HID_H__ \ No newline at end of file diff --git a/hidboot.cpp b/hidboot.cpp index 2458401a..984680eb 100644 --- a/hidboot.cpp +++ b/hidboot.cpp @@ -1,154 +1,139 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "hidboot.h" - -void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) -{ - MOUSEINFO *pmi = (MOUSEINFO*)buf; - - if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1) - OnLeftButtonDown(pmi); - - if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0) - OnLeftButtonUp(pmi); - - if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1) - OnRightButtonDown(pmi); - - if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0) - OnRightButtonUp(pmi); - - if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1) - OnMiddleButtonDown(pmi); - - if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0) - OnMiddleButtonUp(pmi); - - if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY) - OnMouseMove(pmi); - - for (uint8_t i=0; i<3; i++) - prevState.bInfo[i] = buf[i]; -}; - -void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) -{ - // On error - return - if (buf[2] == 1) - return; - - KBDINFO *pki = (KBDINFO*)buf; - - for (uint8_t i=2; i<8; i++) - { - bool down = false; - bool up = false; - - for (uint8_t j=2; j<8; j++) - { - if (buf[i] == prevState.bInfo[j] && buf[i] != 1) - down = true; - if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1) - up = true; - } - if (!down) - { - HandleLockingKeys(hid, buf[i]); - OnKeyDown(*buf, buf[i]); - } - if (!up) - OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]); - } - for (uint8_t i=0; i<8; i++) - prevState.bInfo[i] = buf[i]; -}; - -uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) -{ - uint8_t old_keys = kbdLockingKeys.bLeds; - - switch (key) - { - case KEY_NUM_LOCK: - kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock; - break; - case KEY_CAPS_LOCK: - kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock; - break; - case KEY_SCROLL_LOCK: - kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock; - break; - } - - if (old_keys != kbdLockingKeys.bLeds && hid) - return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds)); - - return 0; -} - -const uint8_t KeyboardReportParser::numKeys[] PROGMEM = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')' }; -const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = { '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' }; -const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' }; -const uint8_t KeyboardReportParser::padKeys[] PROGMEM = { '/', '*', '-', '+', 0x13 }; - -uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) -{ - uint8_t shift = (mod & 0x22); - - // [a-z] - if (key > 0x03 && key < 0x1e) - { - // Upper case letters - if ( (kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) || - (kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0) ) - return (key - 4 + 'A'); - - // Lower case letters - else - return (key - 4 + 'a'); - } - // Numbers - else if (key > 0x1d && key < 0x27) - { - if (shift) - return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e])); - else - return (key - 0x1e + '1'); - } - // Keypad Numbers - else if (key > 0x58 && key < 0x62) - { - if (kbdLockingKeys.kbdLeds.bmNumLock == 1) - return (key - 0x59 + '1'); - } - else if (key > 0x2c && key < 0x39) - return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key-0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key-0x2d])); - else if (key > 0x53 && key < 0x59) - return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]); - else - { - switch (key) - { - case KEY_SPACE: return(0x20); - case KEY_ENTER: return(0x13); - case KEY_ZERO: return((shift) ? ')' : '0'); - case KEY_ZERO2: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0' : 0); - case KEY_PERIOD: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0); - } - } - return( 0 ); -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "hidboot.h" + +void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + MOUSEINFO *pmi = (MOUSEINFO*)buf; + + if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1) + OnLeftButtonDown(pmi); + + if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0) + OnLeftButtonUp(pmi); + + if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1) + OnRightButtonDown(pmi); + + if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0) + OnRightButtonUp(pmi); + + if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1) + OnMiddleButtonDown(pmi); + + if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0) + OnMiddleButtonUp(pmi); + + if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY) + OnMouseMove(pmi); + + if (len > sizeof (MOUSEINFO)) + for (uint8_t i = 0; iSetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds)); + + return 0; +} + +const uint8_t KeyboardReportParser::numKeys[] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'}; +const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'}; +const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'}; +const uint8_t KeyboardReportParser::padKeys[] PROGMEM = {'/', '*', '-', '+', 0x13}; + +uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) { + uint8_t shift = (mod & 0x22); + + // [a-z] + if (key > 0x03 && key < 0x1e) { + // Upper case letters + if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) || + (kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0)) + return (key - 4 + 'A'); + + // Lower case letters + else + return (key - 4 + 'a'); + }// Numbers + else if (key > 0x1d && key < 0x27) { + if (shift) + return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e])); + else + return (key - 0x1e + '1'); + }// Keypad Numbers + else if (key > 0x58 && key < 0x62) { + if (kbdLockingKeys.kbdLeds.bmNumLock == 1) + return (key - 0x59 + '1'); + } else if (key > 0x2c && key < 0x39) + return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key - 0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key - 0x2d])); + else if (key > 0x53 && key < 0x59) + return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]); + else { + switch (key) { + case KEY_SPACE: return (0x20); + case KEY_ENTER: return (0x13); + case KEY_ZERO: return ((shift) ? ')': '0'); + case KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0); + case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0); + } + } + return ( 0); +} diff --git a/hidboot.h b/hidboot.h index 26ac451b..581ee566 100644 --- a/hidboot.h +++ b/hidboot.h @@ -1,495 +1,494 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__HIDBOOT_H__) -#define __HIDBOOT_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#include "confdescparser.h" - -#define KEY_SPACE 0x2c -#define KEY_ZERO 0x27 -#define KEY_ZERO2 0x62 -#define KEY_ENTER 0x28 -#define KEY_PERIOD 0x63 - -struct MOUSEINFO -{ - struct - { - uint8_t bmLeftButton : 1; - uint8_t bmRightButton : 1; - uint8_t bmMiddleButton : 1; - uint8_t bmDummy : 1; - }; - int8_t dX; - int8_t dY; -}; - -class MouseReportParser : public HIDReportParser -{ - union - { - MOUSEINFO mouseInfo; - uint8_t bInfo[3]; - } prevState; - -public: - virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); - -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) {}; -}; - -struct MODIFIERKEYS -{ - uint8_t bmLeftCtrl : 1; - uint8_t bmLeftShift : 1; - uint8_t bmLeftAlt : 1; - uint8_t bmLeftGUI : 1; - uint8_t bmRightCtrl : 1; - uint8_t bmRightShift : 1; - uint8_t bmRightAlt : 1; - uint8_t bmRightGUI : 1; -}; - -struct KBDINFO -{ - struct - { - uint8_t bmLeftCtrl : 1; - uint8_t bmLeftShift : 1; - uint8_t bmLeftAlt : 1; - uint8_t bmLeftGUI : 1; - uint8_t bmRightCtrl : 1; - uint8_t bmRightShift : 1; - uint8_t bmRightAlt : 1; - uint8_t bmRightGUI : 1; - }; - uint8_t bReserved; - uint8_t Keys[6]; -}; - -struct KBDLEDS -{ - uint8_t bmNumLock : 1; - uint8_t bmCapsLock : 1; - uint8_t bmScrollLock : 1; - uint8_t bmCompose : 1; - uint8_t bmKana : 1; - uint8_t bmReserved : 3; -}; - -#define KEY_NUM_LOCK 0x53 -#define KEY_CAPS_LOCK 0x39 -#define KEY_SCROLL_LOCK 0x47 - -class KeyboardReportParser : public HIDReportParser -{ - static const uint8_t numKeys[]; - static const uint8_t symKeysUp[]; - static const uint8_t symKeysLo[]; - static const uint8_t padKeys[]; - -protected: - union - { - KBDINFO kbdInfo; - uint8_t bInfo[sizeof(KBDINFO)]; - } prevState; - - union - { - KBDLEDS kbdLeds; - uint8_t bLeds; - } kbdLockingKeys; - - uint8_t OemToAscii(uint8_t mod, uint8_t key); - -public: - KeyboardReportParser() { kbdLockingKeys.bLeds = 0; }; - - virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); - -protected: - uint8_t HandleLockingKeys(HID* hid, 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 - -template -class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter -{ - EpInfo epInfo[totalEndpoints]; - - HIDReportParser *pRptParser; - - uint8_t bConfNum; // configuration number - uint8_t bIfaceNum; // Interface Number - uint8_t bNumIface; // number of interfaces in the configuration - uint8_t bNumEP; // total number of EP in the configuration - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag - - void Initialize(); - - virtual HIDReportParser* GetReportParser(uint8_t id) { return pRptParser; }; - -public: - HIDBoot(USB *p); - - virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) { pRptParser = prs; }; - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; - - // UsbConfigXtracter implementation - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); -}; - -template -HIDBoot::HIDBoot(USB *p) : - HID(p), - qNextPollTime(0), - bPollEnable(false), - pRptParser(NULL) -{ - Initialize(); - - if (pUsb) - pUsb->RegisterDeviceClass(this); -} - -template -void HIDBoot::Initialize() -{ - for(uint8_t i=0; i -uint8_t HIDBoot::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); - - uint8_t buf[constBufSize]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t len = 0; - uint16_t cd_len = 0; - - uint8_t num_of_conf; // number of configurations - uint8_t num_of_intf; // number of interfaces - - AddressPool &addrPool = pUsb->GetAddressPool(); - - USBTRACE("BM Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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, 8, (uint8_t*)buf ); - - if (!rcode) - len = (buf[0] > constBufSize) ? constBufSize : buf[0]; - - if( rcode ) - { - // Restore p->epinfo - p->epinfo = oldep_ptr; - - goto FailGetDevDescr; - } - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - if (len) - rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf ); - - if(rcode) - goto FailGetDevDescr; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - //USBTRACE2("NC:", num_of_conf); - - for (uint8_t i=0; i HexDump; - ConfigDescParser< - USB_CLASS_HID, - HID_BOOT_INTF_SUBCLASS, - BOOT_PROTOCOL, - CP_MASK_COMPARE_ALL> confDescrParser(this); - - //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - - if (bNumEP > 1) - break; - } // for - - if (bNumEP < 2) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - //USBTRACE2("\r\nbAddr:", bAddress); - //USBTRACE2("\r\nbNumEP:", bNumEP); - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - - //USBTRACE2("\r\nCnf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConfDescr; - - //USBTRACE2("\r\nIf:", bIfaceNum); - - rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL); - - if (rcode) - goto FailSetProtocol; - - if (BOOT_PROTOCOL == 1) - { - rcode = SetIdle(bIfaceNum, 0, 0); - - if (rcode) - goto FailSetIdle; - } - USBTRACE("BM configured\r\n"); - - bPollEnable = true; - return 0; - -FailGetDevDescr: - USBTRACE("getDevDescr:"); - goto Fail; - -FailSetDevTblEntry: - USBTRACE("setDevTblEn:"); - goto Fail; - -FailGetConfDescr: - USBTRACE("getConf:"); - goto Fail; - -FailSetProtocol: - USBTRACE("SetProto:"); - goto Fail; - -FailSetIdle: - USBTRACE("SetIdle:"); - goto Fail; - -FailSetConfDescr: - USBTRACE("setConf:"); - goto Fail; - -Fail: - Serial.println(rcode, HEX); - Release(); - return rcode; -} - -template -void HIDBoot::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 (bNumEP > 1 && conf != bConfNum) - return; - - //ErrorMessage(PSTR("\r\nConf.Val"), conf); - //ErrorMessage(PSTR("Iface Num"), iface); - //ErrorMessage(PSTR("Alt.Set"), alt); - - bConfNum = conf; - bIfaceNum = iface; - - uint8_t index; - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - { - index = epInterruptInIndex; - - // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; - epInfo[index].epAttribs = 0; - - bNumEP ++; - - //PrintEndpointDescriptor(pep); - } -} - - -template -uint8_t HIDBoot::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bConfNum = 0; - bIfaceNum = 0; - bNumEP = 1; - bAddress = 0; - qNextPollTime = 0; - bPollEnable = false; - return 0; -} - -template -uint8_t HIDBoot::Poll() -{ - uint8_t rcode = 0; - - if (!bPollEnable) - return 0; - - if (qNextPollTime <= millis()) - { - qNextPollTime = millis() + 10; - - 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); - - if (rcode) - { - if (rcode != hrNAK) - USBTRACE2("Poll:", rcode); - return rcode; - } - //for (uint8_t i=0; i(buf[i]); - //if (read) - // Serial.println(""); - - if (pRptParser) - pRptParser->Parse((HID*)this, 0, (uint8_t)read, buf); - } - return rcode; -} - - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__HIDBOOT_H__) +#define __HIDBOOT_H__ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" + +#define KEY_SPACE 0x2c +#define KEY_ZERO 0x27 +#define KEY_ZERO2 0x62 +#define KEY_ENTER 0x28 +#define KEY_PERIOD 0x63 + +struct MOUSEINFO { + + struct { + uint8_t bmLeftButton : 1; + uint8_t bmRightButton : 1; + uint8_t bmMiddleButton : 1; + uint8_t bmDummy : 1; + }; + int8_t dX; + int8_t dY; +}; + +class MouseReportParser : public HIDReportParser { + + union { + MOUSEINFO mouseInfo; + uint8_t bInfo[sizeof(MOUSEINFO)]; + } prevState; + +public: + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); + +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) { + }; +}; + +struct MODIFIERKEYS { + uint8_t bmLeftCtrl : 1; + uint8_t bmLeftShift : 1; + uint8_t bmLeftAlt : 1; + uint8_t bmLeftGUI : 1; + uint8_t bmRightCtrl : 1; + uint8_t bmRightShift : 1; + uint8_t bmRightAlt : 1; + uint8_t bmRightGUI : 1; +}; + +struct KBDINFO { + + struct { + uint8_t bmLeftCtrl : 1; + uint8_t bmLeftShift : 1; + uint8_t bmLeftAlt : 1; + uint8_t bmLeftGUI : 1; + uint8_t bmRightCtrl : 1; + uint8_t bmRightShift : 1; + uint8_t bmRightAlt : 1; + uint8_t bmRightGUI : 1; + }; + uint8_t bReserved; + uint8_t Keys[6]; +}; + +struct KBDLEDS { + uint8_t bmNumLock : 1; + uint8_t bmCapsLock : 1; + uint8_t bmScrollLock : 1; + uint8_t bmCompose : 1; + uint8_t bmKana : 1; + uint8_t bmReserved : 3; +}; + +#define KEY_NUM_LOCK 0x53 +#define KEY_CAPS_LOCK 0x39 +#define KEY_SCROLL_LOCK 0x47 + +class KeyboardReportParser : public HIDReportParser { + static const uint8_t numKeys[]; + static const uint8_t symKeysUp[]; + static const uint8_t symKeysLo[]; + static const uint8_t padKeys[]; + +protected: + + union { + KBDINFO kbdInfo; + uint8_t bInfo[sizeof(KBDINFO)]; + } prevState; + + union { + KBDLEDS kbdLeds; + uint8_t bLeds; + } kbdLockingKeys; + + uint8_t OemToAscii(uint8_t mod, uint8_t key); + +public: + + KeyboardReportParser() { + kbdLockingKeys.bLeds = 0; + }; + + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); + +protected: + uint8_t HandleLockingKeys(HID* hid, 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 + +template +class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter +{ + EpInfo epInfo[totalEndpoints]; + + HIDReportParser *pRptParser; + + uint8_t bConfNum; // configuration number + uint8_t bIfaceNum; // Interface Number + uint8_t bNumIface; // number of interfaces in the configuration + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + void Initialize(); + + virtual HIDReportParser* GetReportParser(uint8_t id) { + return pRptParser; + }; + +public: + HIDBoot(USB *p); + + virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) { + pRptParser = prs; + return true; + }; + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; + +template +HIDBoot::HIDBoot(USB *p) : +HID(p), +qNextPollTime(0), +bPollEnable(false), +pRptParser(NULL) { + Initialize(); + + if(pUsb) + pUsb->RegisterDeviceClass(this); +} + +template +void HIDBoot::Initialize() { + for(uint8_t i = 0; i < totalEndpoints; 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; + } + bNumEP = 1; + bNumIface = 0; + bConfNum = 0; +} + +template +uint8_t HIDBoot::Init(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t len = 0; + uint16_t cd_len = 0; + + uint8_t num_of_conf; // number of configurations + uint8_t num_of_intf; // number of interfaces + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("BM Init\r\n"); + + if(bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if(!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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, 8, (uint8_t*) buf); + + if(!rcode) + len = (buf[0] > constBufSize) ? constBufSize : buf[0]; + + if(rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + + goto FailGetDevDescr; + } + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + if(len) + rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf); + + if(rcode) + goto FailGetDevDescr; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if(rcode) + goto FailSetDevTblEntry; + + //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); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + + if(bNumEP > 1) + break; + } // for + + if(bNumEP < 2) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + //USBTRACE2("\r\nbAddr:", bAddress); + //USBTRACE2("\r\nbNumEP:", bNumEP); + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + //USBTRACE2("\r\nCnf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if(rcode) + goto FailSetConfDescr; + + //USBTRACE2("\r\nIf:", bIfaceNum); + + rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL); + + if(rcode) + goto FailSetProtocol; + + if(BOOT_PROTOCOL == 1) { + rcode = SetIdle(bIfaceNum, 0, 0); + + if(rcode) + goto FailSetIdle; + } + USBTRACE("BM configured\r\n"); + + bPollEnable = true; + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetProtocol: + USBTRACE("SetProto:"); + goto Fail; + +FailSetIdle: + USBTRACE("SetIdle:"); + goto Fail; + +FailSetConfDescr: + USBTRACE("setConf:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\n"), 0x80); + // Serial.println(rcode, HEX); + Release(); + return rcode; +} + +template +void HIDBoot::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(bNumEP > 1 && conf != bConfNum) + return; + + bConfNum = conf; + bIfaceNum = iface; + + uint8_t index; + + if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { + index = epInterruptInIndex; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + } +} + +template +uint8_t HIDBoot::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bConfNum = 0; + bIfaceNum = 0; + bNumEP = 1; + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +template +uint8_t HIDBoot::Poll() { + uint8_t rcode = 0; + + if(!bPollEnable) + return 0; + + if(qNextPollTime <= millis()) { + qNextPollTime = millis() + 10; + + 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); + + if(rcode) { + if(rcode != hrNAK) + USBTRACE2("Poll:", rcode); + return rcode; + } + //for (uint8_t i=0; i(buf[i]); + //if (read) + // Serial.println(""); + + if(pRptParser) + pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf); + } + return rcode; +} + + #endif // __HIDBOOTMOUSE_H__ \ No newline at end of file diff --git a/hidescriptorparser.cpp b/hidescriptorparser.cpp index af4fc55d..2db1e75c 100644 --- a/hidescriptorparser.cpp +++ b/hidescriptorparser.cpp @@ -1,1713 +1,1626 @@ -#include "hidescriptorparser.h" - -const char *ReportDescParserBase::usagePageTitles0[] PROGMEM = -{ - pstrUsagePageGenericDesktopControls , - pstrUsagePageSimulationControls , - pstrUsagePageVRControls , - pstrUsagePageSportControls , - pstrUsagePageGameControls , - pstrUsagePageGenericDeviceControls , - pstrUsagePageKeyboardKeypad , - pstrUsagePageLEDs , - pstrUsagePageButton , - pstrUsagePageOrdinal , - pstrUsagePageTelephone , - pstrUsagePageConsumer , - pstrUsagePageDigitizer , - pstrUsagePagePID , - pstrUsagePageUnicode -}; - -const char *ReportDescParserBase::usagePageTitles1[] PROGMEM = -{ - pstrUsagePageBarCodeScanner , - pstrUsagePageScale , - pstrUsagePageMSRDevices , - pstrUsagePagePointOfSale , - pstrUsagePageCameraControl , - pstrUsagePageArcade -}; -const char *ReportDescParserBase::genDesktopTitles0[] PROGMEM = -{ - pstrUsagePointer , - pstrUsageMouse , - pstrUsageJoystick , - pstrUsageGamePad , - pstrUsageKeyboard , - pstrUsageKeypad , - pstrUsageMultiAxisController , - pstrUsageTabletPCSystemControls - -}; -const char *ReportDescParserBase::genDesktopTitles1[] PROGMEM = -{ - pstrUsageX , - pstrUsageY , - pstrUsageZ , - pstrUsageRx , - pstrUsageRy , - pstrUsageRz , - pstrUsageSlider , - pstrUsageDial , - pstrUsageWheel , - pstrUsageHatSwitch , - pstrUsageCountedBuffer , - pstrUsageByteCount , - pstrUsageMotionWakeup , - pstrUsageStart , - pstrUsageSelect , - pstrUsagePageReserved , - pstrUsageVx , - pstrUsageVy , - pstrUsageVz , - pstrUsageVbrx , - pstrUsageVbry , - pstrUsageVbrz , - pstrUsageVno , - pstrUsageFeatureNotification , - pstrUsageResolutionMultiplier -}; -const char *ReportDescParserBase::genDesktopTitles2[] PROGMEM = -{ - pstrUsageSystemControl , - pstrUsageSystemPowerDown , - pstrUsageSystemSleep , - pstrUsageSystemWakeup , - pstrUsageSystemContextMenu , - pstrUsageSystemMainMenu , - pstrUsageSystemAppMenu , - pstrUsageSystemMenuHelp , - pstrUsageSystemMenuExit , - pstrUsageSystemMenuSelect , - pstrUsageSystemMenuRight , - pstrUsageSystemMenuLeft , - pstrUsageSystemMenuUp , - pstrUsageSystemMenuDown , - pstrUsageSystemColdRestart , - pstrUsageSystemWarmRestart , - pstrUsageDPadUp , - pstrUsageDPadDown , - pstrUsageDPadRight , - pstrUsageDPadLeft -}; -const char *ReportDescParserBase::genDesktopTitles3[] PROGMEM = -{ - pstrUsageSystemDock , - pstrUsageSystemUndock , - pstrUsageSystemSetup , - pstrUsageSystemBreak , - pstrUsageSystemDebuggerBreak , - pstrUsageApplicationBreak , - pstrUsageApplicationDebuggerBreak, - pstrUsageSystemSpeakerMute , - pstrUsageSystemHibernate -}; -const char *ReportDescParserBase::genDesktopTitles4[] PROGMEM = -{ - pstrUsageSystemDisplayInvert , - pstrUsageSystemDisplayInternal , - pstrUsageSystemDisplayExternal , - pstrUsageSystemDisplayBoth , - pstrUsageSystemDisplayDual , - pstrUsageSystemDisplayToggleIntExt , - pstrUsageSystemDisplaySwapPriSec , - pstrUsageSystemDisplayLCDAutoscale -}; -const char *ReportDescParserBase::simuTitles0[] PROGMEM = -{ - pstrUsageFlightSimulationDevice , - pstrUsageAutomobileSimulationDevice , - pstrUsageTankSimulationDevice , - pstrUsageSpaceshipSimulationDevice , - pstrUsageSubmarineSimulationDevice , - pstrUsageSailingSimulationDevice , - pstrUsageMotocicleSimulationDevice , - pstrUsageSportsSimulationDevice , - pstrUsageAirplaneSimulationDevice , - pstrUsageHelicopterSimulationDevice , - pstrUsageMagicCarpetSimulationDevice, - pstrUsageBicycleSimulationDevice -}; -const char *ReportDescParserBase::simuTitles1[] PROGMEM = -{ - pstrUsageFlightControlStick , - pstrUsageFlightStick , - pstrUsageCyclicControl , - pstrUsageCyclicTrim , - pstrUsageFlightYoke , - pstrUsageTrackControl -}; -const char *ReportDescParserBase::simuTitles2[] PROGMEM = -{ - pstrUsageAileron , - pstrUsageAileronTrim , - pstrUsageAntiTorqueControl , - pstrUsageAutopilotEnable , - pstrUsageChaffRelease , - pstrUsageCollectiveControl , - pstrUsageDiveBrake , - pstrUsageElectronicCountermeasures , - pstrUsageElevator , - pstrUsageElevatorTrim , - pstrUsageRudder , - pstrUsageThrottle , - pstrUsageFlightCommunications , - pstrUsageFlareRelease , - pstrUsageLandingGear , - pstrUsageToeBrake , - pstrUsageTrigger , - pstrUsageWeaponsArm , - pstrUsageWeaponsSelect , - pstrUsageWingFlaps , - pstrUsageAccelerator , - pstrUsageBrake , - pstrUsageClutch , - pstrUsageShifter , - pstrUsageSteering , - pstrUsageTurretDirection , - pstrUsageBarrelElevation , - pstrUsageDivePlane , - pstrUsageBallast , - pstrUsageBicycleCrank , - pstrUsageHandleBars , - pstrUsageFrontBrake , - pstrUsageRearBrake -}; -const char *ReportDescParserBase::vrTitles0[] PROGMEM = -{ - pstrUsageBelt , - pstrUsageBodySuit , - pstrUsageFlexor , - pstrUsageGlove , - pstrUsageHeadTracker , - pstrUsageHeadMountedDisplay , - pstrUsageHandTracker , - pstrUsageOculometer , - pstrUsageVest , - pstrUsageAnimatronicDevice -}; -const char *ReportDescParserBase::vrTitles1[] PROGMEM = -{ - pstrUsageStereoEnable , - pstrUsageDisplayEnable -}; -const char *ReportDescParserBase::sportsCtrlTitles0[] PROGMEM = -{ - pstrUsageBaseballBat , - pstrUsageGolfClub , - pstrUsageRowingMachine , - pstrUsageTreadmill -}; -const char *ReportDescParserBase::sportsCtrlTitles1[] PROGMEM = -{ - pstrUsageOar , - pstrUsageSlope , - pstrUsageRate , - pstrUsageStickSpeed , - pstrUsageStickFaceAngle , - pstrUsageStickHeelToe , - pstrUsageStickFollowThough , - pstrUsageStickTempo , - pstrUsageStickType , - pstrUsageStickHeight -}; -const char *ReportDescParserBase::sportsCtrlTitles2[] PROGMEM = -{ - pstrUsagePutter , - pstrUsage1Iron , - pstrUsage2Iron , - pstrUsage3Iron , - pstrUsage4Iron , - pstrUsage5Iron , - pstrUsage6Iron , - pstrUsage7Iron , - pstrUsage8Iron , - pstrUsage9Iron , - pstrUsage10Iron , - pstrUsage11Iron , - pstrUsageSandWedge , - pstrUsageLoftWedge , - pstrUsagePowerWedge , - pstrUsage1Wood , - pstrUsage3Wood , - pstrUsage5Wood , - pstrUsage7Wood , - pstrUsage9Wood -}; -const char *ReportDescParserBase::gameTitles0[] PROGMEM = -{ - pstrUsage3DGameController , - pstrUsagePinballDevice , - pstrUsageGunDevice -}; -const char *ReportDescParserBase::gameTitles1[] PROGMEM = -{ - pstrUsagePointOfView , - pstrUsageTurnRightLeft , - pstrUsagePitchForwardBackward , - pstrUsageRollRightLeft , - pstrUsageMoveRightLeft , - pstrUsageMoveForwardBackward , - pstrUsageMoveUpDown , - pstrUsageLeanRightLeft , - pstrUsageLeanForwardBackward , - pstrUsageHeightOfPOV , - pstrUsageFlipper , - pstrUsageSecondaryFlipper , - pstrUsageBump , - pstrUsageNewGame , - pstrUsageShootBall , - pstrUsagePlayer , - pstrUsageGunBolt , - pstrUsageGunClip , - pstrUsageGunSelector , - pstrUsageGunSingleShot , - pstrUsageGunBurst , - pstrUsageGunAutomatic , - pstrUsageGunSafety , - pstrUsageGamepadFireJump , - pstrUsageGamepadTrigger -}; -const char *ReportDescParserBase::genDevCtrlTitles[] PROGMEM = -{ - pstrUsageBatteryStrength, - pstrUsageWirelessChannel, - pstrUsageWirelessID, - pstrUsageDiscoverWirelessControl, - pstrUsageSecurityCodeCharEntered, - pstrUsageSecurityCodeCharErased, - pstrUsageSecurityCodeCleared -}; -const char *ReportDescParserBase::ledTitles[] PROGMEM = -{ - pstrUsageNumLock , - pstrUsageCapsLock , - pstrUsageScrollLock , - pstrUsageCompose , - pstrUsageKana , - pstrUsagePower , - pstrUsageShift , - pstrUsageDoNotDisturb , - pstrUsageMute , - pstrUsageToneEnable , - pstrUsageHighCutFilter , - pstrUsageLowCutFilter , - pstrUsageEqualizerEnable , - pstrUsageSoundFieldOn , - pstrUsageSurroundOn , - pstrUsageRepeat , - pstrUsageStereo , - pstrUsageSamplingRateDetect , - pstrUsageSpinning , - pstrUsageCAV , - pstrUsageCLV , - pstrUsageRecordingFormatDetect , - pstrUsageOffHook , - pstrUsageRing , - pstrUsageMessageWaiting , - pstrUsageDataMode , - pstrUsageBatteryOperation , - pstrUsageBatteryOK , - pstrUsageBatteryLow , - pstrUsageSpeaker , - pstrUsageHeadSet , - pstrUsageHold , - pstrUsageMicrophone , - pstrUsageCoverage , - pstrUsageNightMode , - pstrUsageSendCalls , - pstrUsageCallPickup , - pstrUsageConference , - pstrUsageStandBy , - pstrUsageCameraOn , - pstrUsageCameraOff , - pstrUsageOnLine , - pstrUsageOffLine , - pstrUsageBusy , - pstrUsageReady , - pstrUsagePaperOut , - pstrUsagePaperJam , - pstrUsageRemote , - pstrUsageForward , - pstrUsageReverse , - pstrUsageStop , - pstrUsageRewind , - pstrUsageFastForward , - pstrUsagePlay , - pstrUsagePause , - pstrUsageRecord , - pstrUsageError , - pstrUsageSelectedIndicator , - pstrUsageInUseIndicator , - pstrUsageMultiModeIndicator , - pstrUsageIndicatorOn , - pstrUsageIndicatorFlash , - pstrUsageIndicatorSlowBlink , - pstrUsageIndicatorFastBlink , - pstrUsageIndicatorOff , - pstrUsageFlashOnTime , - pstrUsageSlowBlinkOnTime , - pstrUsageSlowBlinkOffTime , - pstrUsageFastBlinkOnTime , - pstrUsageFastBlinkOffTime , - pstrUsageIndicatorColor , - pstrUsageIndicatorRed , - pstrUsageIndicatorGreen , - pstrUsageIndicatorAmber , - pstrUsageGenericIndicator , - pstrUsageSystemSuspend , - pstrUsageExternalPowerConnected -}; -const char *ReportDescParserBase::telTitles0 [] PROGMEM = -{ - pstrUsagePhone , - pstrUsageAnsweringMachine , - pstrUsageMessageControls , - pstrUsageHandset , - pstrUsageHeadset , - pstrUsageTelephonyKeyPad , - pstrUsageProgrammableButton -}; -const char *ReportDescParserBase::telTitles1 [] PROGMEM = -{ - pstrUsageHookSwitch , - pstrUsageFlash , - pstrUsageFeature , - pstrUsageHold , - pstrUsageRedial , - pstrUsageTransfer , - pstrUsageDrop , - pstrUsagePark , - pstrUsageForwardCalls , - pstrUsageAlternateFunction , - pstrUsageLine , - pstrUsageSpeakerPhone , - pstrUsageConference , - pstrUsageRingEnable , - pstrUsageRingSelect , - pstrUsagePhoneMute , - pstrUsageCallerID , - pstrUsageSend -}; -const char *ReportDescParserBase::telTitles2 [] PROGMEM = -{ - pstrUsageSpeedDial , - pstrUsageStoreNumber , - pstrUsageRecallNumber , - pstrUsagePhoneDirectory -}; -const char *ReportDescParserBase::telTitles3 [] PROGMEM = -{ - pstrUsageVoiceMail , - pstrUsageScreenCalls , - pstrUsageDoNotDisturb , - pstrUsageMessage , - pstrUsageAnswerOnOff -}; -const char *ReportDescParserBase::telTitles4 [] PROGMEM = -{ - pstrUsageInsideDialTone , - pstrUsageOutsideDialTone , - pstrUsageInsideRingTone , - pstrUsageOutsideRingTone , - pstrUsagePriorityRingTone , - pstrUsageInsideRingback , - pstrUsagePriorityRingback , - pstrUsageLineBusyTone , - pstrUsageReorderTone , - pstrUsageCallWaitingTone , - pstrUsageConfirmationTone1 , - pstrUsageConfirmationTone2 , - pstrUsageTonesOff , - pstrUsageOutsideRingback , - pstrUsageRinger -}; -const char *ReportDescParserBase::telTitles5 [] PROGMEM = -{ - pstrUsagePhoneKey0 , - pstrUsagePhoneKey1 , - pstrUsagePhoneKey2 , - pstrUsagePhoneKey3 , - pstrUsagePhoneKey4 , - pstrUsagePhoneKey5 , - pstrUsagePhoneKey6 , - pstrUsagePhoneKey7 , - pstrUsagePhoneKey8 , - pstrUsagePhoneKey9 , - pstrUsagePhoneKeyStar , - pstrUsagePhoneKeyPound , - pstrUsagePhoneKeyA , - pstrUsagePhoneKeyB , - pstrUsagePhoneKeyC , - pstrUsagePhoneKeyD -}; -const char *ReportDescParserBase::consTitles0[] PROGMEM = -{ - pstrUsageConsumerControl, - pstrUsageNumericKeyPad, - pstrUsageProgrammableButton, - pstrUsageMicrophone, - pstrUsageHeadphone, - pstrUsageGraphicEqualizer -}; -const char *ReportDescParserBase::consTitles1[] PROGMEM = -{ - pstrUsagePlus10 , - pstrUsagePlus100, - pstrUsageAMPM -}; -const char *ReportDescParserBase::consTitles2[] PROGMEM = -{ - pstrUsagePower , - pstrUsageReset , - pstrUsageSleep , - pstrUsageSleepAfter , - pstrUsageSleepMode , - pstrUsageIllumination , - pstrUsageFunctionButtons - -}; -const char *ReportDescParserBase::consTitles3[] PROGMEM = -{ - pstrUsageMenu , - pstrUsageMenuPick , - pstrUsageMenuUp , - pstrUsageMenuDown , - pstrUsageMenuLeft , - pstrUsageMenuRight , - pstrUsageMenuEscape , - pstrUsageMenuValueIncrease, - pstrUsageMenuValueDecrease -}; -const char *ReportDescParserBase::consTitles4[] PROGMEM = -{ - pstrUsageDataOnScreen , - pstrUsageClosedCaption , - pstrUsageClosedCaptionSelect, - pstrUsageVCRTV , - pstrUsageBroadcastMode , - pstrUsageSnapshot , - pstrUsageStill -}; -const char *ReportDescParserBase::consTitles5[] PROGMEM = -{ - pstrUsageSelection , - pstrUsageAssignSelection , - pstrUsageModeStep , - pstrUsageRecallLast , - pstrUsageEnterChannel , - pstrUsageOrderMovie , - pstrUsageChannel , - pstrUsageMediaSelection , - pstrUsageMediaSelectComputer , - pstrUsageMediaSelectTV , - pstrUsageMediaSelectWWW , - pstrUsageMediaSelectDVD , - pstrUsageMediaSelectTelephone , - pstrUsageMediaSelectProgramGuide , - pstrUsageMediaSelectVideoPhone , - pstrUsageMediaSelectGames , - pstrUsageMediaSelectMessages , - pstrUsageMediaSelectCD , - pstrUsageMediaSelectVCR , - pstrUsageMediaSelectTuner , - pstrUsageQuit , - pstrUsageHelp , - pstrUsageMediaSelectTape , - pstrUsageMediaSelectCable , - pstrUsageMediaSelectSatellite , - pstrUsageMediaSelectSecurity , - pstrUsageMediaSelectHome , - pstrUsageMediaSelectCall , - pstrUsageChannelIncrement , - pstrUsageChannelDecrement , - pstrUsageMediaSelectSAP , - pstrUsagePageReserved , - pstrUsageVCRPlus , - pstrUsageOnce , - pstrUsageDaily , - pstrUsageWeekly , - pstrUsageMonthly -}; -const char *ReportDescParserBase::consTitles6[] PROGMEM = -{ - pstrUsagePlay , - pstrUsagePause , - pstrUsageRecord , - pstrUsageFastForward , - pstrUsageRewind , - pstrUsageScanNextTrack , - pstrUsageScanPreviousTrack , - pstrUsageStop , - pstrUsageEject , - pstrUsageRandomPlay , - pstrUsageSelectDisk , - pstrUsageEnterDisk , - pstrUsageRepeat , - pstrUsageTracking , - pstrUsageTrackNormal , - pstrUsageSlowTracking , - pstrUsageFrameForward , - pstrUsageFrameBackwards , - pstrUsageMark , - pstrUsageClearMark , - pstrUsageRepeatFromMark , - pstrUsageReturnToMark , - pstrUsageSearchMarkForward , - pstrUsageSearchMarkBackwards , - pstrUsageCounterReset , - pstrUsageShowCounter , - pstrUsageTrackingIncrement , - pstrUsageTrackingDecrement , - pstrUsageStopEject , - pstrUsagePlayPause , - pstrUsagePlaySkip -}; -const char *ReportDescParserBase::consTitles7[] PROGMEM = -{ - pstrUsageVolume , - pstrUsageBalance , - pstrUsageMute , - pstrUsageBass , - pstrUsageTreble , - pstrUsageBassBoost , - pstrUsageSurroundMode , - pstrUsageLoudness , - pstrUsageMPX , - pstrUsageVolumeIncrement , - pstrUsageVolumeDecrement -}; -const char *ReportDescParserBase::consTitles8[] PROGMEM = -{ - pstrUsageSpeedSelect , - pstrUsagePlaybackSpeed , - pstrUsageStandardPlay , - pstrUsageLongPlay , - pstrUsageExtendedPlay , - pstrUsageSlow -}; -const char *ReportDescParserBase::consTitles9[] PROGMEM = -{ - pstrUsageFanEnable , - pstrUsageFanSpeed , - pstrUsageLightEnable , - pstrUsageLightIlluminationLevel , - pstrUsageClimateControlEnable , - pstrUsageRoomTemperature , - pstrUsageSecurityEnable , - pstrUsageFireAlarm , - pstrUsagePoliceAlarm , - pstrUsageProximity , - pstrUsageMotion , - pstrUsageDuresAlarm , - pstrUsageHoldupAlarm , - pstrUsageMedicalAlarm -}; -const char *ReportDescParserBase::consTitlesA[] PROGMEM = -{ - pstrUsageBalanceRight , - pstrUsageBalanceLeft , - pstrUsageBassIncrement , - pstrUsageBassDecrement , - pstrUsageTrebleIncrement , - pstrUsageTrebleDecrement -}; -const char *ReportDescParserBase::consTitlesB[] PROGMEM = -{ - pstrUsageSpeakerSystem , - pstrUsageChannelLeft , - pstrUsageChannelRight , - pstrUsageChannelCenter , - pstrUsageChannelFront , - pstrUsageChannelCenterFront , - pstrUsageChannelSide , - pstrUsageChannelSurround , - pstrUsageChannelLowFreqEnhancement , - pstrUsageChannelTop , - pstrUsageChannelUnknown -}; -const char *ReportDescParserBase::consTitlesC[] PROGMEM = -{ - pstrUsageSubChannel , - pstrUsageSubChannelIncrement , - pstrUsageSubChannelDecrement , - pstrUsageAlternateAudioIncrement , - pstrUsageAlternateAudioDecrement -}; -const char *ReportDescParserBase::consTitlesD[] PROGMEM = -{ - pstrUsageApplicationLaunchButtons , - pstrUsageALLaunchButtonConfigTool , - pstrUsageALProgrammableButton , - pstrUsageALConsumerControlConfig , - pstrUsageALWordProcessor , - pstrUsageALTextEditor , - pstrUsageALSpreadsheet , - pstrUsageALGraphicsEditor , - pstrUsageALPresentationApp , - pstrUsageALDatabaseApp , - pstrUsageALEmailReader , - pstrUsageALNewsreader , - pstrUsageALVoicemail , - pstrUsageALContactsAddressBook , - pstrUsageALCalendarSchedule , - pstrUsageALTaskProjectManager , - pstrUsageALLogJournalTimecard , - pstrUsageALCheckbookFinance , - pstrUsageALCalculator , - pstrUsageALAVCapturePlayback , - pstrUsageALLocalMachineBrowser , - pstrUsageALLANWANBrow , - pstrUsageALInternetBrowser , - pstrUsageALRemoteNetISPConnect , - pstrUsageALNetworkConference , - pstrUsageALNetworkChat , - pstrUsageALTelephonyDialer , - pstrUsageALLogon , - pstrUsageALLogoff , - pstrUsageALLogonLogoff , - pstrUsageALTermLockScrSav , - pstrUsageALControlPannel , - pstrUsageALCommandLineProcessorRun , - pstrUsageALProcessTaskManager , - pstrUsageALSelectTaskApplication , - pstrUsageALNextTaskApplication , - pstrUsageALPreviousTaskApplication , - pstrUsageALPreemptiveHaltTaskApp , - pstrUsageALIntegratedHelpCenter , - pstrUsageALDocuments , - pstrUsageALThesaurus , - pstrUsageALDictionary , - pstrUsageALDesktop , - pstrUsageALSpellCheck , - pstrUsageALGrammarCheck , - pstrUsageALWirelessStatus , - pstrUsageALKeyboardLayout , - pstrUsageALVirusProtection , - pstrUsageALEncryption , - pstrUsageALScreenSaver , - pstrUsageALAlarms , - pstrUsageALClock , - pstrUsageALFileBrowser , - pstrUsageALPowerStatus , - pstrUsageALImageBrowser , - pstrUsageALAudioBrowser , - pstrUsageALMovieBrowser , - pstrUsageALDigitalRightsManager , - pstrUsageALDigitalWallet , - pstrUsagePageReserved , - pstrUsageALInstantMessaging , - pstrUsageALOEMFeaturesBrowser , - pstrUsageALOEMHelp , - pstrUsageALOnlineCommunity , - pstrUsageALEntertainmentContentBrow , - pstrUsageALOnlineShoppingBrowser , - pstrUsageALSmartCardInfoHelp , - pstrUsageALMarketMonitorFinBrowser , - pstrUsageALCustomCorpNewsBrowser , - pstrUsageALOnlineActivityBrowser , - pstrUsageALResearchSearchBrowser , - pstrUsageALAudioPlayer -}; -const char *ReportDescParserBase::consTitlesE[] PROGMEM = -{ - pstrUsageGenericGUIAppControls , - pstrUsageACNew , - pstrUsageACOpen , - pstrUsageACClose , - pstrUsageACExit , - pstrUsageACMaximize , - pstrUsageACMinimize , - pstrUsageACSave , - pstrUsageACPrint , - pstrUsageACProperties , - pstrUsageACUndo , - pstrUsageACCopy , - pstrUsageACCut , - pstrUsageACPaste , - pstrUsageACSelectAll , - pstrUsageACFind , - pstrUsageACFindAndReplace , - pstrUsageACSearch , - pstrUsageACGoto , - pstrUsageACHome , - pstrUsageACBack , - pstrUsageACForward , - pstrUsageACStop , - pstrUsageACRefresh , - pstrUsageACPreviousLink , - pstrUsageACNextLink , - pstrUsageACBookmarks , - pstrUsageACHistory , - pstrUsageACSubscriptions , - pstrUsageACZoomIn , - pstrUsageACZoomOut , - pstrUsageACZoom , - pstrUsageACFullScreenView , - pstrUsageACNormalView , - pstrUsageACViewToggle , - pstrUsageACScrollUp , - pstrUsageACScrollDown , - pstrUsageACScroll , - pstrUsageACPanLeft , - pstrUsageACPanRight , - pstrUsageACPan , - pstrUsageACNewWindow , - pstrUsageACTileHoriz , - pstrUsageACTileVert , - pstrUsageACFormat , - pstrUsageACEdit , - pstrUsageACBold , - pstrUsageACItalics , - pstrUsageACUnderline , - pstrUsageACStrikethrough , - pstrUsageACSubscript , - pstrUsageACSuperscript , - pstrUsageACAllCaps , - pstrUsageACRotate , - pstrUsageACResize , - pstrUsageACFlipHorizontal , - pstrUsageACFlipVertical , - pstrUsageACMirrorHorizontal , - pstrUsageACMirrorVertical , - pstrUsageACFontSelect , - pstrUsageACFontColor , - pstrUsageACFontSize , - pstrUsageACJustifyLeft , - pstrUsageACJustifyCenterH , - pstrUsageACJustifyRight , - pstrUsageACJustifyBlockH , - pstrUsageACJustifyTop , - pstrUsageACJustifyCenterV , - pstrUsageACJustifyBottom , - pstrUsageACJustifyBlockV , - pstrUsageACIndentDecrease , - pstrUsageACIndentIncrease , - pstrUsageACNumberedList , - pstrUsageACRestartNumbering , - pstrUsageACBulletedList , - pstrUsageACPromote , - pstrUsageACDemote , - pstrUsageACYes , - pstrUsageACNo , - pstrUsageACCancel , - pstrUsageACCatalog , - pstrUsageACBuyChkout , - pstrUsageACAddToCart , - pstrUsageACExpand , - pstrUsageACExpandAll , - pstrUsageACCollapse , - pstrUsageACCollapseAll , - pstrUsageACPrintPreview , - pstrUsageACPasteSpecial , - pstrUsageACInsertMode , - pstrUsageACDelete , - pstrUsageACLock , - pstrUsageACUnlock , - pstrUsageACProtect , - pstrUsageACUnprotect , - pstrUsageACAttachComment , - pstrUsageACDeleteComment , - pstrUsageACViewComment , - pstrUsageACSelectWord , - pstrUsageACSelectSentence , - pstrUsageACSelectParagraph , - pstrUsageACSelectColumn , - pstrUsageACSelectRow , - pstrUsageACSelectTable , - pstrUsageACSelectObject , - pstrUsageACRedoRepeat , - pstrUsageACSort , - pstrUsageACSortAscending , - pstrUsageACSortDescending , - pstrUsageACFilter , - pstrUsageACSetClock , - pstrUsageACViewClock , - pstrUsageACSelectTimeZone , - pstrUsageACEditTimeZone , - pstrUsageACSetAlarm , - pstrUsageACClearAlarm , - pstrUsageACSnoozeAlarm , - pstrUsageACResetAlarm , - pstrUsageACSyncronize , - pstrUsageACSendReceive , - pstrUsageACSendTo , - pstrUsageACReply , - pstrUsageACReplyAll , - pstrUsageACForwardMessage , - pstrUsageACSend , - pstrUsageACAttachFile , - pstrUsageACUpload , - pstrUsageACDownload , - pstrUsageACSetBorders , - pstrUsageACInsertRow , - pstrUsageACInsertColumn , - pstrUsageACInsertFile , - pstrUsageACInsertPicture , - pstrUsageACInsertObject , - pstrUsageACInsertSymbol , - pstrUsageACSaveAndClose , - pstrUsageACRename , - pstrUsageACMerge , - pstrUsageACSplit , - pstrUsageACDistributeHorizontaly , - pstrUsageACDistributeVerticaly -}; -const char *ReportDescParserBase::digitTitles0[] PROGMEM = -{ - pstrUsageDigitizer , - pstrUsagePen , - pstrUsageLightPen , - pstrUsageTouchScreen , - pstrUsageTouchPad , - pstrUsageWhiteBoard , - pstrUsageCoordinateMeasuringMachine , - pstrUsage3DDigitizer , - pstrUsageStereoPlotter , - pstrUsageArticulatedArm , - pstrUsageArmature , - pstrUsageMultiplePointDigitizer , - pstrUsageFreeSpaceWand -}; -const char *ReportDescParserBase::digitTitles1[] PROGMEM = -{ - pstrUsageStylus , - pstrUsagePuck , - pstrUsageFinger - -}; -const char *ReportDescParserBase::digitTitles2[] PROGMEM = -{ - pstrUsageTipPressure , - pstrUsageBarrelPressure , - pstrUsageInRange , - pstrUsageTouch , - pstrUsageUntouch , - pstrUsageTap , - pstrUsageQuality , - pstrUsageDataValid , - pstrUsageTransducerIndex , - pstrUsageTabletFunctionKeys , - pstrUsageProgramChangeKeys , - pstrUsageBatteryStrength , - pstrUsageInvert , - pstrUsageXTilt , - pstrUsageYTilt , - pstrUsageAzimuth , - pstrUsageAltitude , - pstrUsageTwist , - pstrUsageTipSwitch , - pstrUsageSecondaryTipSwitch , - pstrUsageBarrelSwitch , - pstrUsageEraser , - pstrUsageTabletPick -}; -const char *ReportDescParserBase::aplphanumTitles0[] PROGMEM = -{ - pstrUsageAlphanumericDisplay, - pstrUsageBitmappedDisplay -}; -const char *ReportDescParserBase::aplphanumTitles1[] PROGMEM = -{ - pstrUsageDisplayAttributesReport , - pstrUsageASCIICharacterSet , - pstrUsageDataReadBack , - pstrUsageFontReadBack , - pstrUsageDisplayControlReport , - pstrUsageClearDisplay , - pstrUsageDisplayEnable , - pstrUsageScreenSaverDelay , - pstrUsageScreenSaverEnable , - pstrUsageVerticalScroll , - pstrUsageHorizontalScroll , - pstrUsageCharacterReport , - pstrUsageDisplayData , - pstrUsageDisplayStatus , - pstrUsageStatusNotReady , - pstrUsageStatusReady , - pstrUsageErrorNotALoadableCharacter , - pstrUsageErrorFotDataCanNotBeRead , - pstrUsageCursorPositionReport , - pstrUsageRow , - pstrUsageColumn , - pstrUsageRows , - pstrUsageColumns , - pstrUsageCursorPixelPosition , - pstrUsageCursorMode , - pstrUsageCursorEnable , - pstrUsageCursorBlink , - pstrUsageFontReport , - pstrUsageFontData , - pstrUsageCharacterWidth , - pstrUsageCharacterHeight , - pstrUsageCharacterSpacingHorizontal , - pstrUsageCharacterSpacingVertical , - pstrUsageUnicodeCharset , - pstrUsageFont7Segment , - pstrUsage7SegmentDirectMap , - pstrUsageFont14Segment , - pstrUsage14SegmentDirectMap , - pstrUsageDisplayBrightness , - pstrUsageDisplayContrast , - pstrUsageCharacterAttribute , - pstrUsageAttributeReadback , - pstrUsageAttributeData , - pstrUsageCharAttributeEnhance , - pstrUsageCharAttributeUnderline , - pstrUsageCharAttributeBlink -}; -const char *ReportDescParserBase::aplphanumTitles2[] PROGMEM = -{ - pstrUsageBitmapSizeX , - pstrUsageBitmapSizeY , - pstrUsagePageReserved , - pstrUsageBitDepthFormat , - pstrUsageDisplayOrientation , - pstrUsagePaletteReport , - pstrUsagePaletteDataSize , - pstrUsagePaletteDataOffset , - pstrUsagePaletteData , - pstrUsageBlitReport , - pstrUsageBlitRectangleX1 , - pstrUsageBlitRectangleY1 , - pstrUsageBlitRectangleX2 , - pstrUsageBlitRectangleY2 , - pstrUsageBlitData , - pstrUsageSoftButton , - pstrUsageSoftButtonID , - pstrUsageSoftButtonSide , - pstrUsageSoftButtonOffset1 , - pstrUsageSoftButtonOffset2 , - pstrUsageSoftButtonReport -}; -const char *ReportDescParserBase::medInstrTitles0[] PROGMEM = -{ - pstrUsageVCRAcquisition , - pstrUsageFreezeThaw , - pstrUsageClipStore , - pstrUsageUpdate , - pstrUsageNext , - pstrUsageSave , - pstrUsagePrint , - pstrUsageMicrophoneEnable -}; -const char *ReportDescParserBase::medInstrTitles1[] PROGMEM = -{ - pstrUsageCine , - pstrUsageTransmitPower , - pstrUsageVolume , - pstrUsageFocus , - pstrUsageDepth -}; -const char *ReportDescParserBase::medInstrTitles2[] PROGMEM = -{ - pstrUsageSoftStepPrimary , - pstrUsageSoftStepSecondary -}; -const char *ReportDescParserBase::medInstrTitles3[] PROGMEM = -{ - pstrUsageZoomSelect , - pstrUsageZoomAdjust , - pstrUsageSpectralDopplerModeSelect , - pstrUsageSpectralDopplerModeAdjust , - pstrUsageColorDopplerModeSelect , - pstrUsageColorDopplerModeAdjust , - pstrUsageMotionModeSelect , - pstrUsageMotionModeAdjust , - pstrUsage2DModeSelect , - pstrUsage2DModeAdjust -}; -const char *ReportDescParserBase::medInstrTitles4[] PROGMEM = -{ - pstrUsageSoftControlSelect , - pstrUsageSoftControlAdjust -}; - -void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) -{ - uint16_t cntdn = (uint16_t)len; - uint8_t *p = (uint8_t*)pbuf; - - - totalSize = 0; - - while(cntdn) - { - //Serial.println(""); - //PrintHex(offset + len - cntdn); - //Serial.print(":"); - - ParseItem(&p, &cntdn); - - //if (ParseItem(&p, &cntdn)) - // return; - } - //USBTRACE2("Total:", totalSize); -} - -void ReportDescParserBase::PrintValue(uint8_t *p, uint8_t len) -{ - Notify(PSTR("(")); - for (; len; p++, len--) - PrintHex(*p); - Notify(PSTR(")")); -} - -void ReportDescParserBase::PrintByteValue(uint8_t data) -{ - Notify(PSTR("(")); - PrintHex(data); - Notify(PSTR(")")); -} - -void ReportDescParserBase::PrintItemTitle(uint8_t prefix) -{ - switch (prefix & (TYPE_MASK | TAG_MASK)) - { - case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): - Notify(PSTR("\r\nPush")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_POP): - Notify(PSTR("\r\nPop")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): - Notify(PSTR("\r\nUsage Page")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): - Notify(PSTR("\r\nLogical Min")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): - Notify(PSTR("\r\nLogical Max")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): - Notify(PSTR("\r\nPhysical Min")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): - Notify(PSTR("\r\nPhysical Max")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): - Notify(PSTR("\r\nUnit Exp")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): - Notify(PSTR("\r\nUnit")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - Notify(PSTR("\r\nReport Size")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): - Notify(PSTR("\r\nReport Count")); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): - Notify(PSTR("\r\nReport Id")); - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGE): - Notify(PSTR("\r\nUsage")); - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): - Notify(PSTR("\r\nUsage Min")); - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): - Notify(PSTR("\r\nUsage Max")); - break; - case (TYPE_MAIN | TAG_MAIN_COLLECTION): - Notify(PSTR("\r\nCollection")); - break; - case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): - Notify(PSTR("\r\nEnd Collection")); - break; - case (TYPE_MAIN | TAG_MAIN_INPUT): - Notify(PSTR("\r\nInput")); - break; - case (TYPE_MAIN | TAG_MAIN_OUTPUT): - Notify(PSTR("\r\nOutput")); - break; - case (TYPE_MAIN | TAG_MAIN_FEATURE): - Notify(PSTR("\r\nFeature")); - break; - } // switch (**pp & (TYPE_MASK | TAG_MASK)) -} -uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) -{ - uint8_t ret = enErrorSuccess; - - switch (itemParseState) - { - case 0: - if (**pp == HID_LONG_ITEM_PREFIX) - USBTRACE("\r\nLONG\r\n"); - else - { - uint8_t size = ((**pp) & DATA_SIZE_MASK); - - itemPrefix = (**pp); - itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); - - PrintItemTitle(itemPrefix); - } - (*pp) ++; - (*pcntdn) --; - itemSize --; - itemParseState = 1; - - if (!itemSize) - break; - - if (!pcntdn) - return enErrorIncomplete; - case 1: - //USBTRACE2("\r\niSz:",itemSize); - - theBuffer.valueSize = itemSize; - valParser.Initialize(&theBuffer); - itemParseState = 2; - case 2: - if (!valParser.Parse(pp, pcntdn)) - return enErrorIncomplete; - itemParseState = 3; - case 3: - { - uint8_t data = *((uint8_t*)varBuffer); - - switch (itemPrefix & (TYPE_MASK | TAG_MASK)) - { - case (TYPE_LOCAL | TAG_LOCAL_USAGE): - if (pfUsage) - if (theBuffer.valueSize > 1) - pfUsage(*((uint16_t*)varBuffer)); - else - pfUsage(data); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - rptSize = data; - PrintByteValue(data); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): - rptCount = data; - PrintByteValue(data); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): - case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): - case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): - case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): - case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): - PrintValue(varBuffer, theBuffer.valueSize); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): - case (TYPE_GLOBAL | TAG_GLOBAL_POP): - break; - case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): - SetUsagePage(data); - PrintUsagePage(data); - PrintByteValue(data); - break; - case (TYPE_MAIN | TAG_MAIN_COLLECTION): - case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): - switch (data) - { - case 0x00: - Notify(PSTR(" Physical")); - break; - case 0x01: - Notify(PSTR(" Application")); - break; - case 0x02: - Notify(PSTR(" Logical")); - break; - case 0x03: - Notify(PSTR(" Report")); - break; - case 0x04: - Notify(PSTR(" Named Array")); - break; - case 0x05: - Notify(PSTR(" Usage Switch")); - break; - case 0x06: - Notify(PSTR(" Usage Modifier")); - break; - default: - Notify(PSTR(" Vendor Defined(")); - PrintHex(data); - Notify(PSTR(")")); - } - break; - case (TYPE_MAIN | TAG_MAIN_INPUT): - case (TYPE_MAIN | TAG_MAIN_OUTPUT): - case (TYPE_MAIN | TAG_MAIN_FEATURE): - totalSize += (uint16_t)rptSize * (uint16_t)rptCount; - rptSize = 0; - rptCount = 0; - Notify(PSTR("(")); - PrintBin(data); - Notify(PSTR(")")); - break; - } // switch (**pp & (TYPE_MASK | TAG_MASK)) - } - } // switch (itemParseState) - itemParseState = 0; - return enErrorSuccess; -} - -ReportDescParserBase::UsagePageFunc ReportDescParserBase::usagePageFunctions[] /*PROGMEM*/ = -{ - &ReportDescParserBase::PrintGenericDesktopPageUsage, - &ReportDescParserBase::PrintSimulationControlsPageUsage, - &ReportDescParserBase::PrintVRControlsPageUsage, - &ReportDescParserBase::PrintSportsControlsPageUsage, - &ReportDescParserBase::PrintGameControlsPageUsage, - &ReportDescParserBase::PrintGenericDeviceControlsPageUsage, - NULL, // Keyboard/Keypad - &ReportDescParserBase::PrintLEDPageUsage, - &ReportDescParserBase::PrintButtonPageUsage, - &ReportDescParserBase::PrintOrdinalPageUsage, - &ReportDescParserBase::PrintTelephonyPageUsage, - &ReportDescParserBase::PrintConsumerPageUsage, - &ReportDescParserBase::PrintDigitizerPageUsage, - NULL, // Reserved - NULL, // PID - NULL // Unicode -}; - -void ReportDescParserBase::SetUsagePage(uint16_t page) -{ - pfUsage = NULL; - - if (page > 0x00 && page < 0x11) - pfUsage = /*(UsagePageFunc)pgm_read_word*/(usagePageFunctions[page - 1]); - //else if (page > 0x7f && page < 0x84) - // Notify(pstrUsagePageMonitor); - //else if (page > 0x83 && page < 0x8c) - // Notify(pstrUsagePagePower); - //else if (page > 0x8b && page < 0x92) - // Notify((char*)pgm_read_word(&usagePageTitles1[page - 0x8c])); - //else if (page > 0xfeff && page <= 0xffff) - // Notify(pstrUsagePageVendorDefined); - else - switch (page) - { - case 0x14: - pfUsage = &ReportDescParserBase::PrintAlphanumDisplayPageUsage; - break; - case 0x40: - pfUsage = &ReportDescParserBase::PrintMedicalInstrumentPageUsage; - break; - } -} - -void ReportDescParserBase::PrintUsagePage(uint16_t page) -{ - Notify(pstrSpace); - - if (page > 0x00 && page < 0x11) - Notify((char*)pgm_read_word(&usagePageTitles0[page - 1])); - else if (page > 0x7f && page < 0x84) - Notify(pstrUsagePageMonitor); - else if (page > 0x83 && page < 0x8c) - Notify(pstrUsagePagePower); - else if (page > 0x8b && page < 0x92) - Notify((char*)pgm_read_word(&usagePageTitles1[page - 0x8c])); - else if (page > 0xfeff && page <= 0xffff) - Notify(pstrUsagePageVendorDefined); - else - switch (page) - { - case 0x14: - Notify(pstrUsagePageAlphaNumericDisplay); - break; - case 0x40: - Notify(pstrUsagePageMedicalInstruments); - break; - default: - Notify(pstrUsagePageUndefined); - } -} - -void ReportDescParserBase::PrintButtonPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - Notify(PSTR("Btn")); - Serial.print(usage, HEX); -} - -void ReportDescParserBase::PrintOrdinalPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - Notify(PSTR("Inst")); - Serial.print(usage, DEC); -} - -void ReportDescParserBase::PrintGenericDesktopPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x0a) - Notify((char*)pgm_read_word(&genDesktopTitles0[usage - 1])); - else if (usage > 0x2f && usage < 0x49) - Notify((char*)pgm_read_word(&genDesktopTitles1[usage - 0x30])); - else if (usage > 0x7f && usage < 0x94) - Notify((char*)pgm_read_word(&genDesktopTitles2[usage - 0x80])); - else if (usage > 0x9f && usage < 0xa9) - Notify((char*)pgm_read_word(&genDesktopTitles3[usage - 0xa0])); - else if (usage > 0xaf && usage < 0xb8) - Notify((char*)pgm_read_word(&genDesktopTitles4[usage - 0xb0])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintSimulationControlsPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x0d) - Notify((char*)pgm_read_word(&simuTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x26) - Notify((char*)pgm_read_word(&simuTitles1[usage - 0x20])); - else if (usage > 0xaf && usage < 0xd1) - Notify((char*)pgm_read_word(&simuTitles2[usage - 0xb0])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintVRControlsPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x0b) - Notify((char*)pgm_read_word(&vrTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x22) - Notify((char*)pgm_read_word(&vrTitles1[usage - 0x20])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintSportsControlsPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x05) - Notify((char*)pgm_read_word(&sportsCtrlTitles0[usage - 1])); - else if (usage > 0x2f && usage < 0x3a) - Notify((char*)pgm_read_word(&sportsCtrlTitles1[usage - 0x30])); - else if (usage > 0x4f && usage < 0x64) - Notify((char*)pgm_read_word(&sportsCtrlTitles2[usage - 0x50])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintGameControlsPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x04) - Notify((char*)pgm_read_word(&gameTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x3a) - Notify((char*)pgm_read_word(&gameTitles1[usage - 0x20])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintGenericDeviceControlsPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x1f && usage < 0x27) - Notify((char*)pgm_read_word(&genDevCtrlTitles[usage - 0x20])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintLEDPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x4e) - Notify((char*)pgm_read_word(&ledTitles[usage - 1])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintTelephonyPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x08) - Notify((char*)pgm_read_word(&telTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x32) - Notify((char*)pgm_read_word(&telTitles1[usage - 0x1f])); - else if (usage > 0x4f && usage < 0x54) - Notify((char*)pgm_read_word(&telTitles2[usage - 0x4f])); - else if (usage > 0x6f && usage < 0x75) - Notify((char*)pgm_read_word(&telTitles3[usage - 0x6f])); - else if (usage > 0x8f && usage < 0x9f) - Notify((char*)pgm_read_word(&telTitles4[usage - 0x8f])); - else if (usage > 0xaf && usage < 0xc0) - Notify((char*)pgm_read_word(&telTitles5[usage - 0xaf])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintConsumerPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x07) - Notify((char*)pgm_read_word(&consTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x23) - Notify((char*)pgm_read_word(&consTitles1[usage - 0x1f])); - else if (usage > 0x2f && usage < 0x37) - Notify((char*)pgm_read_word(&consTitles2[usage - 0x2f])); - else if (usage > 0x3f && usage < 0x49) - Notify((char*)pgm_read_word(&consTitles3[usage - 0x3f])); - else if (usage > 0x5f && usage < 0x67) - Notify((char*)pgm_read_word(&consTitles4[usage - 0x5f])); - else if (usage > 0x7f && usage < 0xa5) - Notify((char*)pgm_read_word(&consTitles5[usage - 0x7f])); - else if (usage > 0xaf && usage < 0xcf) - Notify((char*)pgm_read_word(&consTitles6[usage - 0xaf])); - else if (usage > 0xdf && usage < 0xeb) - Notify((char*)pgm_read_word(&consTitles7[usage - 0xdf])); - else if (usage > 0xef && usage < 0xf6) - Notify((char*)pgm_read_word(&consTitles8[usage - 0xef])); - else if (usage > 0xff && usage < 0x10e) - Notify((char*)pgm_read_word(&consTitles9[usage - 0xff])); - else if (usage > 0x14f && usage < 0x156) - Notify((char*)pgm_read_word(&consTitlesA[usage - 0x14f])); - else if (usage > 0x15f && usage < 0x16b) - Notify((char*)pgm_read_word(&consTitlesB[usage - 0x15f])); - else if (usage > 0x16f && usage < 0x175) - Notify((char*)pgm_read_word(&consTitlesC[usage - 0x16f])); - else if (usage > 0x17f && usage < 0x1c8) - Notify((char*)pgm_read_word(&consTitlesD[usage - 0x17f])); - else if (usage > 0x1ff && usage < 0x29d) - Notify((char*)pgm_read_word(&consTitlesE[usage - 0x1ff])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintDigitizerPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x0e) - Notify((char*)pgm_read_word(&digitTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x23) - Notify((char*)pgm_read_word(&digitTitles1[usage - 0x1f])); - else if (usage > 0x2f && usage < 0x47) - Notify((char*)pgm_read_word(&digitTitles2[usage - 0x2f])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintAlphanumDisplayPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage > 0x00 && usage < 0x03) - Notify((char*)pgm_read_word(&aplphanumTitles0[usage - 1])); - else if (usage > 0x1f && usage < 0x4e) - Notify((char*)pgm_read_word(&aplphanumTitles1[usage - 0x1f])); - else if (usage > 0x7f && usage < 0x96) - Notify((char*)pgm_read_word(&digitTitles2[usage - 0x80])); - else - Notify(pstrUsagePageUndefined); -} - -void ReportDescParserBase::PrintMedicalInstrumentPageUsage(uint16_t usage) -{ - Notify(pstrSpace); - - if (usage == 1) - Notify(pstrUsageMedicalUltrasound); - else if (usage > 0x1f && usage < 0x28) - Notify((char*)pgm_read_word(&medInstrTitles0[usage - 0x1f])); - else if (usage > 0x3f && usage < 0x45) - Notify((char*)pgm_read_word(&medInstrTitles1[usage - 0x40])); - else if (usage > 0x5f && usage < 0x62) - Notify((char*)pgm_read_word(&medInstrTitles2[usage - 0x60])); - else if (usage == 0x70) - Notify(pstrUsageDepthGainCompensation); - else if (usage > 0x7f && usage < 0x8a) - Notify((char*)pgm_read_word(&medInstrTitles3[usage - 0x80])); - else if (usage > 0x9f && usage < 0xa2) - Notify((char*)pgm_read_word(&medInstrTitles4[usage - 0xa0])); - else - Notify(pstrUsagePageUndefined); -} - - - - - -uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) -{ - uint8_t ret = enErrorSuccess; - - switch (itemParseState) - { - case 0: - if (**pp == HID_LONG_ITEM_PREFIX) - USBTRACE("\r\nLONG\r\n"); - else - { - uint8_t size = ((**pp) & DATA_SIZE_MASK); - itemPrefix = (**pp); - itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); - } - (*pp) ++; - (*pcntdn) --; - itemSize --; - itemParseState = 1; - - if (!itemSize) - break; - - if (!pcntdn) - return enErrorIncomplete; - case 1: - theBuffer.valueSize = itemSize; - valParser.Initialize(&theBuffer); - itemParseState = 2; - case 2: - if (!valParser.Parse(pp, pcntdn)) - return enErrorIncomplete; - itemParseState = 3; - case 3: - { - uint8_t data = *((uint8_t*)varBuffer); - - switch (itemPrefix & (TYPE_MASK | TAG_MASK)) - { - case (TYPE_LOCAL | TAG_LOCAL_USAGE): - if (pfUsage) - if (theBuffer.valueSize > 1) - pfUsage(*((uint16_t*)varBuffer)); - else - pfUsage(data); - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - rptSize = data; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): - rptCount = data; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): - rptId = data; - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): - useMin = data; - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): - useMax = data; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): - SetUsagePage(data); - break; - case (TYPE_MAIN | TAG_MAIN_OUTPUT): - case (TYPE_MAIN | TAG_MAIN_FEATURE): - rptSize = 0; - rptCount = 0; - useMin = 0; - useMax = 0; - break; - case (TYPE_MAIN | TAG_MAIN_INPUT): - OnInputItem(data); - - totalSize += (uint16_t)rptSize * (uint16_t)rptCount; - - rptSize = 0; - rptCount = 0; - useMin = 0; - useMax = 0; - break; - } // switch (**pp & (TYPE_MASK | TAG_MASK)) - } - } // switch (itemParseState) - itemParseState = 0; - return enErrorSuccess; -} - -void ReportDescParser2::OnInputItem(uint8_t itm) -{ - uint8_t byte_offset = (totalSize >> 3); // calculate offset to the next unhandled byte i = (int)(totalCount / 8); - uint32_t tmp = (byte_offset << 3); - uint8_t bit_offset = totalSize - tmp; // number of bits in the current byte already handled - uint8_t *p = pBuf + byte_offset; // current byte pointer - - if (bit_offset) - *p >>= bit_offset; - - uint8_t usage = useMin; - - bool print_usemin_usemax = ( (useMin < useMax) && ((itm & 3) == 2) && pfUsage) ? true : false; - - uint8_t bits_of_byte = 8; - - // for each field in field array defined by rptCount - for (uint8_t field=0; field bits_of_byte) ? bits_of_byte : bits_left; - - result.dwResult <<= bits_to_copy; // Result buffer is shifted by the number of bits to be copied into it - - uint8_t val = *p; - - val >>= (8 - bits_of_byte); // Shift by the number of bits already processed - - mask = 0; - - for (uint8_t j=bits_to_copy; j; j--) - { - mask <<= 1; - mask |= 1; - } - - result.bResult[0] = (result.bResult[0] | (val & mask)); - - bits_of_byte -= bits_to_copy; - - if (bits_of_byte < 1) - { - bits_of_byte = 8; - p ++; - } - } - PrintByteValue(result.dwResult); - } - Serial.println(""); -} - -void UniversalReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) -{ - ReportDescParser2 prs(len, buf); - - uint8_t ret = hid->GetReportDescr(0, &prs); - - if (ret) - ErrorMessage(PSTR("GetReportDescr-2"), ret); +#include "hidescriptorparser.h" + +const char * const ReportDescParserBase::usagePageTitles0[] PROGMEM = { + pstrUsagePageGenericDesktopControls, + pstrUsagePageSimulationControls, + pstrUsagePageVRControls, + pstrUsagePageSportControls, + pstrUsagePageGameControls, + pstrUsagePageGenericDeviceControls, + pstrUsagePageKeyboardKeypad, + pstrUsagePageLEDs, + pstrUsagePageButton, + pstrUsagePageOrdinal, + pstrUsagePageTelephone, + pstrUsagePageConsumer, + pstrUsagePageDigitizer, + pstrUsagePagePID, + pstrUsagePageUnicode +}; + +const char * const ReportDescParserBase::usagePageTitles1[] PROGMEM = { + pstrUsagePageBarCodeScanner, + pstrUsagePageScale, + pstrUsagePageMSRDevices, + pstrUsagePagePointOfSale, + pstrUsagePageCameraControl, + pstrUsagePageArcade +}; +const char * const ReportDescParserBase::genDesktopTitles0[] PROGMEM = { + pstrUsagePointer, + pstrUsageMouse, + pstrUsageJoystick, + pstrUsageGamePad, + pstrUsageKeyboard, + pstrUsageKeypad, + pstrUsageMultiAxisController, + pstrUsageTabletPCSystemControls + +}; +const char * const ReportDescParserBase::genDesktopTitles1[] PROGMEM = { + pstrUsageX, + pstrUsageY, + pstrUsageZ, + pstrUsageRx, + pstrUsageRy, + pstrUsageRz, + pstrUsageSlider, + pstrUsageDial, + pstrUsageWheel, + pstrUsageHatSwitch, + pstrUsageCountedBuffer, + pstrUsageByteCount, + pstrUsageMotionWakeup, + pstrUsageStart, + pstrUsageSelect, + pstrUsagePageReserved, + pstrUsageVx, + pstrUsageVy, + pstrUsageVz, + pstrUsageVbrx, + pstrUsageVbry, + pstrUsageVbrz, + pstrUsageVno, + pstrUsageFeatureNotification, + pstrUsageResolutionMultiplier +}; +const char * const ReportDescParserBase::genDesktopTitles2[] PROGMEM = { + pstrUsageSystemControl, + pstrUsageSystemPowerDown, + pstrUsageSystemSleep, + pstrUsageSystemWakeup, + pstrUsageSystemContextMenu, + pstrUsageSystemMainMenu, + pstrUsageSystemAppMenu, + pstrUsageSystemMenuHelp, + pstrUsageSystemMenuExit, + pstrUsageSystemMenuSelect, + pstrUsageSystemMenuRight, + pstrUsageSystemMenuLeft, + pstrUsageSystemMenuUp, + pstrUsageSystemMenuDown, + pstrUsageSystemColdRestart, + pstrUsageSystemWarmRestart, + pstrUsageDPadUp, + pstrUsageDPadDown, + pstrUsageDPadRight, + pstrUsageDPadLeft +}; +const char * const ReportDescParserBase::genDesktopTitles3[] PROGMEM = { + pstrUsageSystemDock, + pstrUsageSystemUndock, + pstrUsageSystemSetup, + pstrUsageSystemBreak, + pstrUsageSystemDebuggerBreak, + pstrUsageApplicationBreak, + pstrUsageApplicationDebuggerBreak, + pstrUsageSystemSpeakerMute, + pstrUsageSystemHibernate +}; +const char * const ReportDescParserBase::genDesktopTitles4[] PROGMEM = { + pstrUsageSystemDisplayInvert, + pstrUsageSystemDisplayInternal, + pstrUsageSystemDisplayExternal, + pstrUsageSystemDisplayBoth, + pstrUsageSystemDisplayDual, + pstrUsageSystemDisplayToggleIntExt, + pstrUsageSystemDisplaySwapPriSec, + pstrUsageSystemDisplayLCDAutoscale +}; +const char * const ReportDescParserBase::simuTitles0[] PROGMEM = { + pstrUsageFlightSimulationDevice, + pstrUsageAutomobileSimulationDevice, + pstrUsageTankSimulationDevice, + pstrUsageSpaceshipSimulationDevice, + pstrUsageSubmarineSimulationDevice, + pstrUsageSailingSimulationDevice, + pstrUsageMotocicleSimulationDevice, + pstrUsageSportsSimulationDevice, + pstrUsageAirplaneSimulationDevice, + pstrUsageHelicopterSimulationDevice, + pstrUsageMagicCarpetSimulationDevice, + pstrUsageBicycleSimulationDevice +}; +const char * const ReportDescParserBase::simuTitles1[] PROGMEM = { + pstrUsageFlightControlStick, + pstrUsageFlightStick, + pstrUsageCyclicControl, + pstrUsageCyclicTrim, + pstrUsageFlightYoke, + pstrUsageTrackControl +}; +const char * const ReportDescParserBase::simuTitles2[] PROGMEM = { + pstrUsageAileron, + pstrUsageAileronTrim, + pstrUsageAntiTorqueControl, + pstrUsageAutopilotEnable, + pstrUsageChaffRelease, + pstrUsageCollectiveControl, + pstrUsageDiveBrake, + pstrUsageElectronicCountermeasures, + pstrUsageElevator, + pstrUsageElevatorTrim, + pstrUsageRudder, + pstrUsageThrottle, + pstrUsageFlightCommunications, + pstrUsageFlareRelease, + pstrUsageLandingGear, + pstrUsageToeBrake, + pstrUsageTrigger, + pstrUsageWeaponsArm, + pstrUsageWeaponsSelect, + pstrUsageWingFlaps, + pstrUsageAccelerator, + pstrUsageBrake, + pstrUsageClutch, + pstrUsageShifter, + pstrUsageSteering, + pstrUsageTurretDirection, + pstrUsageBarrelElevation, + pstrUsageDivePlane, + pstrUsageBallast, + pstrUsageBicycleCrank, + pstrUsageHandleBars, + pstrUsageFrontBrake, + pstrUsageRearBrake +}; +const char * const ReportDescParserBase::vrTitles0[] PROGMEM = { + pstrUsageBelt, + pstrUsageBodySuit, + pstrUsageFlexor, + pstrUsageGlove, + pstrUsageHeadTracker, + pstrUsageHeadMountedDisplay, + pstrUsageHandTracker, + pstrUsageOculometer, + pstrUsageVest, + pstrUsageAnimatronicDevice +}; +const char * const ReportDescParserBase::vrTitles1[] PROGMEM = { + pstrUsageStereoEnable, + pstrUsageDisplayEnable +}; +const char * const ReportDescParserBase::sportsCtrlTitles0[] PROGMEM = { + pstrUsageBaseballBat, + pstrUsageGolfClub, + pstrUsageRowingMachine, + pstrUsageTreadmill +}; +const char * const ReportDescParserBase::sportsCtrlTitles1[] PROGMEM = { + pstrUsageOar, + pstrUsageSlope, + pstrUsageRate, + pstrUsageStickSpeed, + pstrUsageStickFaceAngle, + pstrUsageStickHeelToe, + pstrUsageStickFollowThough, + pstrUsageStickTempo, + pstrUsageStickType, + pstrUsageStickHeight +}; +const char * const ReportDescParserBase::sportsCtrlTitles2[] PROGMEM = { + pstrUsagePutter, + pstrUsage1Iron, + pstrUsage2Iron, + pstrUsage3Iron, + pstrUsage4Iron, + pstrUsage5Iron, + pstrUsage6Iron, + pstrUsage7Iron, + pstrUsage8Iron, + pstrUsage9Iron, + pstrUsage10Iron, + pstrUsage11Iron, + pstrUsageSandWedge, + pstrUsageLoftWedge, + pstrUsagePowerWedge, + pstrUsage1Wood, + pstrUsage3Wood, + pstrUsage5Wood, + pstrUsage7Wood, + pstrUsage9Wood +}; +const char * const ReportDescParserBase::gameTitles0[] PROGMEM = { + pstrUsage3DGameController, + pstrUsagePinballDevice, + pstrUsageGunDevice +}; +const char * const ReportDescParserBase::gameTitles1[] PROGMEM = { + pstrUsagePointOfView, + pstrUsageTurnRightLeft, + pstrUsagePitchForwardBackward, + pstrUsageRollRightLeft, + pstrUsageMoveRightLeft, + pstrUsageMoveForwardBackward, + pstrUsageMoveUpDown, + pstrUsageLeanRightLeft, + pstrUsageLeanForwardBackward, + pstrUsageHeightOfPOV, + pstrUsageFlipper, + pstrUsageSecondaryFlipper, + pstrUsageBump, + pstrUsageNewGame, + pstrUsageShootBall, + pstrUsagePlayer, + pstrUsageGunBolt, + pstrUsageGunClip, + pstrUsageGunSelector, + pstrUsageGunSingleShot, + pstrUsageGunBurst, + pstrUsageGunAutomatic, + pstrUsageGunSafety, + pstrUsageGamepadFireJump, + pstrUsageGamepadTrigger +}; +const char * const ReportDescParserBase::genDevCtrlTitles[] PROGMEM = { + pstrUsageBatteryStrength, + pstrUsageWirelessChannel, + pstrUsageWirelessID, + pstrUsageDiscoverWirelessControl, + pstrUsageSecurityCodeCharEntered, + pstrUsageSecurityCodeCharErased, + pstrUsageSecurityCodeCleared +}; +const char * const ReportDescParserBase::ledTitles[] PROGMEM = { + pstrUsageNumLock, + pstrUsageCapsLock, + pstrUsageScrollLock, + pstrUsageCompose, + pstrUsageKana, + pstrUsagePower, + pstrUsageShift, + pstrUsageDoNotDisturb, + pstrUsageMute, + pstrUsageToneEnable, + pstrUsageHighCutFilter, + pstrUsageLowCutFilter, + pstrUsageEqualizerEnable, + pstrUsageSoundFieldOn, + pstrUsageSurroundOn, + pstrUsageRepeat, + pstrUsageStereo, + pstrUsageSamplingRateDetect, + pstrUsageSpinning, + pstrUsageCAV, + pstrUsageCLV, + pstrUsageRecordingFormatDetect, + pstrUsageOffHook, + pstrUsageRing, + pstrUsageMessageWaiting, + pstrUsageDataMode, + pstrUsageBatteryOperation, + pstrUsageBatteryOK, + pstrUsageBatteryLow, + pstrUsageSpeaker, + pstrUsageHeadSet, + pstrUsageHold, + pstrUsageMicrophone, + pstrUsageCoverage, + pstrUsageNightMode, + pstrUsageSendCalls, + pstrUsageCallPickup, + pstrUsageConference, + pstrUsageStandBy, + pstrUsageCameraOn, + pstrUsageCameraOff, + pstrUsageOnLine, + pstrUsageOffLine, + pstrUsageBusy, + pstrUsageReady, + pstrUsagePaperOut, + pstrUsagePaperJam, + pstrUsageRemote, + pstrUsageForward, + pstrUsageReverse, + pstrUsageStop, + pstrUsageRewind, + pstrUsageFastForward, + pstrUsagePlay, + pstrUsagePause, + pstrUsageRecord, + pstrUsageError, + pstrUsageSelectedIndicator, + pstrUsageInUseIndicator, + pstrUsageMultiModeIndicator, + pstrUsageIndicatorOn, + pstrUsageIndicatorFlash, + pstrUsageIndicatorSlowBlink, + pstrUsageIndicatorFastBlink, + pstrUsageIndicatorOff, + pstrUsageFlashOnTime, + pstrUsageSlowBlinkOnTime, + pstrUsageSlowBlinkOffTime, + pstrUsageFastBlinkOnTime, + pstrUsageFastBlinkOffTime, + pstrUsageIndicatorColor, + pstrUsageIndicatorRed, + pstrUsageIndicatorGreen, + pstrUsageIndicatorAmber, + pstrUsageGenericIndicator, + pstrUsageSystemSuspend, + pstrUsageExternalPowerConnected +}; +const char * const ReportDescParserBase::telTitles0 [] PROGMEM = { + pstrUsagePhone, + pstrUsageAnsweringMachine, + pstrUsageMessageControls, + pstrUsageHandset, + pstrUsageHeadset, + pstrUsageTelephonyKeyPad, + pstrUsageProgrammableButton +}; +const char * const ReportDescParserBase::telTitles1 [] PROGMEM = { + pstrUsageHookSwitch, + pstrUsageFlash, + pstrUsageFeature, + pstrUsageHold, + pstrUsageRedial, + pstrUsageTransfer, + pstrUsageDrop, + pstrUsagePark, + pstrUsageForwardCalls, + pstrUsageAlternateFunction, + pstrUsageLine, + pstrUsageSpeakerPhone, + pstrUsageConference, + pstrUsageRingEnable, + pstrUsageRingSelect, + pstrUsagePhoneMute, + pstrUsageCallerID, + pstrUsageSend +}; +const char * const ReportDescParserBase::telTitles2 [] PROGMEM = { + pstrUsageSpeedDial, + pstrUsageStoreNumber, + pstrUsageRecallNumber, + pstrUsagePhoneDirectory +}; +const char * const ReportDescParserBase::telTitles3 [] PROGMEM = { + pstrUsageVoiceMail, + pstrUsageScreenCalls, + pstrUsageDoNotDisturb, + pstrUsageMessage, + pstrUsageAnswerOnOff +}; +const char * const ReportDescParserBase::telTitles4 [] PROGMEM = { + pstrUsageInsideDialTone, + pstrUsageOutsideDialTone, + pstrUsageInsideRingTone, + pstrUsageOutsideRingTone, + pstrUsagePriorityRingTone, + pstrUsageInsideRingback, + pstrUsagePriorityRingback, + pstrUsageLineBusyTone, + pstrUsageReorderTone, + pstrUsageCallWaitingTone, + pstrUsageConfirmationTone1, + pstrUsageConfirmationTone2, + pstrUsageTonesOff, + pstrUsageOutsideRingback, + pstrUsageRinger +}; +const char * const ReportDescParserBase::telTitles5 [] PROGMEM = { + pstrUsagePhoneKey0, + pstrUsagePhoneKey1, + pstrUsagePhoneKey2, + pstrUsagePhoneKey3, + pstrUsagePhoneKey4, + pstrUsagePhoneKey5, + pstrUsagePhoneKey6, + pstrUsagePhoneKey7, + pstrUsagePhoneKey8, + pstrUsagePhoneKey9, + pstrUsagePhoneKeyStar, + pstrUsagePhoneKeyPound, + pstrUsagePhoneKeyA, + pstrUsagePhoneKeyB, + pstrUsagePhoneKeyC, + pstrUsagePhoneKeyD +}; +const char * const ReportDescParserBase::consTitles0[] PROGMEM = { + pstrUsageConsumerControl, + pstrUsageNumericKeyPad, + pstrUsageProgrammableButton, + pstrUsageMicrophone, + pstrUsageHeadphone, + pstrUsageGraphicEqualizer +}; +const char * const ReportDescParserBase::consTitles1[] PROGMEM = { + pstrUsagePlus10, + pstrUsagePlus100, + pstrUsageAMPM +}; +const char * const ReportDescParserBase::consTitles2[] PROGMEM = { + pstrUsagePower, + pstrUsageReset, + pstrUsageSleep, + pstrUsageSleepAfter, + pstrUsageSleepMode, + pstrUsageIllumination, + pstrUsageFunctionButtons + +}; +const char * const ReportDescParserBase::consTitles3[] PROGMEM = { + pstrUsageMenu, + pstrUsageMenuPick, + pstrUsageMenuUp, + pstrUsageMenuDown, + pstrUsageMenuLeft, + pstrUsageMenuRight, + pstrUsageMenuEscape, + pstrUsageMenuValueIncrease, + pstrUsageMenuValueDecrease +}; +const char * const ReportDescParserBase::consTitles4[] PROGMEM = { + pstrUsageDataOnScreen, + pstrUsageClosedCaption, + pstrUsageClosedCaptionSelect, + pstrUsageVCRTV, + pstrUsageBroadcastMode, + pstrUsageSnapshot, + pstrUsageStill +}; +const char * const ReportDescParserBase::consTitles5[] PROGMEM = { + pstrUsageSelection, + pstrUsageAssignSelection, + pstrUsageModeStep, + pstrUsageRecallLast, + pstrUsageEnterChannel, + pstrUsageOrderMovie, + pstrUsageChannel, + pstrUsageMediaSelection, + pstrUsageMediaSelectComputer, + pstrUsageMediaSelectTV, + pstrUsageMediaSelectWWW, + pstrUsageMediaSelectDVD, + pstrUsageMediaSelectTelephone, + pstrUsageMediaSelectProgramGuide, + pstrUsageMediaSelectVideoPhone, + pstrUsageMediaSelectGames, + pstrUsageMediaSelectMessages, + pstrUsageMediaSelectCD, + pstrUsageMediaSelectVCR, + pstrUsageMediaSelectTuner, + pstrUsageQuit, + pstrUsageHelp, + pstrUsageMediaSelectTape, + pstrUsageMediaSelectCable, + pstrUsageMediaSelectSatellite, + pstrUsageMediaSelectSecurity, + pstrUsageMediaSelectHome, + pstrUsageMediaSelectCall, + pstrUsageChannelIncrement, + pstrUsageChannelDecrement, + pstrUsageMediaSelectSAP, + pstrUsagePageReserved, + pstrUsageVCRPlus, + pstrUsageOnce, + pstrUsageDaily, + pstrUsageWeekly, + pstrUsageMonthly +}; +const char * const ReportDescParserBase::consTitles6[] PROGMEM = { + pstrUsagePlay, + pstrUsagePause, + pstrUsageRecord, + pstrUsageFastForward, + pstrUsageRewind, + pstrUsageScanNextTrack, + pstrUsageScanPreviousTrack, + pstrUsageStop, + pstrUsageEject, + pstrUsageRandomPlay, + pstrUsageSelectDisk, + pstrUsageEnterDisk, + pstrUsageRepeat, + pstrUsageTracking, + pstrUsageTrackNormal, + pstrUsageSlowTracking, + pstrUsageFrameForward, + pstrUsageFrameBackwards, + pstrUsageMark, + pstrUsageClearMark, + pstrUsageRepeatFromMark, + pstrUsageReturnToMark, + pstrUsageSearchMarkForward, + pstrUsageSearchMarkBackwards, + pstrUsageCounterReset, + pstrUsageShowCounter, + pstrUsageTrackingIncrement, + pstrUsageTrackingDecrement, + pstrUsageStopEject, + pstrUsagePlayPause, + pstrUsagePlaySkip +}; +const char * const ReportDescParserBase::consTitles7[] PROGMEM = { + pstrUsageVolume, + pstrUsageBalance, + pstrUsageMute, + pstrUsageBass, + pstrUsageTreble, + pstrUsageBassBoost, + pstrUsageSurroundMode, + pstrUsageLoudness, + pstrUsageMPX, + pstrUsageVolumeIncrement, + pstrUsageVolumeDecrement +}; +const char * const ReportDescParserBase::consTitles8[] PROGMEM = { + pstrUsageSpeedSelect, + pstrUsagePlaybackSpeed, + pstrUsageStandardPlay, + pstrUsageLongPlay, + pstrUsageExtendedPlay, + pstrUsageSlow +}; +const char * const ReportDescParserBase::consTitles9[] PROGMEM = { + pstrUsageFanEnable, + pstrUsageFanSpeed, + pstrUsageLightEnable, + pstrUsageLightIlluminationLevel, + pstrUsageClimateControlEnable, + pstrUsageRoomTemperature, + pstrUsageSecurityEnable, + pstrUsageFireAlarm, + pstrUsagePoliceAlarm, + pstrUsageProximity, + pstrUsageMotion, + pstrUsageDuresAlarm, + pstrUsageHoldupAlarm, + pstrUsageMedicalAlarm +}; +const char * const ReportDescParserBase::consTitlesA[] PROGMEM = { + pstrUsageBalanceRight, + pstrUsageBalanceLeft, + pstrUsageBassIncrement, + pstrUsageBassDecrement, + pstrUsageTrebleIncrement, + pstrUsageTrebleDecrement +}; +const char * const ReportDescParserBase::consTitlesB[] PROGMEM = { + pstrUsageSpeakerSystem, + pstrUsageChannelLeft, + pstrUsageChannelRight, + pstrUsageChannelCenter, + pstrUsageChannelFront, + pstrUsageChannelCenterFront, + pstrUsageChannelSide, + pstrUsageChannelSurround, + pstrUsageChannelLowFreqEnhancement, + pstrUsageChannelTop, + pstrUsageChannelUnknown +}; +const char * const ReportDescParserBase::consTitlesC[] PROGMEM = { + pstrUsageSubChannel, + pstrUsageSubChannelIncrement, + pstrUsageSubChannelDecrement, + pstrUsageAlternateAudioIncrement, + pstrUsageAlternateAudioDecrement +}; +const char * const ReportDescParserBase::consTitlesD[] PROGMEM = { + pstrUsageApplicationLaunchButtons, + pstrUsageALLaunchButtonConfigTool, + pstrUsageALProgrammableButton, + pstrUsageALConsumerControlConfig, + pstrUsageALWordProcessor, + pstrUsageALTextEditor, + pstrUsageALSpreadsheet, + pstrUsageALGraphicsEditor, + pstrUsageALPresentationApp, + pstrUsageALDatabaseApp, + pstrUsageALEmailReader, + pstrUsageALNewsreader, + pstrUsageALVoicemail, + pstrUsageALContactsAddressBook, + pstrUsageALCalendarSchedule, + pstrUsageALTaskProjectManager, + pstrUsageALLogJournalTimecard, + pstrUsageALCheckbookFinance, + pstrUsageALCalculator, + pstrUsageALAVCapturePlayback, + pstrUsageALLocalMachineBrowser, + pstrUsageALLANWANBrow, + pstrUsageALInternetBrowser, + pstrUsageALRemoteNetISPConnect, + pstrUsageALNetworkConference, + pstrUsageALNetworkChat, + pstrUsageALTelephonyDialer, + pstrUsageALLogon, + pstrUsageALLogoff, + pstrUsageALLogonLogoff, + pstrUsageALTermLockScrSav, + pstrUsageALControlPannel, + pstrUsageALCommandLineProcessorRun, + pstrUsageALProcessTaskManager, + pstrUsageALSelectTaskApplication, + pstrUsageALNextTaskApplication, + pstrUsageALPreviousTaskApplication, + pstrUsageALPreemptiveHaltTaskApp, + pstrUsageALIntegratedHelpCenter, + pstrUsageALDocuments, + pstrUsageALThesaurus, + pstrUsageALDictionary, + pstrUsageALDesktop, + pstrUsageALSpellCheck, + pstrUsageALGrammarCheck, + pstrUsageALWirelessStatus, + pstrUsageALKeyboardLayout, + pstrUsageALVirusProtection, + pstrUsageALEncryption, + pstrUsageALScreenSaver, + pstrUsageALAlarms, + pstrUsageALClock, + pstrUsageALFileBrowser, + pstrUsageALPowerStatus, + pstrUsageALImageBrowser, + pstrUsageALAudioBrowser, + pstrUsageALMovieBrowser, + pstrUsageALDigitalRightsManager, + pstrUsageALDigitalWallet, + pstrUsagePageReserved, + pstrUsageALInstantMessaging, + pstrUsageALOEMFeaturesBrowser, + pstrUsageALOEMHelp, + pstrUsageALOnlineCommunity, + pstrUsageALEntertainmentContentBrow, + pstrUsageALOnlineShoppingBrowser, + pstrUsageALSmartCardInfoHelp, + pstrUsageALMarketMonitorFinBrowser, + pstrUsageALCustomCorpNewsBrowser, + pstrUsageALOnlineActivityBrowser, + pstrUsageALResearchSearchBrowser, + pstrUsageALAudioPlayer +}; +const char * const ReportDescParserBase::consTitlesE[] PROGMEM = { + pstrUsageGenericGUIAppControls, + pstrUsageACNew, + pstrUsageACOpen, + pstrUsageACClose, + pstrUsageACExit, + pstrUsageACMaximize, + pstrUsageACMinimize, + pstrUsageACSave, + pstrUsageACPrint, + pstrUsageACProperties, + pstrUsageACUndo, + pstrUsageACCopy, + pstrUsageACCut, + pstrUsageACPaste, + pstrUsageACSelectAll, + pstrUsageACFind, + pstrUsageACFindAndReplace, + pstrUsageACSearch, + pstrUsageACGoto, + pstrUsageACHome, + pstrUsageACBack, + pstrUsageACForward, + pstrUsageACStop, + pstrUsageACRefresh, + pstrUsageACPreviousLink, + pstrUsageACNextLink, + pstrUsageACBookmarks, + pstrUsageACHistory, + pstrUsageACSubscriptions, + pstrUsageACZoomIn, + pstrUsageACZoomOut, + pstrUsageACZoom, + pstrUsageACFullScreenView, + pstrUsageACNormalView, + pstrUsageACViewToggle, + pstrUsageACScrollUp, + pstrUsageACScrollDown, + pstrUsageACScroll, + pstrUsageACPanLeft, + pstrUsageACPanRight, + pstrUsageACPan, + pstrUsageACNewWindow, + pstrUsageACTileHoriz, + pstrUsageACTileVert, + pstrUsageACFormat, + pstrUsageACEdit, + pstrUsageACBold, + pstrUsageACItalics, + pstrUsageACUnderline, + pstrUsageACStrikethrough, + pstrUsageACSubscript, + pstrUsageACSuperscript, + pstrUsageACAllCaps, + pstrUsageACRotate, + pstrUsageACResize, + pstrUsageACFlipHorizontal, + pstrUsageACFlipVertical, + pstrUsageACMirrorHorizontal, + pstrUsageACMirrorVertical, + pstrUsageACFontSelect, + pstrUsageACFontColor, + pstrUsageACFontSize, + pstrUsageACJustifyLeft, + pstrUsageACJustifyCenterH, + pstrUsageACJustifyRight, + pstrUsageACJustifyBlockH, + pstrUsageACJustifyTop, + pstrUsageACJustifyCenterV, + pstrUsageACJustifyBottom, + pstrUsageACJustifyBlockV, + pstrUsageACIndentDecrease, + pstrUsageACIndentIncrease, + pstrUsageACNumberedList, + pstrUsageACRestartNumbering, + pstrUsageACBulletedList, + pstrUsageACPromote, + pstrUsageACDemote, + pstrUsageACYes, + pstrUsageACNo, + pstrUsageACCancel, + pstrUsageACCatalog, + pstrUsageACBuyChkout, + pstrUsageACAddToCart, + pstrUsageACExpand, + pstrUsageACExpandAll, + pstrUsageACCollapse, + pstrUsageACCollapseAll, + pstrUsageACPrintPreview, + pstrUsageACPasteSpecial, + pstrUsageACInsertMode, + pstrUsageACDelete, + pstrUsageACLock, + pstrUsageACUnlock, + pstrUsageACProtect, + pstrUsageACUnprotect, + pstrUsageACAttachComment, + pstrUsageACDeleteComment, + pstrUsageACViewComment, + pstrUsageACSelectWord, + pstrUsageACSelectSentence, + pstrUsageACSelectParagraph, + pstrUsageACSelectColumn, + pstrUsageACSelectRow, + pstrUsageACSelectTable, + pstrUsageACSelectObject, + pstrUsageACRedoRepeat, + pstrUsageACSort, + pstrUsageACSortAscending, + pstrUsageACSortDescending, + pstrUsageACFilter, + pstrUsageACSetClock, + pstrUsageACViewClock, + pstrUsageACSelectTimeZone, + pstrUsageACEditTimeZone, + pstrUsageACSetAlarm, + pstrUsageACClearAlarm, + pstrUsageACSnoozeAlarm, + pstrUsageACResetAlarm, + pstrUsageACSyncronize, + pstrUsageACSendReceive, + pstrUsageACSendTo, + pstrUsageACReply, + pstrUsageACReplyAll, + pstrUsageACForwardMessage, + pstrUsageACSend, + pstrUsageACAttachFile, + pstrUsageACUpload, + pstrUsageACDownload, + pstrUsageACSetBorders, + pstrUsageACInsertRow, + pstrUsageACInsertColumn, + pstrUsageACInsertFile, + pstrUsageACInsertPicture, + pstrUsageACInsertObject, + pstrUsageACInsertSymbol, + pstrUsageACSaveAndClose, + pstrUsageACRename, + pstrUsageACMerge, + pstrUsageACSplit, + pstrUsageACDistributeHorizontaly, + pstrUsageACDistributeVerticaly +}; +const char * const ReportDescParserBase::digitTitles0[] PROGMEM = { + pstrUsageDigitizer, + pstrUsagePen, + pstrUsageLightPen, + pstrUsageTouchScreen, + pstrUsageTouchPad, + pstrUsageWhiteBoard, + pstrUsageCoordinateMeasuringMachine, + pstrUsage3DDigitizer, + pstrUsageStereoPlotter, + pstrUsageArticulatedArm, + pstrUsageArmature, + pstrUsageMultiplePointDigitizer, + pstrUsageFreeSpaceWand +}; +const char * const ReportDescParserBase::digitTitles1[] PROGMEM = { + pstrUsageStylus, + pstrUsagePuck, + pstrUsageFinger + +}; +const char * const ReportDescParserBase::digitTitles2[] PROGMEM = { + pstrUsageTipPressure, + pstrUsageBarrelPressure, + pstrUsageInRange, + pstrUsageTouch, + pstrUsageUntouch, + pstrUsageTap, + pstrUsageQuality, + pstrUsageDataValid, + pstrUsageTransducerIndex, + pstrUsageTabletFunctionKeys, + pstrUsageProgramChangeKeys, + pstrUsageBatteryStrength, + pstrUsageInvert, + pstrUsageXTilt, + pstrUsageYTilt, + pstrUsageAzimuth, + pstrUsageAltitude, + pstrUsageTwist, + pstrUsageTipSwitch, + pstrUsageSecondaryTipSwitch, + pstrUsageBarrelSwitch, + pstrUsageEraser, + pstrUsageTabletPick +}; +const char * const ReportDescParserBase::aplphanumTitles0[] PROGMEM = { + pstrUsageAlphanumericDisplay, + pstrUsageBitmappedDisplay +}; +const char * const ReportDescParserBase::aplphanumTitles1[] PROGMEM = { + pstrUsageDisplayAttributesReport, + pstrUsageASCIICharacterSet, + pstrUsageDataReadBack, + pstrUsageFontReadBack, + pstrUsageDisplayControlReport, + pstrUsageClearDisplay, + pstrUsageDisplayEnable, + pstrUsageScreenSaverDelay, + pstrUsageScreenSaverEnable, + pstrUsageVerticalScroll, + pstrUsageHorizontalScroll, + pstrUsageCharacterReport, + pstrUsageDisplayData, + pstrUsageDisplayStatus, + pstrUsageStatusNotReady, + pstrUsageStatusReady, + pstrUsageErrorNotALoadableCharacter, + pstrUsageErrorFotDataCanNotBeRead, + pstrUsageCursorPositionReport, + pstrUsageRow, + pstrUsageColumn, + pstrUsageRows, + pstrUsageColumns, + pstrUsageCursorPixelPosition, + pstrUsageCursorMode, + pstrUsageCursorEnable, + pstrUsageCursorBlink, + pstrUsageFontReport, + pstrUsageFontData, + pstrUsageCharacterWidth, + pstrUsageCharacterHeight, + pstrUsageCharacterSpacingHorizontal, + pstrUsageCharacterSpacingVertical, + pstrUsageUnicodeCharset, + pstrUsageFont7Segment, + pstrUsage7SegmentDirectMap, + pstrUsageFont14Segment, + pstrUsage14SegmentDirectMap, + pstrUsageDisplayBrightness, + pstrUsageDisplayContrast, + pstrUsageCharacterAttribute, + pstrUsageAttributeReadback, + pstrUsageAttributeData, + pstrUsageCharAttributeEnhance, + pstrUsageCharAttributeUnderline, + pstrUsageCharAttributeBlink +}; +const char * const ReportDescParserBase::aplphanumTitles2[] PROGMEM = { + pstrUsageBitmapSizeX, + pstrUsageBitmapSizeY, + pstrUsagePageReserved, + pstrUsageBitDepthFormat, + pstrUsageDisplayOrientation, + pstrUsagePaletteReport, + pstrUsagePaletteDataSize, + pstrUsagePaletteDataOffset, + pstrUsagePaletteData, + pstrUsageBlitReport, + pstrUsageBlitRectangleX1, + pstrUsageBlitRectangleY1, + pstrUsageBlitRectangleX2, + pstrUsageBlitRectangleY2, + pstrUsageBlitData, + pstrUsageSoftButton, + pstrUsageSoftButtonID, + pstrUsageSoftButtonSide, + pstrUsageSoftButtonOffset1, + pstrUsageSoftButtonOffset2, + pstrUsageSoftButtonReport +}; +const char * const ReportDescParserBase::medInstrTitles0[] PROGMEM = { + pstrUsageVCRAcquisition, + pstrUsageFreezeThaw, + pstrUsageClipStore, + pstrUsageUpdate, + pstrUsageNext, + pstrUsageSave, + pstrUsagePrint, + pstrUsageMicrophoneEnable +}; +const char * const ReportDescParserBase::medInstrTitles1[] PROGMEM = { + pstrUsageCine, + pstrUsageTransmitPower, + pstrUsageVolume, + pstrUsageFocus, + pstrUsageDepth +}; +const char * const ReportDescParserBase::medInstrTitles2[] PROGMEM = { + pstrUsageSoftStepPrimary, + pstrUsageSoftStepSecondary +}; +const char * const ReportDescParserBase::medInstrTitles3[] PROGMEM = { + pstrUsageZoomSelect, + pstrUsageZoomAdjust, + pstrUsageSpectralDopplerModeSelect, + pstrUsageSpectralDopplerModeAdjust, + pstrUsageColorDopplerModeSelect, + pstrUsageColorDopplerModeAdjust, + pstrUsageMotionModeSelect, + pstrUsageMotionModeAdjust, + pstrUsage2DModeSelect, + pstrUsage2DModeAdjust +}; +const char * const ReportDescParserBase::medInstrTitles4[] PROGMEM = { + pstrUsageSoftControlSelect, + pstrUsageSoftControlAdjust +}; + +void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) { + uint16_t cntdn = (uint16_t)len; + uint8_t *p = (uint8_t*)pbuf; + + + totalSize = 0; + + while (cntdn) { + //Serial.println(""); + //PrintHex(offset + len - cntdn); + //Serial.print(":"); + + ParseItem(&p, &cntdn); + + //if (ParseItem(&p, &cntdn)) + // return; + } + //USBTRACE2("Total:", totalSize); +} + +void ReportDescParserBase::PrintValue(uint8_t *p, uint8_t len) { + Notify(PSTR("("), 0x80); + for (; len; p++, len--) + PrintHex (*p, 0x80); + Notify(PSTR(")"), 0x80); +} + +void ReportDescParserBase::PrintByteValue(uint8_t data) { + Notify(PSTR("("), 0x80); + PrintHex (data, 0x80); + 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); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_POP): + Notify(PSTR("\r\nPop"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): + Notify(PSTR("\r\nUsage Page"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): + Notify(PSTR("\r\nLogical Min"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): + Notify(PSTR("\r\nLogical Max"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): + Notify(PSTR("\r\nPhysical Min"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): + Notify(PSTR("\r\nPhysical Max"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): + Notify(PSTR("\r\nUnit Exp"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): + Notify(PSTR("\r\nUnit"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + Notify(PSTR("\r\nReport Size"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + Notify(PSTR("\r\nReport Count"), 0x80); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): + Notify(PSTR("\r\nReport Id"), 0x80); + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGE): + Notify(PSTR("\r\nUsage"), 0x80); + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): + Notify(PSTR("\r\nUsage Min"), 0x80); + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): + Notify(PSTR("\r\nUsage Max"), 0x80); + break; + case (TYPE_MAIN | TAG_MAIN_COLLECTION): + Notify(PSTR("\r\nCollection"), 0x80); + break; + case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): + Notify(PSTR("\r\nEnd Collection"), 0x80); + break; + case (TYPE_MAIN | TAG_MAIN_INPUT): + Notify(PSTR("\r\nInput"), 0x80); + break; + case (TYPE_MAIN | TAG_MAIN_OUTPUT): + Notify(PSTR("\r\nOutput"), 0x80); + break; + case (TYPE_MAIN | TAG_MAIN_FEATURE): + Notify(PSTR("\r\nFeature"), 0x80); + break; + } // switch (**pp & (TYPE_MASK | TAG_MASK)) +} + +uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) { + //uint8_t ret = enErrorSuccess; + + switch (itemParseState) { + case 0: + if (**pp == HID_LONG_ITEM_PREFIX) + USBTRACE("\r\nLONG\r\n"); + else { + uint8_t size = ((**pp) & DATA_SIZE_MASK); + + itemPrefix = (**pp); + itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); + + PrintItemTitle(itemPrefix); + } + (*pp)++; + (*pcntdn)--; + itemSize--; + itemParseState = 1; + + if (!itemSize) + break; + + if (!pcntdn) + return enErrorIncomplete; + case 1: + //USBTRACE2("\r\niSz:",itemSize); + + theBuffer.valueSize = itemSize; + valParser.Initialize(&theBuffer); + itemParseState = 2; + case 2: + if (!valParser.Parse(pp, pcntdn)) + return enErrorIncomplete; + itemParseState = 3; + case 3: + { + uint8_t data = *((uint8_t*)varBuffer); + + switch (itemPrefix & (TYPE_MASK | TAG_MASK)) { + case (TYPE_LOCAL | TAG_LOCAL_USAGE): + if (pfUsage) { + if (theBuffer.valueSize > 1) + pfUsage(*((uint16_t*)varBuffer)); + else + pfUsage(data); + } + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + rptSize = data; + PrintByteValue(data); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + rptCount = data; + PrintByteValue(data); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): + case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): + case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): + case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): + case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): + PrintValue(varBuffer, theBuffer.valueSize); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): + case (TYPE_GLOBAL | TAG_GLOBAL_POP): + break; + case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): + SetUsagePage(data); + PrintUsagePage(data); + PrintByteValue(data); + break; + case (TYPE_MAIN | TAG_MAIN_COLLECTION): + case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): + switch (data) { + case 0x00: + Notify(PSTR(" Physical"), 0x80); + break; + case 0x01: + Notify(PSTR(" Application"), 0x80); + break; + case 0x02: + Notify(PSTR(" Logical"), 0x80); + break; + case 0x03: + Notify(PSTR(" Report"), 0x80); + break; + case 0x04: + Notify(PSTR(" Named Array"), 0x80); + break; + case 0x05: + Notify(PSTR(" Usage Switch"), 0x80); + break; + case 0x06: + Notify(PSTR(" Usage Modifier"), 0x80); + break; + default: + Notify(PSTR(" Vendor Defined("), 0x80); + PrintHex (data, 0x80); + Notify(PSTR(")"), 0x80); + } + break; + case (TYPE_MAIN | TAG_MAIN_INPUT): + case (TYPE_MAIN | TAG_MAIN_OUTPUT): + case (TYPE_MAIN | TAG_MAIN_FEATURE): + totalSize += (uint16_t)rptSize * (uint16_t)rptCount; + rptSize = 0; + rptCount = 0; + Notify(PSTR("("), 0x80); + PrintBin (data, 0x80); + Notify(PSTR(")"), 0x80); + break; + } // switch (**pp & (TYPE_MASK | TAG_MASK)) + } + } // switch (itemParseState) + itemParseState = 0; + return enErrorSuccess; +} + +ReportDescParserBase::UsagePageFunc ReportDescParserBase::usagePageFunctions[] /*PROGMEM*/ = { + &ReportDescParserBase::PrintGenericDesktopPageUsage, + &ReportDescParserBase::PrintSimulationControlsPageUsage, + &ReportDescParserBase::PrintVRControlsPageUsage, + &ReportDescParserBase::PrintSportsControlsPageUsage, + &ReportDescParserBase::PrintGameControlsPageUsage, + &ReportDescParserBase::PrintGenericDeviceControlsPageUsage, + NULL, // Keyboard/Keypad + &ReportDescParserBase::PrintLEDPageUsage, + &ReportDescParserBase::PrintButtonPageUsage, + &ReportDescParserBase::PrintOrdinalPageUsage, + &ReportDescParserBase::PrintTelephonyPageUsage, + &ReportDescParserBase::PrintConsumerPageUsage, + &ReportDescParserBase::PrintDigitizerPageUsage, + NULL, // Reserved + NULL, // PID + NULL // Unicode +}; + +void ReportDescParserBase::SetUsagePage(uint16_t page) { + pfUsage = NULL; + + if (page > 0x00 && page < 0x11) + pfUsage = /*(UsagePageFunc)pgm_read_word*/(usagePageFunctions[page - 1]); + //else if (page > 0x7f && page < 0x84) + // Notify(pstrUsagePageMonitor); + //else if (page > 0x83 && page < 0x8c) + // Notify(pstrUsagePagePower); + //else if (page > 0x8b && page < 0x92) + // Notify((char*)pgm_read_word(&usagePageTitles1[page - 0x8c])); + //else if (page > 0xfeff && page <= 0xffff) + // Notify(pstrUsagePageVendorDefined); + else + switch (page) { + case 0x14: + pfUsage = &ReportDescParserBase::PrintAlphanumDisplayPageUsage; + break; + case 0x40: + pfUsage = &ReportDescParserBase::PrintMedicalInstrumentPageUsage; + break; + } +} + +void ReportDescParserBase::PrintUsagePage(uint16_t page) { + Notify(pstrSpace, 0x80); + + if (page > 0x00 && page < 0x11) + Notify((char*)pgm_read_word(&usagePageTitles0[page - 1]), 0x80); + else if (page > 0x7f && page < 0x84) + Notify(pstrUsagePageMonitor, 0x80); + else if (page > 0x83 && page < 0x8c) + Notify(pstrUsagePagePower, 0x80); + else if (page > 0x8b && page < 0x92) + Notify((char*)pgm_read_word(&usagePageTitles1[page - 0x8c]), 0x80); + else if (page > 0xfeff && page <= 0xffff) + Notify(pstrUsagePageVendorDefined, 0x80); + else + switch (page) { + case 0x14: + Notify(pstrUsagePageAlphaNumericDisplay, 0x80); + break; + case 0x40: + Notify(pstrUsagePageMedicalInstruments, 0x80); + break; + default: + Notify(pstrUsagePageUndefined, 0x80); + } +} + +void ReportDescParserBase::PrintButtonPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + Notify(PSTR("Btn"), 0x80); + PrintHex (usage, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.print(usage, HEX); +} + +void ReportDescParserBase::PrintOrdinalPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + Notify(PSTR("Inst"), 0x80); + // Sorry, HEX for now... + PrintHex (usage, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.print(usage, DEC); +} + +void ReportDescParserBase::PrintGenericDesktopPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x0a) + Notify((char*)pgm_read_word(&genDesktopTitles0[usage - 1]), 0x80); + else if (usage > 0x2f && usage < 0x49) + Notify((char*)pgm_read_word(&genDesktopTitles1[usage - 0x30]), 0x80); + else if (usage > 0x7f && usage < 0x94) + Notify((char*)pgm_read_word(&genDesktopTitles2[usage - 0x80]), 0x80); + else if (usage > 0x9f && usage < 0xa9) + Notify((char*)pgm_read_word(&genDesktopTitles3[usage - 0xa0]), 0x80); + else if (usage > 0xaf && usage < 0xb8) + Notify((char*)pgm_read_word(&genDesktopTitles4[usage - 0xb0]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintSimulationControlsPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x0d) + Notify((char*)pgm_read_word(&simuTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x26) + Notify((char*)pgm_read_word(&simuTitles1[usage - 0x20]), 0x80); + else if (usage > 0xaf && usage < 0xd1) + Notify((char*)pgm_read_word(&simuTitles2[usage - 0xb0]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintVRControlsPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x0b) + Notify((char*)pgm_read_word(&vrTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x22) + Notify((char*)pgm_read_word(&vrTitles1[usage - 0x20]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintSportsControlsPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x05) + Notify((char*)pgm_read_word(&sportsCtrlTitles0[usage - 1]), 0x80); + else if (usage > 0x2f && usage < 0x3a) + Notify((char*)pgm_read_word(&sportsCtrlTitles1[usage - 0x30]), 0x80); + else if (usage > 0x4f && usage < 0x64) + Notify((char*)pgm_read_word(&sportsCtrlTitles2[usage - 0x50]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintGameControlsPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x04) + Notify((char*)pgm_read_word(&gameTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x3a) + Notify((char*)pgm_read_word(&gameTitles1[usage - 0x20]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintGenericDeviceControlsPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x1f && usage < 0x27) + Notify((char*)pgm_read_word(&genDevCtrlTitles[usage - 0x20]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintLEDPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x4e) + Notify((char*)pgm_read_word(&ledTitles[usage - 1]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintTelephonyPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x08) + Notify((char*)pgm_read_word(&telTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x32) + Notify((char*)pgm_read_word(&telTitles1[usage - 0x1f]), 0x80); + else if (usage > 0x4f && usage < 0x54) + Notify((char*)pgm_read_word(&telTitles2[usage - 0x4f]), 0x80); + else if (usage > 0x6f && usage < 0x75) + Notify((char*)pgm_read_word(&telTitles3[usage - 0x6f]), 0x80); + else if (usage > 0x8f && usage < 0x9f) + Notify((char*)pgm_read_word(&telTitles4[usage - 0x8f]), 0x80); + else if (usage > 0xaf && usage < 0xc0) + Notify((char*)pgm_read_word(&telTitles5[usage - 0xaf]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintConsumerPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x07) + Notify((char*)pgm_read_word(&consTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x23) + Notify((char*)pgm_read_word(&consTitles1[usage - 0x1f]), 0x80); + else if (usage > 0x2f && usage < 0x37) + Notify((char*)pgm_read_word(&consTitles2[usage - 0x2f]), 0x80); + else if (usage > 0x3f && usage < 0x49) + Notify((char*)pgm_read_word(&consTitles3[usage - 0x3f]), 0x80); + else if (usage > 0x5f && usage < 0x67) + Notify((char*)pgm_read_word(&consTitles4[usage - 0x5f]), 0x80); + else if (usage > 0x7f && usage < 0xa5) + Notify((char*)pgm_read_word(&consTitles5[usage - 0x7f]), 0x80); + else if (usage > 0xaf && usage < 0xcf) + Notify((char*)pgm_read_word(&consTitles6[usage - 0xaf]), 0x80); + else if (usage > 0xdf && usage < 0xeb) + Notify((char*)pgm_read_word(&consTitles7[usage - 0xdf]), 0x80); + else if (usage > 0xef && usage < 0xf6) + Notify((char*)pgm_read_word(&consTitles8[usage - 0xef]), 0x80); + else if (usage > 0xff && usage < 0x10e) + Notify((char*)pgm_read_word(&consTitles9[usage - 0xff]), 0x80); + else if (usage > 0x14f && usage < 0x156) + Notify((char*)pgm_read_word(&consTitlesA[usage - 0x14f]), 0x80); + else if (usage > 0x15f && usage < 0x16b) + Notify((char*)pgm_read_word(&consTitlesB[usage - 0x15f]), 0x80); + else if (usage > 0x16f && usage < 0x175) + Notify((char*)pgm_read_word(&consTitlesC[usage - 0x16f]), 0x80); + else if (usage > 0x17f && usage < 0x1c8) + Notify((char*)pgm_read_word(&consTitlesD[usage - 0x17f]), 0x80); + else if (usage > 0x1ff && usage < 0x29d) + Notify((char*)pgm_read_word(&consTitlesE[usage - 0x1ff]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintDigitizerPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x0e) + Notify((char*)pgm_read_word(&digitTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x23) + Notify((char*)pgm_read_word(&digitTitles1[usage - 0x1f]), 0x80); + else if (usage > 0x2f && usage < 0x47) + Notify((char*)pgm_read_word(&digitTitles2[usage - 0x2f]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintAlphanumDisplayPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage > 0x00 && usage < 0x03) + Notify((char*)pgm_read_word(&aplphanumTitles0[usage - 1]), 0x80); + else if (usage > 0x1f && usage < 0x4e) + Notify((char*)pgm_read_word(&aplphanumTitles1[usage - 0x1f]), 0x80); + else if (usage > 0x7f && usage < 0x96) + Notify((char*)pgm_read_word(&digitTitles2[usage - 0x80]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +void ReportDescParserBase::PrintMedicalInstrumentPageUsage(uint16_t usage) { + Notify(pstrSpace, 0x80); + + if (usage == 1) + Notify(pstrUsageMedicalUltrasound, 0x80); + else if (usage > 0x1f && usage < 0x28) + Notify((char*)pgm_read_word(&medInstrTitles0[usage - 0x1f]), 0x80); + else if (usage > 0x3f && usage < 0x45) + Notify((char*)pgm_read_word(&medInstrTitles1[usage - 0x40]), 0x80); + else if (usage > 0x5f && usage < 0x62) + Notify((char*)pgm_read_word(&medInstrTitles2[usage - 0x60]), 0x80); + else if (usage == 0x70) + Notify(pstrUsageDepthGainCompensation, 0x80); + else if (usage > 0x7f && usage < 0x8a) + Notify((char*)pgm_read_word(&medInstrTitles3[usage - 0x80]), 0x80); + else if (usage > 0x9f && usage < 0xa2) + Notify((char*)pgm_read_word(&medInstrTitles4[usage - 0xa0]), 0x80); + else + Notify(pstrUsagePageUndefined, 0x80); +} + +uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) { + //uint8_t ret = enErrorSuccess; + + switch (itemParseState) { + case 0: + if (**pp == HID_LONG_ITEM_PREFIX) + USBTRACE("\r\nLONG\r\n"); + else { + uint8_t size = ((**pp) & DATA_SIZE_MASK); + itemPrefix = (**pp); + itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); + } + (*pp)++; + (*pcntdn)--; + itemSize--; + itemParseState = 1; + + if (!itemSize) + break; + + if (!pcntdn) + return enErrorIncomplete; + case 1: + theBuffer.valueSize = itemSize; + valParser.Initialize(&theBuffer); + itemParseState = 2; + case 2: + if (!valParser.Parse(pp, pcntdn)) + return enErrorIncomplete; + itemParseState = 3; + case 3: + { + uint8_t data = *((uint8_t*)varBuffer); + + switch (itemPrefix & (TYPE_MASK | TAG_MASK)) { + case (TYPE_LOCAL | TAG_LOCAL_USAGE): + if (pfUsage) { + if (theBuffer.valueSize > 1) + pfUsage(*((uint16_t*)varBuffer)); + else + pfUsage(data); + } + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + rptSize = data; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + rptCount = data; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): + rptId = data; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): + useMin = data; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): + useMax = data; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): + SetUsagePage(data); + break; + case (TYPE_MAIN | TAG_MAIN_OUTPUT): + case (TYPE_MAIN | TAG_MAIN_FEATURE): + rptSize = 0; + rptCount = 0; + useMin = 0; + useMax = 0; + break; + case (TYPE_MAIN | TAG_MAIN_INPUT): + OnInputItem(data); + + totalSize += (uint16_t)rptSize * (uint16_t)rptCount; + + rptSize = 0; + rptCount = 0; + useMin = 0; + useMax = 0; + break; + } // switch (**pp & (TYPE_MASK | TAG_MASK)) + } + } // switch (itemParseState) + itemParseState = 0; + return enErrorSuccess; +} + +void ReportDescParser2::OnInputItem(uint8_t itm) { + uint8_t byte_offset = (totalSize >> 3); // calculate offset to the next unhandled byte i = (int)(totalCount / 8); + uint32_t tmp = (byte_offset << 3); + uint8_t bit_offset = totalSize - tmp; // number of bits in the current byte already handled + uint8_t *p = pBuf + byte_offset; // current byte pointer + + if (bit_offset) + *p >>= bit_offset; + + uint8_t usage = useMin; + + bool print_usemin_usemax = ((useMin < useMax) && ((itm & 3) == 2) && pfUsage) ? true : false; + + uint8_t bits_of_byte = 8; + + // for each field in field array defined by rptCount + for (uint8_t field = 0; field < rptCount; field++, usage++) { + + union { + uint8_t bResult[4]; + uint16_t wResult[2]; + uint32_t dwResult; + } result; + + result.dwResult = 0; + uint8_t mask = 0; + + if (print_usemin_usemax) + pfUsage(usage); + + // bits_left - number of bits in the field(array of fields, depending on Report Count) left to process + // bits_of_byte - number of bits in current byte left to process + // bits_to_copy - number of bits to copy to result buffer + + // for each bit in a field + for (uint8_t bits_left = rptSize, bits_to_copy = 0; bits_left; + bits_left -= bits_to_copy) { + bits_to_copy = (bits_left > bits_of_byte) ? bits_of_byte : bits_left; + + result.dwResult <<= bits_to_copy; // Result buffer is shifted by the number of bits to be copied into it + + uint8_t val = *p; + + val >>= (8 - bits_of_byte); // Shift by the number of bits already processed + + mask = 0; + + for (uint8_t j = bits_to_copy; j; j--) { + mask <<= 1; + mask |= 1; + } + + result.bResult[0] = (result.bResult[0] | (val & mask)); + + bits_of_byte -= bits_to_copy; + + if (bits_of_byte < 1) { + bits_of_byte = 8; + p++; + } + } + PrintByteValue(result.dwResult); + } + Notify(PSTR("\r\n"), 0x80); +} + +void UniversalReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + ReportDescParser2 prs(len, buf); + + uint8_t ret = hid->GetReportDescr(0, &prs); + + if (ret) + ErrorMessage (PSTR("GetReportDescr-2"), ret); } \ No newline at end of file diff --git a/hidescriptorparser.h b/hidescriptorparser.h index 119a5a66..1c4a1900 100644 --- a/hidescriptorparser.h +++ b/hidescriptorparser.h @@ -1,195 +1,191 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__HIDDESCRIPTORPARSER_H__) -#define __HIDDESCRIPTORPARSER_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.h" -#include "confdescparser.h" -#include "hid.h" - -class ReportDescParserBase : public USBReadParser -{ -public: - typedef void (*UsagePageFunc)(uint16_t usage); - - static void PrintGenericDesktopPageUsage(uint16_t usage); - static void PrintSimulationControlsPageUsage(uint16_t usage); - static void PrintVRControlsPageUsage(uint16_t usage); - static void PrintSportsControlsPageUsage(uint16_t usage); - static void PrintGameControlsPageUsage(uint16_t usage); - static void PrintGenericDeviceControlsPageUsage(uint16_t usage); - static void PrintLEDPageUsage(uint16_t usage); - static void PrintButtonPageUsage(uint16_t usage); - static void PrintOrdinalPageUsage(uint16_t usage); - static void PrintTelephonyPageUsage(uint16_t usage); - static void PrintConsumerPageUsage(uint16_t usage); - static void PrintDigitizerPageUsage(uint16_t usage); - static void PrintAlphanumDisplayPageUsage(uint16_t usage); - static void PrintMedicalInstrumentPageUsage(uint16_t usage); - - static void PrintValue(uint8_t *p, uint8_t len); - static void PrintByteValue(uint8_t data); - - static void PrintItemTitle(uint8_t prefix); - - static const char *usagePageTitles0[]; - static const char *usagePageTitles1[]; - static const char *genDesktopTitles0[]; - static const char *genDesktopTitles1[]; - static const char *genDesktopTitles2[]; - static const char *genDesktopTitles3[]; - static const char *genDesktopTitles4[]; - static const char *simuTitles0[]; - static const char *simuTitles1[]; - static const char *simuTitles2[]; - static const char *vrTitles0[]; - static const char *vrTitles1[]; - static const char *sportsCtrlTitles0[]; - static const char *sportsCtrlTitles1[]; - static const char *sportsCtrlTitles2[]; - static const char *gameTitles0[]; - static const char *gameTitles1[]; - static const char *genDevCtrlTitles[]; - static const char *ledTitles[]; - static const char *telTitles0[]; - static const char *telTitles1[]; - static const char *telTitles2[]; - static const char *telTitles3[]; - static const char *telTitles4[]; - static const char *telTitles5[]; - static const char *consTitles0[]; - static const char *consTitles1[]; - static const char *consTitles2[]; - static const char *consTitles3[]; - static const char *consTitles4[]; - static const char *consTitles5[]; - static const char *consTitles6[]; - static const char *consTitles7[]; - static const char *consTitles8[]; - static const char *consTitles9[]; - static const char *consTitlesA[]; - static const char *consTitlesB[]; - static const char *consTitlesC[]; - static const char *consTitlesD[]; - static const char *consTitlesE[]; - static const char *digitTitles0[]; - static const char *digitTitles1[]; - static const char *digitTitles2[]; - static const char *aplphanumTitles0[]; - static const char *aplphanumTitles1[]; - static const char *aplphanumTitles2[]; - static const char *medInstrTitles0[]; - static const char *medInstrTitles1[]; - static const char *medInstrTitles2[]; - static const char *medInstrTitles3[]; - static const char *medInstrTitles4[]; - -protected: - static UsagePageFunc usagePageFunctions[]; - - MultiValueBuffer theBuffer; - MultiByteValueParser valParser; - ByteSkipper theSkipper; - uint8_t varBuffer[sizeof(USB_CONFIGURATION_DESCRIPTOR)]; - - uint8_t itemParseState; // Item parser state variable - uint8_t itemSize; // Item size - uint8_t itemPrefix; // Item prefix (first byte) - uint8_t rptSize; // Report Size - uint8_t rptCount; // Report Count - - uint16_t totalSize; // Report size in bits - - virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); - - UsagePageFunc pfUsage; - - static void PrintUsagePage(uint16_t page); - void SetUsagePage(uint16_t page); - -public: - ReportDescParserBase() : - itemParseState(0), - itemSize(0), - itemPrefix(0), - rptSize(0), - rptCount(0), - pfUsage(NULL) - { - theBuffer.pValue = varBuffer; - valParser.Initialize(&theBuffer); - theSkipper.Initialize(&theBuffer); - }; - - virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); - - enum - { - enErrorSuccess = 0 - , enErrorIncomplete // value or record is partialy read in buffer - , enErrorBufferTooSmall - }; -}; - -class ReportDescParser : public ReportDescParserBase -{ -}; - -class ReportDescParser2 : public ReportDescParserBase -{ - uint8_t rptId; // Report ID - uint8_t useMin; // Usage Minimum - uint8_t useMax; // Usage Maximum - uint8_t fieldCount; // Number of field being currently processed - - void OnInputItem(uint8_t itm); // Method which is called every time Input item is found - - uint8_t *pBuf; // Report buffer pointer - uint8_t bLen; // Report length - -protected: - virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); - -public: - ReportDescParser2(uint16_t len, uint8_t *pbuf) : - ReportDescParserBase(), bLen(len), pBuf(pbuf), rptId(0), useMin(0), useMax(0), fieldCount(0) - {}; -}; - -class UniversalReportParser : public HIDReportParser -{ -public: - virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); -}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__HIDDESCRIPTORPARSER_H__) +#define __HIDDESCRIPTORPARSER_H__ + +#include +#include +#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 +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" +#include "confdescparser.h" +#include "hid.h" + +class ReportDescParserBase : public USBReadParser { +public: + typedef void (*UsagePageFunc)(uint16_t usage); + + static void PrintGenericDesktopPageUsage(uint16_t usage); + static void PrintSimulationControlsPageUsage(uint16_t usage); + static void PrintVRControlsPageUsage(uint16_t usage); + static void PrintSportsControlsPageUsage(uint16_t usage); + static void PrintGameControlsPageUsage(uint16_t usage); + static void PrintGenericDeviceControlsPageUsage(uint16_t usage); + static void PrintLEDPageUsage(uint16_t usage); + static void PrintButtonPageUsage(uint16_t usage); + static void PrintOrdinalPageUsage(uint16_t usage); + static void PrintTelephonyPageUsage(uint16_t usage); + static void PrintConsumerPageUsage(uint16_t usage); + static void PrintDigitizerPageUsage(uint16_t usage); + static void PrintAlphanumDisplayPageUsage(uint16_t usage); + static void PrintMedicalInstrumentPageUsage(uint16_t usage); + + static void PrintValue(uint8_t *p, uint8_t len); + static void PrintByteValue(uint8_t data); + + static void PrintItemTitle(uint8_t prefix); + + static const char * const usagePageTitles0[]; + static const char * const usagePageTitles1[]; + static const char * const genDesktopTitles0[]; + static const char * const genDesktopTitles1[]; + static const char * const genDesktopTitles2[]; + static const char * const genDesktopTitles3[]; + static const char * const genDesktopTitles4[]; + static const char * const simuTitles0[]; + static const char * const simuTitles1[]; + static const char * const simuTitles2[]; + static const char * const vrTitles0[]; + static const char * const vrTitles1[]; + static const char * const sportsCtrlTitles0[]; + static const char * const sportsCtrlTitles1[]; + static const char * const sportsCtrlTitles2[]; + static const char * const gameTitles0[]; + static const char * const gameTitles1[]; + static const char * const genDevCtrlTitles[]; + static const char * const ledTitles[]; + static const char * const telTitles0[]; + static const char * const telTitles1[]; + static const char * const telTitles2[]; + static const char * const telTitles3[]; + static const char * const telTitles4[]; + static const char * const telTitles5[]; + static const char * const consTitles0[]; + static const char * const consTitles1[]; + static const char * const consTitles2[]; + static const char * const consTitles3[]; + static const char * const consTitles4[]; + static const char * const consTitles5[]; + static const char * const consTitles6[]; + static const char * const consTitles7[]; + static const char * const consTitles8[]; + static const char * const consTitles9[]; + static const char * const consTitlesA[]; + static const char * const consTitlesB[]; + static const char * const consTitlesC[]; + static const char * const consTitlesD[]; + static const char * const consTitlesE[]; + static const char * const digitTitles0[]; + static const char * const digitTitles1[]; + static const char * const digitTitles2[]; + static const char * const aplphanumTitles0[]; + static const char * const aplphanumTitles1[]; + static const char * const aplphanumTitles2[]; + static const char * const medInstrTitles0[]; + static const char * const medInstrTitles1[]; + static const char * const medInstrTitles2[]; + static const char * const medInstrTitles3[]; + static const char * const medInstrTitles4[]; + +protected: + static UsagePageFunc usagePageFunctions[]; + + MultiValueBuffer theBuffer; + MultiByteValueParser valParser; + ByteSkipper theSkipper; + uint8_t varBuffer[sizeof(USB_CONFIGURATION_DESCRIPTOR)]; + + uint8_t itemParseState; // Item parser state variable + uint8_t itemSize; // Item size + uint8_t itemPrefix; // Item prefix (first byte) + uint8_t rptSize; // Report Size + uint8_t rptCount; // Report Count + + uint16_t totalSize; // Report size in bits + + virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); + + UsagePageFunc pfUsage; + + static void PrintUsagePage(uint16_t page); + void SetUsagePage(uint16_t page); + +public: + + ReportDescParserBase() : + itemParseState(0), + itemSize(0), + itemPrefix(0), + rptSize(0), + rptCount(0), + pfUsage(NULL) { + theBuffer.pValue = varBuffer; + valParser.Initialize(&theBuffer); + theSkipper.Initialize(&theBuffer); + }; + + virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); + + enum { + enErrorSuccess = 0 + , enErrorIncomplete // value or record is partialy read in buffer + , enErrorBufferTooSmall + }; +}; + +class ReportDescParser : public ReportDescParserBase { +}; + +class ReportDescParser2 : public ReportDescParserBase { + uint8_t rptId; // Report ID + uint8_t useMin; // Usage Minimum + uint8_t useMax; // Usage Maximum + uint8_t fieldCount; // Number of field being currently processed + + void OnInputItem(uint8_t itm); // Method which is called every time Input item is found + + uint8_t *pBuf; // Report buffer pointer + uint8_t bLen; // Report length + +protected: + virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); + +public: + + ReportDescParser2(uint16_t len, uint8_t *pbuf) : + ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) { + }; +}; + +class UniversalReportParser : public HIDReportParser { +public: + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); +}; + #endif // __HIDDESCRIPTORPARSER_H__ \ No newline at end of file diff --git a/hiduniversal.cpp b/hiduniversal.cpp index 9bffe3b7..2ae0ba3c 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -1,418 +1,378 @@ -#include "hiduniversal.h" - -HIDUniversal::HIDUniversal(USB *p) : - HID(p), - qNextPollTime(0), - bPollEnable(false), - bHasReportId(false) -{ - Initialize(); - - if (pUsb) - pUsb->RegisterDeviceClass(this); -} - -uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) -{ - for (uint8_t i=0, n=0; iGetAddressPool(); - - USBTRACE("HU Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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; - - //delay(200); - - // Get device descriptor - rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); - - if (!rcode) - len = (buf[0] > constBufSize) ? constBufSize : buf[0]; - - if( rcode ) - { - // Restore p->epinfo - p->epinfo = oldep_ptr; - - goto FailGetDevDescr; - } - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - delay(500); - - if (len) - rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf ); - - if(rcode) - goto FailGetDevDescr; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - USBTRACE2("NC:", num_of_conf); - - for (uint8_t i=0; i HexDump; - ConfigDescParser confDescrParser(this); - - //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); - rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); - - if (bNumEP > 1) - break; - } // for - - if (bNumEP < 2) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - - USBTRACE2("\r\nCnf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConfDescr; - - for (uint8_t i=0; i 1 && conf != bConfNum) - return; - - //ErrorMessage(PSTR("\r\nConf.Val"), conf); - //ErrorMessage(PSTR("Iface Num"), iface); - //ErrorMessage(PSTR("Alt.Set"), alt); - - bConfNum = conf; - - uint8_t index = 0; - HIDInterface *piface = FindInterface(iface, alt, proto); - - // Fill in interface structure in case of new interface - if (!piface) - { - piface = hidInterfaces + bNumIface; - piface->bmInterface = iface; - piface->bmAltSet = alt; - piface->bmProtocol = proto; - bNumIface ++; - } - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - index = epInterruptOutIndex; - - if (index) - { - // Fill in the endpoint info structure - epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize; - epInfo[bNumEP].epAttribs = 0; - epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT; - - // Fill in the endpoint index list - piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); - - bNumEP ++; - } - //PrintEndpointDescriptor(pep); -} - - -uint8_t HIDUniversal::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bNumEP = 1; - bAddress = 0; - qNextPollTime = 0; - bPollEnable = false; - return 0; -} - -bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) -{ - for (uint8_t i=0; iinTransfer(bAddress, epInfo[index].epAddr, &read, buf); - - if (rcode) - { - if (rcode != hrNAK) - USBTRACE2("Poll:", rcode); - return rcode; - } - - if (read > constBuffLen) - read = constBuffLen; - - bool identical = BuffersIdentical(read, buf, prevBuf); - - SaveBuffer(read, buf, prevBuf); - - if (identical) - return 0; - - Serial.print("\r\nBuf: "); - - for (uint8_t i=0; i(buf[i]); - - Serial.println(""); - - HIDReportParser *prs = GetReportParser( ((bHasReportId) ? *buf : 0) ); - - if (prs) - prs->Parse(this, bHasReportId, (uint8_t)read, buf); - } - } - return rcode; -} +#include "hiduniversal.h" + +HIDUniversal::HIDUniversal(USB *p) : +HID(p), +qNextPollTime(0), +bPollEnable(false), +bHasReportId(false) { + Initialize(); + + if (pUsb) + pUsb->RegisterDeviceClass(this); +} + +uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) { + for (uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) { + if (descrInfo[i].bDescrType == type) { + if (n == num) + return descrInfo[i].wDescriptorLength; + n++; + } + } + return 0; +} + +void HIDUniversal::Initialize() { + for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) { + rptParsers[i].rptId = 0; + rptParsers[i].rptParser = NULL; + } + for (uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) { + descrInfo[i].bDescrType = 0; + descrInfo[i].wDescriptorLength = 0; + } + for (uint8_t i = 0; i < maxHidInterfaces; i++) { + hidInterfaces[i].bmInterface = 0; + hidInterfaces[i].bmProtocol = 0; + + for (uint8_t j = 0; j < maxEpPerInterface; j++) + hidInterfaces[i].epIndex[j] = 0; + } + for (uint8_t i = 0; i < totalEndpoints; 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; + } + bNumEP = 1; + bNumIface = 0; + bConfNum = 0; + + ZeroMemory(constBuffLen, prevBuf); +} + +bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) { + for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) { + if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) { + rptParsers[i].rptId = id; + rptParsers[i].rptParser = prs; + return true; + } + } + return false; +} + +HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) { + if (!bHasReportId) + return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL); + + for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) { + if (rptParsers[i].rptId == id) + return rptParsers[i].rptParser; + } + return NULL; +} + +uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t len = 0; + + uint8_t num_of_conf; // number of configurations + //uint8_t num_of_intf; // number of interfaces + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("HU Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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, 8, (uint8_t*)buf); + + if (!rcode) + len = (buf[0] > constBufSize) ? constBufSize : buf[0]; + + if (rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + + goto FailGetDevDescr; + } + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + if (len) + rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf); + + if (rcode) + goto FailGetDevDescr; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + //HexDumper HexDump; + ConfigDescParser confDescrParser(this); + + //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + + if (rcode) + goto FailGetConfDescr; + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 2) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("\r\nCnf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConfDescr; + + for (uint8_t i = 0; i < bNumIface; i++) { + if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0) + continue; + + rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0); + + if (rcode && rcode != hrSTALL) + goto FailSetIdle; + } + + USBTRACE("HU configured\r\n"); + + OnInitSuccessful(); + + bPollEnable = true; + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConfDescr: + USBTRACE("setConf:"); + goto Fail; + +FailSetIdle: + USBTRACE("SetIdle:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.println(rcode, HEX); + Release(); + return rcode; +} + +HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) { + for (uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++) + if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt + && hidInterfaces[i].bmProtocol == proto) + return hidInterfaces + i; + return NULL; +} + +void HIDUniversal::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 (bNumEP > 1 && conf != bConfNum) + return; + + //ErrorMessage(PSTR("\r\nConf.Val"), conf); + //ErrorMessage(PSTR("Iface Num"), iface); + //ErrorMessage(PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index = 0; + HIDInterface *piface = FindInterface(iface, alt, proto); + + // Fill in interface structure in case of new interface + if (!piface) { + piface = hidInterfaces + bNumIface; + piface->bmInterface = iface; + piface->bmAltSet = alt; + piface->bmProtocol = proto; + bNumIface++; + } + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + index = epInterruptOutIndex; + + if (index) { + // Fill in the endpoint info structure + epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[bNumEP].epAttribs = 0; + epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT; + + // Fill in the endpoint index list + piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); + + bNumEP++; + } + //PrintEndpointDescriptor(pep); +} + +uint8_t HIDUniversal::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bNumEP = 1; + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) { + for (uint8_t i = 0; i < len; i++) + if (buf1[i] != buf2[i]) + return false; + return true; +} + +void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) { + for (uint8_t i = 0; i < len; i++) + buf[i] = 0; +} + +void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) { + for (uint8_t i = 0; i < len; i++) + dest[i] = src[i]; +} + +uint8_t HIDUniversal::Poll() { + uint8_t rcode = 0; + + if (!bPollEnable) + return 0; + + if (qNextPollTime <= millis()) { + qNextPollTime = millis() + 50; + + uint8_t buf[constBuffLen]; + + for (uint8_t i = 0; i < bNumIface; i++) { + uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex]; + uint16_t read = (uint16_t)epInfo[index].maxPktSize; + + ZeroMemory(constBuffLen, buf); + + uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf); + + if (rcode) { + if (rcode != hrNAK) + USBTRACE2("Poll:", rcode); + return rcode; + } + + if (read > constBuffLen) + read = constBuffLen; + + bool identical = BuffersIdentical(read, buf, prevBuf); + + SaveBuffer(read, buf, prevBuf); + + if (identical) + return 0; + + Notify(PSTR("\r\nBuf: "), 0x80); + + for (uint8_t i = 0; i < read; i++) + PrintHex (buf[i], 0x80); + + Notify(PSTR("\r\n"), 0x80); + + HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0)); + + if (prs) + prs->Parse(this, bHasReportId, (uint8_t)read, buf); + } + } + return rcode; +} diff --git a/hiduniversal.h b/hiduniversal.h index 9b64af37..e1ea26c4 100644 --- a/hiduniversal.h +++ b/hiduniversal.h @@ -1,75 +1,79 @@ -#if !defined(__HIDUNIVERSAL_H__) -#define __HIDUNIVERSAL_H__ - -#include "hid.h" -//#include "hidescriptorparser.h" - -class HIDUniversal : public HID -{ - struct ReportParser - { - uint8_t rptId; - HIDReportParser *rptParser; - } rptParsers[MAX_REPORT_PARSERS]; - - // HID class specific descriptor type and length info obtained from HID descriptor - HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS]; - - // Returns HID class specific descriptor length by its type and order number - uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num); - - EpInfo epInfo[totalEndpoints]; - - struct HIDInterface - { - struct - { - uint8_t bmInterface : 3; - uint8_t bmAltSet : 3; - uint8_t bmProtocol : 2; - }; - uint8_t epIndex[maxEpPerInterface]; - }; - - HIDInterface hidInterfaces[maxHidInterfaces]; - - uint8_t bConfNum; // configuration number - uint8_t bNumIface; // number of interfaces in the configuration - uint8_t bNumEP; // total number of EP in the configuration - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag - - static const uint16_t constBuffLen = 64; // event buffer length - uint8_t prevBuf[constBuffLen]; // previous event buffer - - void Initialize(); - HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto); - - void ZeroMemory(uint8_t len, uint8_t *buf); - bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2); - void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest); - -protected: - bool bHasReportId; - - // HID implementation - virtual HIDReportParser* GetReportParser(uint8_t id); - virtual uint8_t OnInitSuccessful() { return 0; }; - -public: - HIDUniversal(USB *p); - - // HID implementation - virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; - - // UsbConfigXtracter implementation - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); -}; - +#if !defined(__HIDUNIVERSAL_H__) +#define __HIDUNIVERSAL_H__ + +#include "hid.h" +//#include "hidescriptorparser.h" + +class HIDUniversal : public HID { + + struct ReportParser { + uint8_t rptId; + HIDReportParser *rptParser; + } rptParsers[MAX_REPORT_PARSERS]; + + // HID class specific descriptor type and length info obtained from HID descriptor + HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS]; + + // Returns HID class specific descriptor length by its type and order number + uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num); + + EpInfo epInfo[totalEndpoints]; + + struct HIDInterface { + + struct { + uint8_t bmInterface : 3; + uint8_t bmAltSet : 3; + uint8_t bmProtocol : 2; + }; + uint8_t epIndex[maxEpPerInterface]; + }; + + HIDInterface hidInterfaces[maxHidInterfaces]; + + uint8_t bConfNum; // configuration number + uint8_t bNumIface; // number of interfaces in the configuration + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + static const uint16_t constBuffLen = 64; // event buffer length + uint8_t prevBuf[constBuffLen]; // previous event buffer + + void Initialize(); + HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto); + + void ZeroMemory(uint8_t len, uint8_t *buf); + bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2); + void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest); + +protected: + bool bHasReportId; + + // HID implementation + virtual HIDReportParser* GetReportParser(uint8_t id); + + virtual uint8_t OnInitSuccessful() { + return 0; + }; + +public: + HIDUniversal(USB *p); + + // HID implementation + virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; + #endif // __HIDUNIVERSAL_H__ \ No newline at end of file diff --git a/hidusagestr.h b/hidusagestr.h index b150f26a..6c137e02 100644 --- a/hidusagestr.h +++ b/hidusagestr.h @@ -1,977 +1,977 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined( __HIDUSAGESTR_H__) -#define __HIDUSAGESTR_H__ - -#include - -const char pstrSpace [] PROGMEM = " "; -const char pstrCRLF [] PROGMEM = "\r\n"; -const char pstrSingleTab [] PROGMEM = "\t"; -const char pstrDoubleTab [] PROGMEM = "\t\t"; -const char pstrTripleTab [] PROGMEM = "\t\t\t"; - -// Usage Page String Titles -const char pstrUsagePageUndefined [] PROGMEM = "Undef"; -const char pstrUsagePageGenericDesktopControls [] PROGMEM = "Gen Desktop Ctrls"; -const char pstrUsagePageSimulationControls [] PROGMEM = "Simu Ctrls"; -const char pstrUsagePageVRControls [] PROGMEM = "VR Ctrls"; -const char pstrUsagePageSportControls [] PROGMEM = "Sport Ctrls"; -const char pstrUsagePageGameControls [] PROGMEM = "Game Ctrls"; -const char pstrUsagePageGenericDeviceControls [] PROGMEM = "Gen Dev Ctrls"; -const char pstrUsagePageKeyboardKeypad [] PROGMEM = "Kbrd/Keypad"; -const char pstrUsagePageLEDs [] PROGMEM = "LEDs"; -const char pstrUsagePageButton [] PROGMEM = "Button"; -const char pstrUsagePageOrdinal [] PROGMEM = "Ordinal"; -const char pstrUsagePageTelephone [] PROGMEM = "Tel"; -const char pstrUsagePageConsumer [] PROGMEM = "Consumer"; -const char pstrUsagePageDigitizer [] PROGMEM = "Digitizer"; -const char pstrUsagePagePID [] PROGMEM = "PID"; -const char pstrUsagePageUnicode [] PROGMEM = "Unicode"; -const char pstrUsagePageAlphaNumericDisplay [] PROGMEM = "Alpha Num Disp"; -const char pstrUsagePageMedicalInstruments [] PROGMEM = "Medical Instr"; -const char pstrUsagePageMonitor [] PROGMEM = "Monitor"; -const char pstrUsagePagePower [] PROGMEM = "Power"; -const char pstrUsagePageBarCodeScanner [] PROGMEM = "Bar Code Scan"; -const char pstrUsagePageScale [] PROGMEM = "Scale"; -const char pstrUsagePageMSRDevices [] PROGMEM = "Magn Stripe Read Dev"; -const char pstrUsagePagePointOfSale [] PROGMEM = "POS"; -const char pstrUsagePageCameraControl [] PROGMEM = "Cam Ctrl"; -const char pstrUsagePageArcade [] PROGMEM = "Arcade"; -const char pstrUsagePageReserved [] PROGMEM = "Reserved"; -const char pstrUsagePageVendorDefined [] PROGMEM = "Vendor Def"; - -// Generic Desktop Controls Page -const char pstrUsagePointer [] PROGMEM = "Pointer"; -const char pstrUsageMouse [] PROGMEM = "Mouse"; -const char pstrUsageJoystick [] PROGMEM = "Joystick"; -const char pstrUsageGamePad [] PROGMEM = "Game Pad"; -const char pstrUsageKeyboard [] PROGMEM = "Kbrd"; -const char pstrUsageKeypad [] PROGMEM = "Keypad"; -const char pstrUsageMultiAxisController [] PROGMEM = "Multi-axis Ctrl"; -const char pstrUsageTabletPCSystemControls [] PROGMEM = "Tablet PC Sys Ctrls"; -const char pstrUsageX [] PROGMEM = "X"; -const char pstrUsageY [] PROGMEM = "Y"; -const char pstrUsageZ [] PROGMEM = "Z"; -const char pstrUsageRx [] PROGMEM = "Rx"; -const char pstrUsageRy [] PROGMEM = "Ry"; -const char pstrUsageRz [] PROGMEM = "Rz"; -const char pstrUsageSlider [] PROGMEM = "Slider"; -const char pstrUsageDial [] PROGMEM = "Dial"; -const char pstrUsageWheel [] PROGMEM = "Wheel"; -const char pstrUsageHatSwitch [] PROGMEM = "Hat Switch"; -const char pstrUsageCountedBuffer [] PROGMEM = "Counted Buf"; -const char pstrUsageByteCount [] PROGMEM = "Byte Count"; -const char pstrUsageMotionWakeup [] PROGMEM = "Motion Wakeup"; -const char pstrUsageStart [] PROGMEM = "Start"; -const char pstrUsageSelect [] PROGMEM = "Sel"; -const char pstrUsageVx [] PROGMEM = "Vx"; -const char pstrUsageVy [] PROGMEM = "Vy"; -const char pstrUsageVz [] PROGMEM = "Vz"; -const char pstrUsageVbrx [] PROGMEM = "Vbrx"; -const char pstrUsageVbry [] PROGMEM = "Vbry"; -const char pstrUsageVbrz [] PROGMEM = "Vbrz"; -const char pstrUsageVno [] PROGMEM = "Vno"; -const char pstrUsageFeatureNotification [] PROGMEM = "Feature Notif"; -const char pstrUsageResolutionMultiplier [] PROGMEM = "Res Mult"; -const char pstrUsageSystemControl [] PROGMEM = "Sys Ctrl"; -const char pstrUsageSystemPowerDown [] PROGMEM = "Sys Pwr Down"; -const char pstrUsageSystemSleep [] PROGMEM = "Sys Sleep"; -const char pstrUsageSystemWakeup [] PROGMEM = "Sys Wakeup"; -const char pstrUsageSystemContextMenu [] PROGMEM = "Sys Context Menu"; -const char pstrUsageSystemMainMenu [] PROGMEM = "Sys Main Menu"; -const char pstrUsageSystemAppMenu [] PROGMEM = "Sys App Menu"; -const char pstrUsageSystemMenuHelp [] PROGMEM = "Sys Menu Help"; -const char pstrUsageSystemMenuExit [] PROGMEM = "Sys Menu Exit"; -const char pstrUsageSystemMenuSelect [] PROGMEM = "Sys Menu Select"; -const char pstrUsageSystemMenuRight [] PROGMEM = "Sys Menu Right"; -const char pstrUsageSystemMenuLeft [] PROGMEM = "Sys Menu Left"; -const char pstrUsageSystemMenuUp [] PROGMEM = "Sys Menu Up"; -const char pstrUsageSystemMenuDown [] PROGMEM = "Sys Menu Down"; -const char pstrUsageSystemColdRestart [] PROGMEM = "Sys Cold Restart"; -const char pstrUsageSystemWarmRestart [] PROGMEM = "Sys Warm Restart"; -const char pstrUsageDPadUp [] PROGMEM = "D-pad Up"; -const char pstrUsageDPadDown [] PROGMEM = "D-pad Down"; -const char pstrUsageDPadRight [] PROGMEM = "D-pad Right"; -const char pstrUsageDPadLeft [] PROGMEM = "D-pad Left"; -const char pstrUsageSystemDock [] PROGMEM = "Sys Dock"; -const char pstrUsageSystemUndock [] PROGMEM = "Sys Undock"; -const char pstrUsageSystemSetup [] PROGMEM = "Sys Setup"; -const char pstrUsageSystemBreak [] PROGMEM = "Sys Break"; -const char pstrUsageSystemDebuggerBreak [] PROGMEM = "Sys Dbg Brk"; -const char pstrUsageApplicationBreak [] PROGMEM = "App Break"; -const char pstrUsageApplicationDebuggerBreak [] PROGMEM = "App Dbg Brk"; -const char pstrUsageSystemSpeakerMute [] PROGMEM = "Sys Spk Mute"; -const char pstrUsageSystemHibernate [] PROGMEM = "Sys Hiber"; -const char pstrUsageSystemDisplayInvert [] PROGMEM = "Sys Disp Inv"; -const char pstrUsageSystemDisplayInternal [] PROGMEM = "Sys Disp Int"; -const char pstrUsageSystemDisplayExternal [] PROGMEM = "Sys Disp Ext"; -const char pstrUsageSystemDisplayBoth [] PROGMEM = "Sys Disp Both"; -const char pstrUsageSystemDisplayDual [] PROGMEM = "Sys Disp Dual"; -const char pstrUsageSystemDisplayToggleIntExt [] PROGMEM = "Sys Disp Tgl Int/Ext"; -const char pstrUsageSystemDisplaySwapPriSec [] PROGMEM = "Sys Disp Swap Pri/Sec"; -const char pstrUsageSystemDisplayLCDAutoscale [] PROGMEM = "Sys Disp LCD Autoscale"; - -// Simulation Controls Page -const char pstrUsageFlightSimulationDevice [] PROGMEM = "Flight Simu Dev"; -const char pstrUsageAutomobileSimulationDevice [] PROGMEM = "Auto Simu Dev"; -const char pstrUsageTankSimulationDevice [] PROGMEM = "Tank Simu Dev"; -const char pstrUsageSpaceshipSimulationDevice [] PROGMEM = "Space Simu Dev"; -const char pstrUsageSubmarineSimulationDevice [] PROGMEM = "Subm Simu Dev"; -const char pstrUsageSailingSimulationDevice [] PROGMEM = "Sail Simu Dev"; -const char pstrUsageMotocicleSimulationDevice [] PROGMEM = "Moto Simu Dev"; -const char pstrUsageSportsSimulationDevice [] PROGMEM = "Sport Simu Dev"; -const char pstrUsageAirplaneSimulationDevice [] PROGMEM = "Airp Simu Dev"; -const char pstrUsageHelicopterSimulationDevice [] PROGMEM = "Heli Simu Dev"; -const char pstrUsageMagicCarpetSimulationDevice [] PROGMEM = "Magic Carpet Simu Dev"; -const char pstrUsageBicycleSimulationDevice [] PROGMEM = "Bike Simu Dev"; -const char pstrUsageFlightControlStick [] PROGMEM = "Flight Ctrl Stick"; -const char pstrUsageFlightStick [] PROGMEM = "Flight Stick"; -const char pstrUsageCyclicControl [] PROGMEM = "Cyclic Ctrl"; -const char pstrUsageCyclicTrim [] PROGMEM = "Cyclic Trim"; -const char pstrUsageFlightYoke [] PROGMEM = "Flight Yoke"; -const char pstrUsageTrackControl [] PROGMEM = "Track Ctrl"; -const char pstrUsageAileron [] PROGMEM = "Aileron"; -const char pstrUsageAileronTrim [] PROGMEM = "Aileron Trim"; -const char pstrUsageAntiTorqueControl [] PROGMEM = "Anti-Torque Ctrl"; -const char pstrUsageAutopilotEnable [] PROGMEM = "Autopilot Enable"; -const char pstrUsageChaffRelease [] PROGMEM = "Chaff Release"; -const char pstrUsageCollectiveControl [] PROGMEM = "Collective Ctrl"; -const char pstrUsageDiveBrake [] PROGMEM = "Dive Brake"; -const char pstrUsageElectronicCountermeasures [] PROGMEM = "El Countermeasures"; -const char pstrUsageElevator [] PROGMEM = "Elevator"; -const char pstrUsageElevatorTrim [] PROGMEM = "Elevator Trim"; -const char pstrUsageRudder [] PROGMEM = "Rudder"; -const char pstrUsageThrottle [] PROGMEM = "Throttle"; -const char pstrUsageFlightCommunications [] PROGMEM = "Flight Comm"; -const char pstrUsageFlareRelease [] PROGMEM = "Flare Release"; -const char pstrUsageLandingGear [] PROGMEM = "Landing Gear"; -const char pstrUsageToeBrake [] PROGMEM = "Toe Brake"; -const char pstrUsageTrigger [] PROGMEM = "Trigger"; -const char pstrUsageWeaponsArm [] PROGMEM = "Weapons Arm"; -const char pstrUsageWeaponsSelect [] PROGMEM = "Weapons Sel"; -const char pstrUsageWingFlaps [] PROGMEM = "Wing Flaps"; -const char pstrUsageAccelerator [] PROGMEM = "Accel"; -const char pstrUsageBrake [] PROGMEM = "Brake"; -const char pstrUsageClutch [] PROGMEM = "Clutch"; -const char pstrUsageShifter [] PROGMEM = "Shifter"; -const char pstrUsageSteering [] PROGMEM = "Steering"; -const char pstrUsageTurretDirection [] PROGMEM = "Turret Dir"; -const char pstrUsageBarrelElevation [] PROGMEM = "Barrel Ele"; -const char pstrUsageDivePlane [] PROGMEM = "Dive Plane"; -const char pstrUsageBallast [] PROGMEM = "Ballast"; -const char pstrUsageBicycleCrank [] PROGMEM = "Bicycle Crank"; -const char pstrUsageHandleBars [] PROGMEM = "Handle Bars"; -const char pstrUsageFrontBrake [] PROGMEM = "Front Brake"; -const char pstrUsageRearBrake [] PROGMEM = "Rear Brake"; - -// VR Controls Page -const char pstrUsageBelt [] PROGMEM = "Belt"; -const char pstrUsageBodySuit [] PROGMEM = "Body Suit"; -const char pstrUsageFlexor [] PROGMEM = "Flexor"; -const char pstrUsageGlove [] PROGMEM = "Glove"; -const char pstrUsageHeadTracker [] PROGMEM = "Head Track"; -const char pstrUsageHeadMountedDisplay [] PROGMEM = "Head Disp"; -const char pstrUsageHandTracker [] PROGMEM = "Hand Track"; -const char pstrUsageOculometer [] PROGMEM = "Oculometer"; -const char pstrUsageVest [] PROGMEM = "Vest"; -const char pstrUsageAnimatronicDevice [] PROGMEM = "Animat Dev"; -const char pstrUsageStereoEnable [] PROGMEM = "Stereo Enbl"; -const char pstrUsageDisplayEnable [] PROGMEM = "Display Enbl"; - -// Sport Controls Page -const char pstrUsageBaseballBat [] PROGMEM = "Baseball Bat"; -const char pstrUsageGolfClub [] PROGMEM = "Golf Club"; -const char pstrUsageRowingMachine [] PROGMEM = "Rowing Mach"; -const char pstrUsageTreadmill [] PROGMEM = "Treadmill"; -const char pstrUsageOar [] PROGMEM = "Oar"; -const char pstrUsageSlope [] PROGMEM = "Slope"; -const char pstrUsageRate [] PROGMEM = "Rate"; -const char pstrUsageStickSpeed [] PROGMEM = "Stick Speed"; -const char pstrUsageStickFaceAngle [] PROGMEM = "Stick Face Ang"; -const char pstrUsageStickHeelToe [] PROGMEM = "Stick Heel/Toe"; -const char pstrUsageStickFollowThough [] PROGMEM = "Stick Flw Thru"; -const char pstrUsageStickTempo [] PROGMEM = "Stick Tempo"; -const char pstrUsageStickType [] PROGMEM = "Stick Type"; -const char pstrUsageStickHeight [] PROGMEM = "Stick Hght"; -const char pstrUsagePutter [] PROGMEM = "Putter"; -const char pstrUsage1Iron [] PROGMEM = "1 Iron"; -const char pstrUsage2Iron [] PROGMEM = "2 Iron"; -const char pstrUsage3Iron [] PROGMEM = "3 Iron"; -const char pstrUsage4Iron [] PROGMEM = "4 Iron"; -const char pstrUsage5Iron [] PROGMEM = "5 Iron"; -const char pstrUsage6Iron [] PROGMEM = "6 Iron"; -const char pstrUsage7Iron [] PROGMEM = "7 Iron"; -const char pstrUsage8Iron [] PROGMEM = "8 Iron"; -const char pstrUsage9Iron [] PROGMEM = "9 Iron"; -const char pstrUsage10Iron [] PROGMEM = "10 Iron"; -const char pstrUsage11Iron [] PROGMEM = "11 Iron"; -const char pstrUsageSandWedge [] PROGMEM = "Sand Wedge"; -const char pstrUsageLoftWedge [] PROGMEM = "Loft Wedge"; -const char pstrUsagePowerWedge [] PROGMEM = "Pwr Wedge"; -const char pstrUsage1Wood [] PROGMEM = "1 Wood"; -const char pstrUsage3Wood [] PROGMEM = "3 Wood"; -const char pstrUsage5Wood [] PROGMEM = "5 Wood"; -const char pstrUsage7Wood [] PROGMEM = "7 Wood"; -const char pstrUsage9Wood [] PROGMEM = "9 Wood"; - -// Game Controls Page -const char pstrUsage3DGameController [] PROGMEM = "3D Game Ctrl"; -const char pstrUsagePinballDevice [] PROGMEM = "Pinball Dev"; -const char pstrUsageGunDevice [] PROGMEM = "Gun Dev"; -const char pstrUsagePointOfView [] PROGMEM = "POV"; -const char pstrUsageTurnRightLeft [] PROGMEM = "Turn Right Left"; -const char pstrUsagePitchForwardBackward [] PROGMEM = "Pitch Fwd/Back"; -const char pstrUsageRollRightLeft [] PROGMEM = "Roll Right/Left"; -const char pstrUsageMoveRightLeft [] PROGMEM = "Move Right/Left"; -const char pstrUsageMoveForwardBackward [] PROGMEM = "Move Fwd/Back"; -const char pstrUsageMoveUpDown [] PROGMEM = "Move Up/Down"; -const char pstrUsageLeanRightLeft [] PROGMEM = "Lean Right/Left"; -const char pstrUsageLeanForwardBackward [] PROGMEM = "Lean Fwd/Back"; -const char pstrUsageHeightOfPOV [] PROGMEM = "Height of POV"; -const char pstrUsageFlipper [] PROGMEM = "Flipper"; -const char pstrUsageSecondaryFlipper [] PROGMEM = "Second Flipper"; -const char pstrUsageBump [] PROGMEM = "Bump"; -const char pstrUsageNewGame [] PROGMEM = "New Game"; -const char pstrUsageShootBall [] PROGMEM = "Shoot Ball"; -const char pstrUsagePlayer [] PROGMEM = "Player"; -const char pstrUsageGunBolt [] PROGMEM = "Gun Bolt"; -const char pstrUsageGunClip [] PROGMEM = "Gun Clip"; -const char pstrUsageGunSelector [] PROGMEM = "Gun Sel"; -const char pstrUsageGunSingleShot [] PROGMEM = "Gun Sngl Shot"; -const char pstrUsageGunBurst [] PROGMEM = "Gun Burst"; -const char pstrUsageGunAutomatic [] PROGMEM = "Gun Auto"; -const char pstrUsageGunSafety [] PROGMEM = "Gun Safety"; -const char pstrUsageGamepadFireJump [] PROGMEM = "Gamepad Fire/Jump"; -const char pstrUsageGamepadTrigger [] PROGMEM = "Gamepad Trig"; - -// Generic Device Controls Page -const char pstrUsageBatteryStrength [] PROGMEM = "Bat Strength"; -const char pstrUsageWirelessChannel [] PROGMEM = "Wireless Ch"; -const char pstrUsageWirelessID [] PROGMEM = "Wireless ID"; -const char pstrUsageDiscoverWirelessControl [] PROGMEM = "Discover Wireless Ctrl"; -const char pstrUsageSecurityCodeCharEntered [] PROGMEM = "Sec Code Char Entrd"; -const char pstrUsageSecurityCodeCharErased [] PROGMEM = "Sec Code Char Erased"; -const char pstrUsageSecurityCodeCleared [] PROGMEM = "Sec Code Cleared"; - -// LED Page -const char pstrUsageNumLock [] PROGMEM = "Num Lock"; -const char pstrUsageCapsLock [] PROGMEM = "Caps Lock"; -const char pstrUsageScrollLock [] PROGMEM = "Scroll Lock"; -const char pstrUsageCompose [] PROGMEM = "Compose"; -const char pstrUsageKana [] PROGMEM = "Kana"; -const char pstrUsagePower [] PROGMEM = "Pwr"; -const char pstrUsageShift [] PROGMEM = "Shift"; -const char pstrUsageDoNotDisturb [] PROGMEM = "DND"; -const char pstrUsageMute [] PROGMEM = "Mute"; -const char pstrUsageToneEnable [] PROGMEM = "Tone Enbl"; -const char pstrUsageHighCutFilter [] PROGMEM = "High Cut Fltr"; -const char pstrUsageLowCutFilter [] PROGMEM = "Low Cut Fltr"; -const char pstrUsageEqualizerEnable [] PROGMEM = "Eq Enbl"; -const char pstrUsageSoundFieldOn [] PROGMEM = "Sound Field On"; -const char pstrUsageSurroundOn [] PROGMEM = "Surround On"; -const char pstrUsageRepeat [] PROGMEM = "Repeat"; -const char pstrUsageStereo [] PROGMEM = "Stereo"; -const char pstrUsageSamplingRateDetect [] PROGMEM = "Smpl Rate Detect"; -const char pstrUsageSpinning [] PROGMEM = "Spinning"; -const char pstrUsageCAV [] PROGMEM = "CAV"; -const char pstrUsageCLV [] PROGMEM = "CLV"; -const char pstrUsageRecordingFormatDetect [] PROGMEM = "Rec Format Detect"; -const char pstrUsageOffHook [] PROGMEM = "Off Hook"; -const char pstrUsageRing [] PROGMEM = "Ring"; -const char pstrUsageMessageWaiting [] PROGMEM = "Msg Wait"; -const char pstrUsageDataMode [] PROGMEM = "Data Mode"; -const char pstrUsageBatteryOperation [] PROGMEM = "Bat Op"; -const char pstrUsageBatteryOK [] PROGMEM = "Bat OK"; -const char pstrUsageBatteryLow [] PROGMEM = "Bat Low"; -const char pstrUsageSpeaker [] PROGMEM = "Speaker"; -const char pstrUsageHeadSet [] PROGMEM = "Head Set"; -const char pstrUsageHold [] PROGMEM = "Hold"; -const char pstrUsageMicrophone [] PROGMEM = "Mic"; -const char pstrUsageCoverage [] PROGMEM = "Coverage"; -const char pstrUsageNightMode [] PROGMEM = "Night Mode"; -const char pstrUsageSendCalls [] PROGMEM = "Send Calls"; -const char pstrUsageCallPickup [] PROGMEM = "Call Pickup"; -const char pstrUsageConference [] PROGMEM = "Conf"; -const char pstrUsageStandBy [] PROGMEM = "Stand-by"; -const char pstrUsageCameraOn [] PROGMEM = "Cam On"; -const char pstrUsageCameraOff [] PROGMEM = "Cam Off"; -const char pstrUsageOnLine [] PROGMEM = "On-Line"; -const char pstrUsageOffLine [] PROGMEM = "Off-Line"; -const char pstrUsageBusy [] PROGMEM = "Busy"; -const char pstrUsageReady [] PROGMEM = "Ready"; -const char pstrUsagePaperOut [] PROGMEM = "Paper Out"; -const char pstrUsagePaperJam [] PROGMEM = "Paper Jam"; -const char pstrUsageRemote [] PROGMEM = "Remote"; -const char pstrUsageForward [] PROGMEM = "Fwd"; -const char pstrUsageReverse [] PROGMEM = "Rev"; -const char pstrUsageStop [] PROGMEM = "Stop"; -const char pstrUsageRewind [] PROGMEM = "Rewind"; -const char pstrUsageFastForward [] PROGMEM = "Fast Fwd"; -const char pstrUsagePlay [] PROGMEM = "Play"; -const char pstrUsagePause [] PROGMEM = "Pause"; -const char pstrUsageRecord [] PROGMEM = "Rec"; -const char pstrUsageError [] PROGMEM = "Error"; -const char pstrUsageSelectedIndicator [] PROGMEM = "Usage Sel Ind"; -const char pstrUsageInUseIndicator [] PROGMEM = "Usage In Use Ind"; -const char pstrUsageMultiModeIndicator [] PROGMEM = "Usage Multi Mode Ind"; -const char pstrUsageIndicatorOn [] PROGMEM = "Ind On"; -const char pstrUsageIndicatorFlash [] PROGMEM = "Ind Flash"; -const char pstrUsageIndicatorSlowBlink [] PROGMEM = "Ind Slow Blk"; -const char pstrUsageIndicatorFastBlink [] PROGMEM = "Ind Fast Blk"; -const char pstrUsageIndicatorOff [] PROGMEM = "Ind Off"; -const char pstrUsageFlashOnTime [] PROGMEM = "Flash On Time"; -const char pstrUsageSlowBlinkOnTime [] PROGMEM = "Slow Blk On Time"; -const char pstrUsageSlowBlinkOffTime [] PROGMEM = "Slow Blk Off Time"; -const char pstrUsageFastBlinkOnTime [] PROGMEM = "Fast Blk On Time"; -const char pstrUsageFastBlinkOffTime [] PROGMEM = "Fast Blk Off Time"; -const char pstrUsageIndicatorColor [] PROGMEM = "Usage Ind Color"; -const char pstrUsageIndicatorRed [] PROGMEM = "Ind Red"; -const char pstrUsageIndicatorGreen [] PROGMEM = "Ind Green"; -const char pstrUsageIndicatorAmber [] PROGMEM = "Ind Amber"; -const char pstrUsageGenericIndicator [] PROGMEM = "Gen Ind"; -const char pstrUsageSystemSuspend [] PROGMEM = "Sys Suspend"; -const char pstrUsageExternalPowerConnected [] PROGMEM = "Ext Pwr Conn"; - -// Telephony Usage Page -const char pstrUsagePhone [] PROGMEM = "Phone"; -const char pstrUsageAnsweringMachine [] PROGMEM = "Answ Mach"; -const char pstrUsageMessageControls [] PROGMEM = "Msg Ctrls"; -const char pstrUsageHandset [] PROGMEM = "Handset"; -const char pstrUsageHeadset [] PROGMEM = "Headset"; -const char pstrUsageTelephonyKeyPad [] PROGMEM = "Tel Key Pad"; -const char pstrUsageProgrammableButton [] PROGMEM = "Prog Button"; -const char pstrUsageHookSwitch [] PROGMEM = "Hook Sw"; -const char pstrUsageFlash [] PROGMEM = "Flash"; -const char pstrUsageFeature [] PROGMEM = "Feature"; -//const char pstrUsageHold [] PROGMEM = "Hold"; -const char pstrUsageRedial [] PROGMEM = "Redial"; -const char pstrUsageTransfer [] PROGMEM = "Transfer"; -const char pstrUsageDrop [] PROGMEM = "Drop"; -const char pstrUsagePark [] PROGMEM = "Park"; -const char pstrUsageForwardCalls [] PROGMEM = "Fwd Calls"; -const char pstrUsageAlternateFunction [] PROGMEM = "Alt Func"; -const char pstrUsageLine [] PROGMEM = "Line"; -const char pstrUsageSpeakerPhone [] PROGMEM = "Spk Phone"; -//const char pstrUsageConference [] PROGMEM = "Conference"; -const char pstrUsageRingEnable [] PROGMEM = "Ring Enbl"; -const char pstrUsageRingSelect [] PROGMEM = "Ring Sel"; -const char pstrUsagePhoneMute [] PROGMEM = "Phone Mute"; -const char pstrUsageCallerID [] PROGMEM = "Caller ID"; -const char pstrUsageSend [] PROGMEM = "Send"; -const char pstrUsageSpeedDial [] PROGMEM = "Speed Dial"; -const char pstrUsageStoreNumber [] PROGMEM = "Store Num"; -const char pstrUsageRecallNumber [] PROGMEM = "Recall Num"; -const char pstrUsagePhoneDirectory [] PROGMEM = "Phone Dir"; -const char pstrUsageVoiceMail [] PROGMEM = "Voice Mail"; -const char pstrUsageScreenCalls [] PROGMEM = "Screen Calls"; -//const char pstrUsageDoNotDisturb [] PROGMEM = "Do Not Disturb"; -const char pstrUsageMessage [] PROGMEM = "Msg"; -const char pstrUsageAnswerOnOff [] PROGMEM = "Answer On/Off"; -const char pstrUsageInsideDialTone [] PROGMEM = "Inside Dial Tone"; -const char pstrUsageOutsideDialTone [] PROGMEM = "Outside Dial Tone"; -const char pstrUsageInsideRingTone [] PROGMEM = "Inside Ring Tone"; -const char pstrUsageOutsideRingTone [] PROGMEM = "Outside Ring Tone"; -const char pstrUsagePriorityRingTone [] PROGMEM = "Prior Ring Tone"; -const char pstrUsageInsideRingback [] PROGMEM = "Inside Ringback"; -const char pstrUsagePriorityRingback [] PROGMEM = "Priority Ringback"; -const char pstrUsageLineBusyTone [] PROGMEM = "Ln Busy Tone"; -const char pstrUsageReorderTone [] PROGMEM = "Reorder Tone"; -const char pstrUsageCallWaitingTone [] PROGMEM = "Call Wait Tone"; -const char pstrUsageConfirmationTone1 [] PROGMEM = "Cnfrm Tone1"; -const char pstrUsageConfirmationTone2 [] PROGMEM = "Cnfrm Tone2"; -const char pstrUsageTonesOff [] PROGMEM = "Tones Off"; -const char pstrUsageOutsideRingback [] PROGMEM = "Outside Ringback"; -const char pstrUsageRinger [] PROGMEM = "Ringer"; -const char pstrUsagePhoneKey0 [] PROGMEM = "0"; -const char pstrUsagePhoneKey1 [] PROGMEM = "1"; -const char pstrUsagePhoneKey2 [] PROGMEM = "2"; -const char pstrUsagePhoneKey3 [] PROGMEM = "3"; -const char pstrUsagePhoneKey4 [] PROGMEM = "4"; -const char pstrUsagePhoneKey5 [] PROGMEM = "5"; -const char pstrUsagePhoneKey6 [] PROGMEM = "6"; -const char pstrUsagePhoneKey7 [] PROGMEM = "7"; -const char pstrUsagePhoneKey8 [] PROGMEM = "8"; -const char pstrUsagePhoneKey9 [] PROGMEM = "9"; -const char pstrUsagePhoneKeyStar [] PROGMEM = "*"; -const char pstrUsagePhoneKeyPound [] PROGMEM = "#"; -const char pstrUsagePhoneKeyA [] PROGMEM = "A"; -const char pstrUsagePhoneKeyB [] PROGMEM = "B"; -const char pstrUsagePhoneKeyC [] PROGMEM = "C"; -const char pstrUsagePhoneKeyD [] PROGMEM = "D"; - -// Consumer Usage Page -const char pstrUsageConsumerControl [] PROGMEM = "Consumer Ctrl"; -const char pstrUsageNumericKeyPad [] PROGMEM = "Num Key Pad"; -//const char pstrUsageProgrammableButton [] PROGMEM = "Prog Btn"; -//const char pstrUsageMicrophone [] PROGMEM = "Mic"; -const char pstrUsageHeadphone [] PROGMEM = "Headphone"; -const char pstrUsageGraphicEqualizer [] PROGMEM = "Graph Eq"; -const char pstrUsagePlus10 [] PROGMEM = "+10"; -const char pstrUsagePlus100 [] PROGMEM = "+100"; -const char pstrUsageAMPM [] PROGMEM = "AM/PM"; -//const char pstrUsagePower [] PROGMEM = "Pwr"; -const char pstrUsageReset [] PROGMEM = "Reset"; -const char pstrUsageSleep [] PROGMEM = "Sleep"; -const char pstrUsageSleepAfter [] PROGMEM = "Sleep After"; -const char pstrUsageSleepMode [] PROGMEM = "Sleep Mode"; -const char pstrUsageIllumination [] PROGMEM = "Illumin"; -const char pstrUsageFunctionButtons [] PROGMEM = "Func Btns"; -const char pstrUsageMenu [] PROGMEM = "Menu"; -const char pstrUsageMenuPick [] PROGMEM = "Menu Pick"; -const char pstrUsageMenuUp [] PROGMEM = "Menu Up"; -const char pstrUsageMenuDown [] PROGMEM = "Menu Down"; -const char pstrUsageMenuLeft [] PROGMEM = "Menu Left"; -const char pstrUsageMenuRight [] PROGMEM = "Menu Right"; -const char pstrUsageMenuEscape [] PROGMEM = "Menu Esc"; -const char pstrUsageMenuValueIncrease [] PROGMEM = "Menu Val Inc"; -const char pstrUsageMenuValueDecrease [] PROGMEM = "Menu Val Dec"; -const char pstrUsageDataOnScreen [] PROGMEM = "Data On Scr"; -const char pstrUsageClosedCaption [] PROGMEM = "Closed Cptn"; -const char pstrUsageClosedCaptionSelect [] PROGMEM = "Closed Cptn Sel"; -const char pstrUsageVCRTV [] PROGMEM = "VCR/TV"; -const char pstrUsageBroadcastMode [] PROGMEM = "Brdcast Mode"; -const char pstrUsageSnapshot [] PROGMEM = "Snapshot"; -const char pstrUsageStill [] PROGMEM = "Still"; -const char pstrUsageSelection [] PROGMEM = "Sel"; -const char pstrUsageAssignSelection [] PROGMEM = "Assign Sel"; -const char pstrUsageModeStep [] PROGMEM = "Mode Step"; -const char pstrUsageRecallLast [] PROGMEM = "Recall Last"; -const char pstrUsageEnterChannel [] PROGMEM = "Entr Channel"; -const char pstrUsageOrderMovie [] PROGMEM = "Ord Movie"; -const char pstrUsageChannel [] PROGMEM = "Channel"; -const char pstrUsageMediaSelection [] PROGMEM = "Med Sel"; -const char pstrUsageMediaSelectComputer [] PROGMEM = "Med Sel Comp"; -const char pstrUsageMediaSelectTV [] PROGMEM = "Med Sel TV"; -const char pstrUsageMediaSelectWWW [] PROGMEM = "Med Sel WWW"; -const char pstrUsageMediaSelectDVD [] PROGMEM = "Med Sel DVD"; -const char pstrUsageMediaSelectTelephone [] PROGMEM = "Med Sel Tel"; -const char pstrUsageMediaSelectProgramGuide [] PROGMEM = "Med Sel PG"; -const char pstrUsageMediaSelectVideoPhone [] PROGMEM = "Med Sel Vid"; -const char pstrUsageMediaSelectGames [] PROGMEM = "Med Sel Games"; -const char pstrUsageMediaSelectMessages [] PROGMEM = "Med Sel Msg"; -const char pstrUsageMediaSelectCD [] PROGMEM = "Med Sel CD"; -const char pstrUsageMediaSelectVCR [] PROGMEM = "Med Sel VCR"; -const char pstrUsageMediaSelectTuner [] PROGMEM = "Med Sel Tuner"; -const char pstrUsageQuit [] PROGMEM = "Quit"; -const char pstrUsageHelp [] PROGMEM = "Help"; -const char pstrUsageMediaSelectTape [] PROGMEM = "Med Sel Tape"; -const char pstrUsageMediaSelectCable [] PROGMEM = "Med Sel Cbl"; -const char pstrUsageMediaSelectSatellite [] PROGMEM = "Med Sel Sat"; -const char pstrUsageMediaSelectSecurity [] PROGMEM = "Med Sel Secur"; -const char pstrUsageMediaSelectHome [] PROGMEM = "Med Sel Home"; -const char pstrUsageMediaSelectCall [] PROGMEM = "Med Sel Call"; -const char pstrUsageChannelIncrement [] PROGMEM = "Ch Inc"; -const char pstrUsageChannelDecrement [] PROGMEM = "Ch Dec"; -const char pstrUsageMediaSelectSAP [] PROGMEM = "Med Sel SAP"; -const char pstrUsageVCRPlus [] PROGMEM = "VCR+"; -const char pstrUsageOnce [] PROGMEM = "Once"; -const char pstrUsageDaily [] PROGMEM = "Daily"; -const char pstrUsageWeekly [] PROGMEM = "Weekly"; -const char pstrUsageMonthly [] PROGMEM = "Monthly"; -//const char pstrUsagePlay [] PROGMEM = "Play"; -//const char pstrUsagePause [] PROGMEM = "Pause"; -//const char pstrUsageRecord [] PROGMEM = "Rec"; -//const char pstrUsageFastForward [] PROGMEM = "FF"; -//const char pstrUsageRewind [] PROGMEM = "Rewind"; -const char pstrUsageScanNextTrack [] PROGMEM = "Next Track"; -const char pstrUsageScanPreviousTrack [] PROGMEM = "Prev Track"; -//const char pstrUsageStop [] PROGMEM = "Stop"; -const char pstrUsageEject [] PROGMEM = "Eject"; -const char pstrUsageRandomPlay [] PROGMEM = "Random"; -const char pstrUsageSelectDisk [] PROGMEM = "Sel Disk"; -const char pstrUsageEnterDisk [] PROGMEM = "Ent Disk"; -//const char pstrUsageRepeat [] PROGMEM = "Repeat"; -const char pstrUsageTracking [] PROGMEM = "Tracking"; -const char pstrUsageTrackNormal [] PROGMEM = "Trk Norm"; -const char pstrUsageSlowTracking [] PROGMEM = "Slow Trk"; -const char pstrUsageFrameForward [] PROGMEM = "Frm Fwd"; -const char pstrUsageFrameBackwards [] PROGMEM = "Frm Back"; -const char pstrUsageMark [] PROGMEM = "Mark"; -const char pstrUsageClearMark [] PROGMEM = "Clr Mark"; -const char pstrUsageRepeatFromMark [] PROGMEM = "Rpt Mark"; -const char pstrUsageReturnToMark [] PROGMEM = "Ret to Mark"; -const char pstrUsageSearchMarkForward [] PROGMEM = "Search Mark Fwd"; -const char pstrUsageSearchMarkBackwards [] PROGMEM = "Search Mark Back"; -const char pstrUsageCounterReset [] PROGMEM = "Counter Reset"; -const char pstrUsageShowCounter [] PROGMEM = "Show Counter"; -const char pstrUsageTrackingIncrement [] PROGMEM = "Track Inc"; -const char pstrUsageTrackingDecrement [] PROGMEM = "Track Dec"; -const char pstrUsageStopEject [] PROGMEM = "Stop/Eject"; -const char pstrUsagePlayPause [] PROGMEM = "Play/Pause"; -const char pstrUsagePlaySkip [] PROGMEM = "Play/Skip"; -const char pstrUsageVolume [] PROGMEM = "Vol"; -const char pstrUsageBalance [] PROGMEM = "Balance"; -//const char pstrUsageMute [] PROGMEM = "Mute"; -const char pstrUsageBass [] PROGMEM = "Bass"; -const char pstrUsageTreble [] PROGMEM = "Treble"; -const char pstrUsageBassBoost [] PROGMEM = "Bass Boost"; -const char pstrUsageSurroundMode [] PROGMEM = "Surround"; -const char pstrUsageLoudness [] PROGMEM = "Loud"; -const char pstrUsageMPX [] PROGMEM = "MPX"; -const char pstrUsageVolumeIncrement [] PROGMEM = "Vol Inc"; -const char pstrUsageVolumeDecrement [] PROGMEM = "Vol Dec"; -const char pstrUsageSpeedSelect [] PROGMEM = "Speed"; -const char pstrUsagePlaybackSpeed [] PROGMEM = "Play Speed"; -const char pstrUsageStandardPlay [] PROGMEM = "Std Play"; -const char pstrUsageLongPlay [] PROGMEM = "Long Play"; -const char pstrUsageExtendedPlay [] PROGMEM = "Ext Play"; -const char pstrUsageSlow [] PROGMEM = "Slow"; -const char pstrUsageFanEnable [] PROGMEM = "Fan Enbl"; -const char pstrUsageFanSpeed [] PROGMEM = "Fan Speed"; -const char pstrUsageLightEnable [] PROGMEM = "Light Enbl"; -const char pstrUsageLightIlluminationLevel [] PROGMEM = "Light Illum Lev"; -const char pstrUsageClimateControlEnable [] PROGMEM = "Climate Enbl"; -const char pstrUsageRoomTemperature [] PROGMEM = "Room Temp"; -const char pstrUsageSecurityEnable [] PROGMEM = "Secur Enbl"; -const char pstrUsageFireAlarm [] PROGMEM = "Fire Alm"; -const char pstrUsagePoliceAlarm [] PROGMEM = "Police Alm"; -const char pstrUsageProximity [] PROGMEM = "Prox"; -const char pstrUsageMotion [] PROGMEM = "Motion"; -const char pstrUsageDuresAlarm [] PROGMEM = "Dures Alm"; -const char pstrUsageHoldupAlarm [] PROGMEM = "Holdup Alm"; -const char pstrUsageMedicalAlarm [] PROGMEM = "Med Alm"; -const char pstrUsageBalanceRight [] PROGMEM = "Balance Right"; -const char pstrUsageBalanceLeft [] PROGMEM = "Balance Left"; -const char pstrUsageBassIncrement [] PROGMEM = "Bass Inc"; -const char pstrUsageBassDecrement [] PROGMEM = "Bass Dec"; -const char pstrUsageTrebleIncrement [] PROGMEM = "Treble Inc"; -const char pstrUsageTrebleDecrement [] PROGMEM = "Treble Dec"; -const char pstrUsageSpeakerSystem [] PROGMEM = "Spk Sys"; -const char pstrUsageChannelLeft [] PROGMEM = "Ch Left"; -const char pstrUsageChannelRight [] PROGMEM = "Ch Right"; -const char pstrUsageChannelCenter [] PROGMEM = "Ch Center"; -const char pstrUsageChannelFront [] PROGMEM = "Ch Front"; -const char pstrUsageChannelCenterFront [] PROGMEM = "Ch Cntr Front"; -const char pstrUsageChannelSide [] PROGMEM = "Ch Side"; -const char pstrUsageChannelSurround [] PROGMEM = "Ch Surround"; -const char pstrUsageChannelLowFreqEnhancement [] PROGMEM = "Ch Low Freq Enh"; -const char pstrUsageChannelTop [] PROGMEM = "Ch Top"; -const char pstrUsageChannelUnknown [] PROGMEM = "Ch Unk"; -const char pstrUsageSubChannel [] PROGMEM = "Sub-ch"; -const char pstrUsageSubChannelIncrement [] PROGMEM = "Sub-ch Inc"; -const char pstrUsageSubChannelDecrement [] PROGMEM = "Sub-ch Dec"; -const char pstrUsageAlternateAudioIncrement [] PROGMEM = "Alt Aud Inc"; -const char pstrUsageAlternateAudioDecrement [] PROGMEM = "Alt Aud Dec"; -const char pstrUsageApplicationLaunchButtons [] PROGMEM = "App Launch Btns"; -const char pstrUsageALLaunchButtonConfigTool [] PROGMEM = "AL Launch Conf Tl"; -const char pstrUsageALProgrammableButton [] PROGMEM = "AL Pgm Btn"; -const char pstrUsageALConsumerControlConfig [] PROGMEM = "AL Cons Ctrl Cfg"; -const char pstrUsageALWordProcessor [] PROGMEM = "AL Word Proc"; -const char pstrUsageALTextEditor [] PROGMEM = "AL Txt Edtr"; -const char pstrUsageALSpreadsheet [] PROGMEM = "AL Sprdsheet"; -const char pstrUsageALGraphicsEditor [] PROGMEM = "AL Graph Edtr"; -const char pstrUsageALPresentationApp [] PROGMEM = "AL Present App"; -const char pstrUsageALDatabaseApp [] PROGMEM = "AL DB App"; -const char pstrUsageALEmailReader [] PROGMEM = "AL E-mail Rdr"; -const char pstrUsageALNewsreader [] PROGMEM = "AL Newsrdr"; -const char pstrUsageALVoicemail [] PROGMEM = "AL Voicemail"; -const char pstrUsageALContactsAddressBook [] PROGMEM = "AL Addr Book"; -const char pstrUsageALCalendarSchedule [] PROGMEM = "AL Clndr/Schdlr"; -const char pstrUsageALTaskProjectManager [] PROGMEM = "AL Task/Prj Mgr"; -const char pstrUsageALLogJournalTimecard [] PROGMEM = "AL Log/Jrnl/Tmcrd"; -const char pstrUsageALCheckbookFinance [] PROGMEM = "AL Chckbook/Fin"; -const char pstrUsageALCalculator [] PROGMEM = "AL Calc"; -const char pstrUsageALAVCapturePlayback [] PROGMEM = "AL A/V Capt/Play"; -const char pstrUsageALLocalMachineBrowser [] PROGMEM = "AL Loc Mach Brow"; -const char pstrUsageALLANWANBrow [] PROGMEM = "AL LAN/WAN Brow"; -const char pstrUsageALInternetBrowser [] PROGMEM = "AL I-net Brow"; -const char pstrUsageALRemoteNetISPConnect [] PROGMEM = "AL Rem Net Con"; -const char pstrUsageALNetworkConference [] PROGMEM = "AL Net Conf"; -const char pstrUsageALNetworkChat [] PROGMEM = "AL Net Chat"; -const char pstrUsageALTelephonyDialer [] PROGMEM = "AL Tel/Dial"; -const char pstrUsageALLogon [] PROGMEM = "AL Logon"; -const char pstrUsageALLogoff [] PROGMEM = "AL Logoff"; -const char pstrUsageALLogonLogoff [] PROGMEM = "AL Logon/Logoff"; -const char pstrUsageALTermLockScrSav [] PROGMEM = "AL Term Lock/Scr Sav"; -const char pstrUsageALControlPannel [] PROGMEM = "AL Ctrl Pan"; -const char pstrUsageALCommandLineProcessorRun [] PROGMEM = "AL Cmd/Run"; -const char pstrUsageALProcessTaskManager [] PROGMEM = "AL Task Mgr"; -const char pstrUsageALSelectTaskApplication [] PROGMEM = "AL Sel App"; -const char pstrUsageALNextTaskApplication [] PROGMEM = "AL Next App"; -const char pstrUsageALPreviousTaskApplication [] PROGMEM = "AL Prev App"; -const char pstrUsageALPreemptiveHaltTaskApp [] PROGMEM = "AL Prmpt Halt App"; -const char pstrUsageALIntegratedHelpCenter [] PROGMEM = "AL Hlp Cntr"; -const char pstrUsageALDocuments [] PROGMEM = "AL Docs"; -const char pstrUsageALThesaurus [] PROGMEM = "AL Thsrs"; -const char pstrUsageALDictionary [] PROGMEM = "AL Dict"; -const char pstrUsageALDesktop [] PROGMEM = "AL Desktop"; -const char pstrUsageALSpellCheck [] PROGMEM = "AL Spell Chk"; -const char pstrUsageALGrammarCheck [] PROGMEM = "AL Gram Chk"; -const char pstrUsageALWirelessStatus [] PROGMEM = "AL Wireless Sts"; -const char pstrUsageALKeyboardLayout [] PROGMEM = "AL Kbd Layout"; -const char pstrUsageALVirusProtection [] PROGMEM = "AL Vir Protect"; -const char pstrUsageALEncryption [] PROGMEM = "AL Encrypt"; -const char pstrUsageALScreenSaver [] PROGMEM = "AL Scr Sav"; -const char pstrUsageALAlarms [] PROGMEM = "AL Alarms"; -const char pstrUsageALClock [] PROGMEM = "AL Clock"; -const char pstrUsageALFileBrowser [] PROGMEM = "AL File Brow"; -const char pstrUsageALPowerStatus [] PROGMEM = "AL Pwr Sts"; -const char pstrUsageALImageBrowser [] PROGMEM = "AL Img Brow"; -const char pstrUsageALAudioBrowser [] PROGMEM = "AL Aud Brow"; -const char pstrUsageALMovieBrowser [] PROGMEM = "AL Mov Brow"; -const char pstrUsageALDigitalRightsManager [] PROGMEM = "AL Dig Rights Mgr"; -const char pstrUsageALDigitalWallet [] PROGMEM = "AL Dig Wallet"; -const char pstrUsageALInstantMessaging [] PROGMEM = "AL Inst Msg"; -const char pstrUsageALOEMFeaturesBrowser [] PROGMEM = "AL OEM Tips Brow"; -const char pstrUsageALOEMHelp [] PROGMEM = "AL OEM Hlp"; -const char pstrUsageALOnlineCommunity [] PROGMEM = "AL Online Com"; -const char pstrUsageALEntertainmentContentBrow [] PROGMEM = "AL Ent Cont Brow"; -const char pstrUsageALOnlineShoppingBrowser [] PROGMEM = "AL Online Shop Brow"; -const char pstrUsageALSmartCardInfoHelp [] PROGMEM = "AL SmartCard Inf"; -const char pstrUsageALMarketMonitorFinBrowser [] PROGMEM = "AL Market Brow"; -const char pstrUsageALCustomCorpNewsBrowser [] PROGMEM = "AL Cust Corp News Brow"; -const char pstrUsageALOnlineActivityBrowser [] PROGMEM = "AL Online Act Brow"; -const char pstrUsageALResearchSearchBrowser [] PROGMEM = "AL Search Brow"; -const char pstrUsageALAudioPlayer [] PROGMEM = "AL Aud Player"; -const char pstrUsageGenericGUIAppControls [] PROGMEM = "Gen GUI App Ctrl"; -const char pstrUsageACNew [] PROGMEM = "AC New"; -const char pstrUsageACOpen [] PROGMEM = "AC Open"; -const char pstrUsageACClose [] PROGMEM = "AC Close"; -const char pstrUsageACExit [] PROGMEM = "AC Exit"; -const char pstrUsageACMaximize [] PROGMEM = "AC Max"; -const char pstrUsageACMinimize [] PROGMEM = "AC Min"; -const char pstrUsageACSave [] PROGMEM = "AC Save"; -const char pstrUsageACPrint [] PROGMEM = "AC Print"; -const char pstrUsageACProperties [] PROGMEM = "AC Prop"; -const char pstrUsageACUndo [] PROGMEM = "AC Undo"; -const char pstrUsageACCopy [] PROGMEM = "AC Copy"; -const char pstrUsageACCut [] PROGMEM = "AC Cut"; -const char pstrUsageACPaste [] PROGMEM = "AC Paste"; -const char pstrUsageACSelectAll [] PROGMEM = "AC Sel All"; -const char pstrUsageACFind [] PROGMEM = "AC Find"; -const char pstrUsageACFindAndReplace [] PROGMEM = "AC Find/Replace"; -const char pstrUsageACSearch [] PROGMEM = "AC Search"; -const char pstrUsageACGoto [] PROGMEM = "AC Goto"; -const char pstrUsageACHome [] PROGMEM = "AC Home"; -const char pstrUsageACBack [] PROGMEM = "AC Back"; -const char pstrUsageACForward [] PROGMEM = "AC Fwd"; -const char pstrUsageACStop [] PROGMEM = "AC Stop"; -const char pstrUsageACRefresh [] PROGMEM = "AC Refresh"; -const char pstrUsageACPreviousLink [] PROGMEM = "AC Prev Link"; -const char pstrUsageACNextLink [] PROGMEM = "AC Next Link"; -const char pstrUsageACBookmarks [] PROGMEM = "AC Bkmarks"; -const char pstrUsageACHistory [] PROGMEM = "AC Hist"; -const char pstrUsageACSubscriptions [] PROGMEM = "AC Subscr"; -const char pstrUsageACZoomIn [] PROGMEM = "AC Zoom In"; -const char pstrUsageACZoomOut [] PROGMEM = "AC Zoom Out"; -const char pstrUsageACZoom [] PROGMEM = "AC Zoom"; -const char pstrUsageACFullScreenView [] PROGMEM = "AC Full Scr"; -const char pstrUsageACNormalView [] PROGMEM = "AC Norm View"; -const char pstrUsageACViewToggle [] PROGMEM = "AC View Tgl"; -const char pstrUsageACScrollUp [] PROGMEM = "AC Scroll Up"; -const char pstrUsageACScrollDown [] PROGMEM = "AC Scroll Down"; -const char pstrUsageACScroll [] PROGMEM = "AC Scroll"; -const char pstrUsageACPanLeft [] PROGMEM = "AC Pan Left"; -const char pstrUsageACPanRight [] PROGMEM = "AC Pan Right"; -const char pstrUsageACPan [] PROGMEM = "AC Pan"; -const char pstrUsageACNewWindow [] PROGMEM = "AC New Wnd"; -const char pstrUsageACTileHoriz [] PROGMEM = "AC Tile Horiz"; -const char pstrUsageACTileVert [] PROGMEM = "AC Tile Vert"; -const char pstrUsageACFormat [] PROGMEM = "AC Frmt"; -const char pstrUsageACEdit [] PROGMEM = "AC Edit"; -const char pstrUsageACBold [] PROGMEM = "AC Bold"; -const char pstrUsageACItalics [] PROGMEM = "AC Ital"; -const char pstrUsageACUnderline [] PROGMEM = "AC Under"; -const char pstrUsageACStrikethrough [] PROGMEM = "AC Strike"; -const char pstrUsageACSubscript [] PROGMEM = "AC Sub"; -const char pstrUsageACSuperscript [] PROGMEM = "AC Super"; -const char pstrUsageACAllCaps [] PROGMEM = "AC All Caps"; -const char pstrUsageACRotate [] PROGMEM = "AC Rotate"; -const char pstrUsageACResize [] PROGMEM = "AC Resize"; -const char pstrUsageACFlipHorizontal [] PROGMEM = "AC Flp H"; -const char pstrUsageACFlipVertical [] PROGMEM = "AC Flp V"; -const char pstrUsageACMirrorHorizontal [] PROGMEM = "AC Mir H"; -const char pstrUsageACMirrorVertical [] PROGMEM = "AC Mir V"; -const char pstrUsageACFontSelect [] PROGMEM = "AC Fnt Sel"; -const char pstrUsageACFontColor [] PROGMEM = "AC Fnt Clr"; -const char pstrUsageACFontSize [] PROGMEM = "AC Fnt Size"; -const char pstrUsageACJustifyLeft [] PROGMEM = "AC Just Left"; -const char pstrUsageACJustifyCenterH [] PROGMEM = "AC Just Cent H"; -const char pstrUsageACJustifyRight [] PROGMEM = "AC Just Right"; -const char pstrUsageACJustifyBlockH [] PROGMEM = "AC Just Block H"; -const char pstrUsageACJustifyTop [] PROGMEM = "AC Just Top"; -const char pstrUsageACJustifyCenterV [] PROGMEM = "AC Just Cent V"; -const char pstrUsageACJustifyBottom [] PROGMEM = "AC Just Bot"; -const char pstrUsageACJustifyBlockV [] PROGMEM = "AC Just Block V"; -const char pstrUsageACIndentDecrease [] PROGMEM = "AC Indent Dec"; -const char pstrUsageACIndentIncrease [] PROGMEM = "AC Indent Inc"; -const char pstrUsageACNumberedList [] PROGMEM = "AC Num List"; -const char pstrUsageACRestartNumbering [] PROGMEM = "AC Res Num"; -const char pstrUsageACBulletedList [] PROGMEM = "AC Blt List"; -const char pstrUsageACPromote [] PROGMEM = "AC Promote"; -const char pstrUsageACDemote [] PROGMEM = "AC Demote"; -const char pstrUsageACYes [] PROGMEM = "AC Yes"; -const char pstrUsageACNo [] PROGMEM = "AC No"; -const char pstrUsageACCancel [] PROGMEM = "AC Cancel"; -const char pstrUsageACCatalog [] PROGMEM = "AC Ctlg"; -const char pstrUsageACBuyChkout [] PROGMEM = "AC Buy"; -const char pstrUsageACAddToCart [] PROGMEM = "AC Add2Cart"; -const char pstrUsageACExpand [] PROGMEM = "AC Xpnd"; -const char pstrUsageACExpandAll [] PROGMEM = "AC Xpand All"; -const char pstrUsageACCollapse [] PROGMEM = "AC Collapse"; -const char pstrUsageACCollapseAll [] PROGMEM = "AC Collapse All"; -const char pstrUsageACPrintPreview [] PROGMEM = "AC Prn Prevw"; -const char pstrUsageACPasteSpecial [] PROGMEM = "AC Paste Spec"; -const char pstrUsageACInsertMode [] PROGMEM = "AC Ins Mode"; -const char pstrUsageACDelete [] PROGMEM = "AC Del"; -const char pstrUsageACLock [] PROGMEM = "AC Lock"; -const char pstrUsageACUnlock [] PROGMEM = "AC Unlock"; -const char pstrUsageACProtect [] PROGMEM = "AC Prot"; -const char pstrUsageACUnprotect [] PROGMEM = "AC Unprot"; -const char pstrUsageACAttachComment [] PROGMEM = "AC Attach Cmnt"; -const char pstrUsageACDeleteComment [] PROGMEM = "AC Del Cmnt"; -const char pstrUsageACViewComment [] PROGMEM = "AC View Cmnt"; -const char pstrUsageACSelectWord [] PROGMEM = "AC Sel Word"; -const char pstrUsageACSelectSentence [] PROGMEM = "AC Sel Sntc"; -const char pstrUsageACSelectParagraph [] PROGMEM = "AC Sel Para"; -const char pstrUsageACSelectColumn [] PROGMEM = "AC Sel Col"; -const char pstrUsageACSelectRow [] PROGMEM = "AC Sel Row"; -const char pstrUsageACSelectTable [] PROGMEM = "AC Sel Tbl"; -const char pstrUsageACSelectObject [] PROGMEM = "AC Sel Obj"; -const char pstrUsageACRedoRepeat [] PROGMEM = "AC Redo"; -const char pstrUsageACSort [] PROGMEM = "AC Sort"; -const char pstrUsageACSortAscending [] PROGMEM = "AC Sort Asc"; -const char pstrUsageACSortDescending [] PROGMEM = "AC Sort Desc"; -const char pstrUsageACFilter [] PROGMEM = "AC Filt"; -const char pstrUsageACSetClock [] PROGMEM = "AC Set Clk"; -const char pstrUsageACViewClock [] PROGMEM = "AC View Clk"; -const char pstrUsageACSelectTimeZone [] PROGMEM = "AC Sel Time Z"; -const char pstrUsageACEditTimeZone [] PROGMEM = "AC Edt Time Z"; -const char pstrUsageACSetAlarm [] PROGMEM = "AC Set Alm"; -const char pstrUsageACClearAlarm [] PROGMEM = "AC Clr Alm"; -const char pstrUsageACSnoozeAlarm [] PROGMEM = "AC Snz Alm"; -const char pstrUsageACResetAlarm [] PROGMEM = "AC Rst Alm"; -const char pstrUsageACSyncronize [] PROGMEM = "AC Sync"; -const char pstrUsageACSendReceive [] PROGMEM = "AC Snd/Rcv"; -const char pstrUsageACSendTo [] PROGMEM = "AC Snd To"; -const char pstrUsageACReply [] PROGMEM = "AC Reply"; -const char pstrUsageACReplyAll [] PROGMEM = "AC Reply All"; -const char pstrUsageACForwardMessage [] PROGMEM = "AC Fwd Msg"; -const char pstrUsageACSend [] PROGMEM = "AC Snd"; -const char pstrUsageACAttachFile [] PROGMEM = "AC Att File"; -const char pstrUsageACUpload [] PROGMEM = "AC Upld"; -const char pstrUsageACDownload [] PROGMEM = "AC Dnld"; -const char pstrUsageACSetBorders [] PROGMEM = "AC Set Brd"; -const char pstrUsageACInsertRow [] PROGMEM = "AC Ins Row"; -const char pstrUsageACInsertColumn [] PROGMEM = "AC Ins Col"; -const char pstrUsageACInsertFile [] PROGMEM = "AC Ins File"; -const char pstrUsageACInsertPicture [] PROGMEM = "AC Ins Pic"; -const char pstrUsageACInsertObject [] PROGMEM = "AC Ins Obj"; -const char pstrUsageACInsertSymbol [] PROGMEM = "AC Ins Sym"; -const char pstrUsageACSaveAndClose [] PROGMEM = "AC Sav&Cls"; -const char pstrUsageACRename [] PROGMEM = "AC Rename"; -const char pstrUsageACMerge [] PROGMEM = "AC Merge"; -const char pstrUsageACSplit [] PROGMEM = "AC Split"; -const char pstrUsageACDistributeHorizontaly [] PROGMEM = "AC Dist Hor"; -const char pstrUsageACDistributeVerticaly [] PROGMEM = "AC Dist Ver"; - -// Digitaizers -const char pstrUsageDigitizer [] PROGMEM = "Digitizer"; -const char pstrUsagePen [] PROGMEM = "Pen"; -const char pstrUsageLightPen [] PROGMEM = "Light Pen"; -const char pstrUsageTouchScreen [] PROGMEM = "Touch Scr"; -const char pstrUsageTouchPad [] PROGMEM = "Touch Pad"; -const char pstrUsageWhiteBoard [] PROGMEM = "White Brd"; -const char pstrUsageCoordinateMeasuringMachine [] PROGMEM = "Coord Meas Mach"; -const char pstrUsage3DDigitizer [] PROGMEM = "3D Dgtz"; -const char pstrUsageStereoPlotter [] PROGMEM = "Stereo Plot"; -const char pstrUsageArticulatedArm [] PROGMEM = "Art Arm"; -const char pstrUsageArmature [] PROGMEM = "Armature"; -const char pstrUsageMultiplePointDigitizer [] PROGMEM = "Multi Point Dgtz"; -const char pstrUsageFreeSpaceWand [] PROGMEM = "Free Space Wand"; -const char pstrUsageStylus [] PROGMEM = "Stylus"; -const char pstrUsagePuck [] PROGMEM = "Puck"; -const char pstrUsageFinger [] PROGMEM = "Finger"; -const char pstrUsageTipPressure [] PROGMEM = "Tip Press"; -const char pstrUsageBarrelPressure [] PROGMEM = "Brl Press"; -const char pstrUsageInRange [] PROGMEM = "In Range"; -const char pstrUsageTouch [] PROGMEM = "Touch"; -const char pstrUsageUntouch [] PROGMEM = "Untouch"; -const char pstrUsageTap [] PROGMEM = "Tap"; -const char pstrUsageQuality [] PROGMEM = "Qlty"; -const char pstrUsageDataValid [] PROGMEM = "Data Valid"; -const char pstrUsageTransducerIndex [] PROGMEM = "Transducer Ind"; -const char pstrUsageTabletFunctionKeys [] PROGMEM = "Tabl Func Keys"; -const char pstrUsageProgramChangeKeys [] PROGMEM = "Pgm Chng Keys"; -//const char pstrUsageBatteryStrength [] PROGMEM = "Bat Strength"; -const char pstrUsageInvert [] PROGMEM = "Invert"; -const char pstrUsageXTilt [] PROGMEM = "X Tilt"; -const char pstrUsageYTilt [] PROGMEM = "Y Tilt"; -const char pstrUsageAzimuth [] PROGMEM = "Azimuth"; -const char pstrUsageAltitude [] PROGMEM = "Altitude"; -const char pstrUsageTwist [] PROGMEM = "Twist"; -const char pstrUsageTipSwitch [] PROGMEM = "Tip Sw"; -const char pstrUsageSecondaryTipSwitch [] PROGMEM = "Scnd Tip Sw"; -const char pstrUsageBarrelSwitch [] PROGMEM = "Brl Sw"; -const char pstrUsageEraser [] PROGMEM = "Eraser"; -const char pstrUsageTabletPick [] PROGMEM = "Tbl Pick"; - -// Alphanumeric Display Page -const char pstrUsageAlphanumericDisplay [] PROGMEM = "Alphanum Disp"; -const char pstrUsageBitmappedDisplay [] PROGMEM = "Bmp Disp"; -const char pstrUsageDisplayAttributesReport [] PROGMEM = "Disp Attr Rpt"; -const char pstrUsageASCIICharacterSet [] PROGMEM = "ASCII chset"; -const char pstrUsageDataReadBack [] PROGMEM = "Data Rd Back"; -const char pstrUsageFontReadBack [] PROGMEM = "Fnt Rd Back"; -const char pstrUsageDisplayControlReport [] PROGMEM = "Disp Ctrl Rpt"; -const char pstrUsageClearDisplay [] PROGMEM = "Clr Disp"; -//const char pstrUsageDisplayEnable [] PROGMEM = "Disp Enbl"; -const char pstrUsageScreenSaverDelay [] PROGMEM = "Scr Sav Delay"; -const char pstrUsageScreenSaverEnable [] PROGMEM = "Scr Sav Enbl"; -const char pstrUsageVerticalScroll [] PROGMEM = "V Scroll"; -const char pstrUsageHorizontalScroll [] PROGMEM = "H Scroll"; -const char pstrUsageCharacterReport [] PROGMEM = "Char Rpt"; -const char pstrUsageDisplayData [] PROGMEM = "Disp Data"; -const char pstrUsageDisplayStatus [] PROGMEM = "Disp Stat"; -const char pstrUsageStatusNotReady [] PROGMEM = "Stat !Ready"; -const char pstrUsageStatusReady [] PROGMEM = "Stat Ready"; -const char pstrUsageErrorNotALoadableCharacter [] PROGMEM = "Err Not Ld Char"; -const char pstrUsageErrorFotDataCanNotBeRead [] PROGMEM = "Fnt Data Rd Err"; -const char pstrUsageCursorPositionReport [] PROGMEM = "Cur Pos Rpt"; -const char pstrUsageRow [] PROGMEM = "Row"; -const char pstrUsageColumn [] PROGMEM = "Col"; -const char pstrUsageRows [] PROGMEM = "Rows"; -const char pstrUsageColumns [] PROGMEM = "Cols"; -const char pstrUsageCursorPixelPosition [] PROGMEM = "Cur Pix Pos"; -const char pstrUsageCursorMode [] PROGMEM = "Cur Mode"; -const char pstrUsageCursorEnable [] PROGMEM = "Cur Enbl"; -const char pstrUsageCursorBlink [] PROGMEM = "Cur Blnk"; -const char pstrUsageFontReport [] PROGMEM = "Fnt Rpt"; -const char pstrUsageFontData [] PROGMEM = "Fnt Data"; -const char pstrUsageCharacterWidth [] PROGMEM = "Char Wdth"; -const char pstrUsageCharacterHeight [] PROGMEM = "Char Hght"; -const char pstrUsageCharacterSpacingHorizontal [] PROGMEM = "Char Space H"; -const char pstrUsageCharacterSpacingVertical [] PROGMEM = "Char Space V"; -const char pstrUsageUnicodeCharset [] PROGMEM = "Unicode Char"; -const char pstrUsageFont7Segment [] PROGMEM = "Fnt 7-seg"; -const char pstrUsage7SegmentDirectMap [] PROGMEM = "7-seg map"; -const char pstrUsageFont14Segment [] PROGMEM = "Fnt 14-seg"; -const char pstrUsage14SegmentDirectMap [] PROGMEM = "14-seg map"; -const char pstrUsageDisplayBrightness [] PROGMEM = "Disp Bright"; -const char pstrUsageDisplayContrast [] PROGMEM = "Disp Cntrst"; -const char pstrUsageCharacterAttribute [] PROGMEM = "Char Attr"; -const char pstrUsageAttributeReadback [] PROGMEM = "Attr Readbk"; -const char pstrUsageAttributeData [] PROGMEM = "Attr Data"; -const char pstrUsageCharAttributeEnhance [] PROGMEM = "Char Attr Enh"; -const char pstrUsageCharAttributeUnderline [] PROGMEM = "Char Attr Undl"; -const char pstrUsageCharAttributeBlink [] PROGMEM = "Char Attr Blnk"; -const char pstrUsageBitmapSizeX [] PROGMEM = "Bmp Size X"; -const char pstrUsageBitmapSizeY [] PROGMEM = "Bmp Size Y"; -const char pstrUsageBitDepthFormat [] PROGMEM = "Bit Dpth Fmt"; -const char pstrUsageDisplayOrientation [] PROGMEM = "Disp Ornt"; -const char pstrUsagePaletteReport [] PROGMEM = "Pal Rpt"; -const char pstrUsagePaletteDataSize [] PROGMEM = "Pal Data Size"; -const char pstrUsagePaletteDataOffset [] PROGMEM = "Pal Data Off"; -const char pstrUsagePaletteData [] PROGMEM = "Pal Data"; -const char pstrUsageBlitReport [] PROGMEM = "Blit Rpt"; -const char pstrUsageBlitRectangleX1 [] PROGMEM = "Blit Rect X1"; -const char pstrUsageBlitRectangleY1 [] PROGMEM = "Blit Rect Y1"; -const char pstrUsageBlitRectangleX2 [] PROGMEM = "Blit Rect X2"; -const char pstrUsageBlitRectangleY2 [] PROGMEM = "Blit Rect Y2"; -const char pstrUsageBlitData [] PROGMEM = "Blit Data"; -const char pstrUsageSoftButton [] PROGMEM = "Soft Btn"; -const char pstrUsageSoftButtonID [] PROGMEM = "Soft Btn ID"; -const char pstrUsageSoftButtonSide [] PROGMEM = "Soft Btn Side"; -const char pstrUsageSoftButtonOffset1 [] PROGMEM = "Soft Btn Off1"; -const char pstrUsageSoftButtonOffset2 [] PROGMEM = "Soft Btn Off2"; -const char pstrUsageSoftButtonReport [] PROGMEM = "Soft Btn Rpt"; - -// Medical Instrument Page -const char pstrUsageMedicalUltrasound [] PROGMEM = "Med Ultrasnd"; -const char pstrUsageVCRAcquisition [] PROGMEM = "VCR/Acq"; -const char pstrUsageFreezeThaw [] PROGMEM = "Freeze"; -const char pstrUsageClipStore [] PROGMEM = "Clip Store"; -const char pstrUsageUpdate [] PROGMEM = "Update"; -const char pstrUsageNext [] PROGMEM = "Next"; -const char pstrUsageSave [] PROGMEM = "Save"; -const char pstrUsagePrint [] PROGMEM = "Print"; -const char pstrUsageMicrophoneEnable [] PROGMEM = "Mic Enbl"; -const char pstrUsageCine [] PROGMEM = "Cine"; -const char pstrUsageTransmitPower [] PROGMEM = "Trans Pwr"; -//const char pstrUsageVolume [] PROGMEM = "Vol"; -const char pstrUsageFocus [] PROGMEM = "Focus"; -const char pstrUsageDepth [] PROGMEM = "Depth"; -const char pstrUsageSoftStepPrimary [] PROGMEM = "Soft Stp-Pri"; -const char pstrUsageSoftStepSecondary [] PROGMEM = "Soft Stp-Sec"; -const char pstrUsageDepthGainCompensation [] PROGMEM = "Dpth Gain Comp"; -const char pstrUsageZoomSelect [] PROGMEM = "Zoom Sel"; -const char pstrUsageZoomAdjust [] PROGMEM = "Zoom Adj"; -const char pstrUsageSpectralDopplerModeSelect [] PROGMEM = "Spec Dop Mode Sel"; -const char pstrUsageSpectralDopplerModeAdjust [] PROGMEM = "Spec Dop Mode Adj"; -const char pstrUsageColorDopplerModeSelect [] PROGMEM = "Color Dop Mode Sel"; -const char pstrUsageColorDopplerModeAdjust [] PROGMEM = "Color Dop Mode Adj"; -const char pstrUsageMotionModeSelect [] PROGMEM = "Motion Mode Sel"; -const char pstrUsageMotionModeAdjust [] PROGMEM = "Motion Mode Adj"; -const char pstrUsage2DModeSelect [] PROGMEM = "2D Mode Sel"; -const char pstrUsage2DModeAdjust [] PROGMEM = "2D Mode Adj"; -const char pstrUsageSoftControlSelect [] PROGMEM = "Soft Ctrl Sel"; -const char pstrUsageSoftControlAdjust [] PROGMEM = "Soft Ctrl Adj"; - -//extern const char *usagePageTitles0[15]; -//const char *usagePageTitles1[]; -//const char *genDesktopTitles0[]; -//const char *genDesktopTitles1[]; -//const char *genDesktopTitles2[]; -//const char *genDesktopTitles3[]; -//const char *genDesktopTitles4[]; -//const char *simuTitles0[]; -//const char *simuTitles1[]; -//const char *simuTitles2[]; -//const char *vrTitles0[]; -//const char *vrTitles1[]; -//const char *sportsCtrlTitles0[]; -//const char *sportsCtrlTitles1[]; -//const char *sportsCtrlTitles2[]; -//const char *gameTitles0[]; -//const char *gameTitles1[]; -//const char *genDevCtrlTitles[]; -//const char *ledTitles[]; -//const char *telTitles0[]; -//const char *telTitles1[]; -//const char *telTitles2[]; -//const char *telTitles3[]; -//const char *telTitles4[]; -//const char *telTitles5[]; -//const char *consTitles0[]; -//const char *consTitles1[]; -//const char *consTitles2[]; -//const char *consTitles3[]; -//const char *consTitles4[]; -//const char *consTitles5[]; -//const char *consTitles6[]; -//const char *consTitles7[]; -//const char *consTitles8[]; -//const char *consTitles9[]; -//const char *consTitlesA[]; -//const char *consTitlesB[]; -//const char *consTitlesC[]; -//const char *consTitlesD[]; -//const char *consTitlesE[]; -//const char *digitTitles0[]; -//const char *digitTitles1[]; -//const char *digitTitles2[]; -//const char *aplphanumTitles0[]; -//const char *aplphanumTitles1[]; -//const char *aplphanumTitles2[]; -//const char *medInstrTitles0[]; -//const char *medInstrTitles1[]; -//const char *medInstrTitles2[]; -//const char *medInstrTitles3[]; -//const char *medInstrTitles4[]; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined( __HIDUSAGESTR_H__) +#define __HIDUSAGESTR_H__ + +#include + +const char pstrSpace [] PROGMEM = " "; +const char pstrCRLF [] PROGMEM = "\r\n"; +const char pstrSingleTab [] PROGMEM = "\t"; +const char pstrDoubleTab [] PROGMEM = "\t\t"; +const char pstrTripleTab [] PROGMEM = "\t\t\t"; + +// Usage Page String Titles +const char pstrUsagePageUndefined [] PROGMEM = "Undef"; +const char pstrUsagePageGenericDesktopControls [] PROGMEM = "Gen Desktop Ctrls"; +const char pstrUsagePageSimulationControls [] PROGMEM = "Simu Ctrls"; +const char pstrUsagePageVRControls [] PROGMEM = "VR Ctrls"; +const char pstrUsagePageSportControls [] PROGMEM = "Sport Ctrls"; +const char pstrUsagePageGameControls [] PROGMEM = "Game Ctrls"; +const char pstrUsagePageGenericDeviceControls [] PROGMEM = "Gen Dev Ctrls"; +const char pstrUsagePageKeyboardKeypad [] PROGMEM = "Kbrd/Keypad"; +const char pstrUsagePageLEDs [] PROGMEM = "LEDs"; +const char pstrUsagePageButton [] PROGMEM = "Button"; +const char pstrUsagePageOrdinal [] PROGMEM = "Ordinal"; +const char pstrUsagePageTelephone [] PROGMEM = "Tel"; +const char pstrUsagePageConsumer [] PROGMEM = "Consumer"; +const char pstrUsagePageDigitizer [] PROGMEM = "Digitizer"; +const char pstrUsagePagePID [] PROGMEM = "PID"; +const char pstrUsagePageUnicode [] PROGMEM = "Unicode"; +const char pstrUsagePageAlphaNumericDisplay [] PROGMEM = "Alpha Num Disp"; +const char pstrUsagePageMedicalInstruments [] PROGMEM = "Medical Instr"; +const char pstrUsagePageMonitor [] PROGMEM = "Monitor"; +const char pstrUsagePagePower [] PROGMEM = "Power"; +const char pstrUsagePageBarCodeScanner [] PROGMEM = "Bar Code Scan"; +const char pstrUsagePageScale [] PROGMEM = "Scale"; +const char pstrUsagePageMSRDevices [] PROGMEM = "Magn Stripe Read Dev"; +const char pstrUsagePagePointOfSale [] PROGMEM = "POS"; +const char pstrUsagePageCameraControl [] PROGMEM = "Cam Ctrl"; +const char pstrUsagePageArcade [] PROGMEM = "Arcade"; +const char pstrUsagePageReserved [] PROGMEM = "Reserved"; +const char pstrUsagePageVendorDefined [] PROGMEM = "Vendor Def"; + +// Generic Desktop Controls Page +const char pstrUsagePointer [] PROGMEM = "Pointer"; +const char pstrUsageMouse [] PROGMEM = "Mouse"; +const char pstrUsageJoystick [] PROGMEM = "Joystick"; +const char pstrUsageGamePad [] PROGMEM = "Game Pad"; +const char pstrUsageKeyboard [] PROGMEM = "Kbrd"; +const char pstrUsageKeypad [] PROGMEM = "Keypad"; +const char pstrUsageMultiAxisController [] PROGMEM = "Multi-axis Ctrl"; +const char pstrUsageTabletPCSystemControls [] PROGMEM = "Tablet PC Sys Ctrls"; +const char pstrUsageX [] PROGMEM = "X"; +const char pstrUsageY [] PROGMEM = "Y"; +const char pstrUsageZ [] PROGMEM = "Z"; +const char pstrUsageRx [] PROGMEM = "Rx"; +const char pstrUsageRy [] PROGMEM = "Ry"; +const char pstrUsageRz [] PROGMEM = "Rz"; +const char pstrUsageSlider [] PROGMEM = "Slider"; +const char pstrUsageDial [] PROGMEM = "Dial"; +const char pstrUsageWheel [] PROGMEM = "Wheel"; +const char pstrUsageHatSwitch [] PROGMEM = "Hat Switch"; +const char pstrUsageCountedBuffer [] PROGMEM = "Counted Buf"; +const char pstrUsageByteCount [] PROGMEM = "Byte Count"; +const char pstrUsageMotionWakeup [] PROGMEM = "Motion Wakeup"; +const char pstrUsageStart [] PROGMEM = "Start"; +const char pstrUsageSelect [] PROGMEM = "Sel"; +const char pstrUsageVx [] PROGMEM = "Vx"; +const char pstrUsageVy [] PROGMEM = "Vy"; +const char pstrUsageVz [] PROGMEM = "Vz"; +const char pstrUsageVbrx [] PROGMEM = "Vbrx"; +const char pstrUsageVbry [] PROGMEM = "Vbry"; +const char pstrUsageVbrz [] PROGMEM = "Vbrz"; +const char pstrUsageVno [] PROGMEM = "Vno"; +const char pstrUsageFeatureNotification [] PROGMEM = "Feature Notif"; +const char pstrUsageResolutionMultiplier [] PROGMEM = "Res Mult"; +const char pstrUsageSystemControl [] PROGMEM = "Sys Ctrl"; +const char pstrUsageSystemPowerDown [] PROGMEM = "Sys Pwr Down"; +const char pstrUsageSystemSleep [] PROGMEM = "Sys Sleep"; +const char pstrUsageSystemWakeup [] PROGMEM = "Sys Wakeup"; +const char pstrUsageSystemContextMenu [] PROGMEM = "Sys Context Menu"; +const char pstrUsageSystemMainMenu [] PROGMEM = "Sys Main Menu"; +const char pstrUsageSystemAppMenu [] PROGMEM = "Sys App Menu"; +const char pstrUsageSystemMenuHelp [] PROGMEM = "Sys Menu Help"; +const char pstrUsageSystemMenuExit [] PROGMEM = "Sys Menu Exit"; +const char pstrUsageSystemMenuSelect [] PROGMEM = "Sys Menu Select"; +const char pstrUsageSystemMenuRight [] PROGMEM = "Sys Menu Right"; +const char pstrUsageSystemMenuLeft [] PROGMEM = "Sys Menu Left"; +const char pstrUsageSystemMenuUp [] PROGMEM = "Sys Menu Up"; +const char pstrUsageSystemMenuDown [] PROGMEM = "Sys Menu Down"; +const char pstrUsageSystemColdRestart [] PROGMEM = "Sys Cold Restart"; +const char pstrUsageSystemWarmRestart [] PROGMEM = "Sys Warm Restart"; +const char pstrUsageDPadUp [] PROGMEM = "D-pad Up"; +const char pstrUsageDPadDown [] PROGMEM = "D-pad Down"; +const char pstrUsageDPadRight [] PROGMEM = "D-pad Right"; +const char pstrUsageDPadLeft [] PROGMEM = "D-pad Left"; +const char pstrUsageSystemDock [] PROGMEM = "Sys Dock"; +const char pstrUsageSystemUndock [] PROGMEM = "Sys Undock"; +const char pstrUsageSystemSetup [] PROGMEM = "Sys Setup"; +const char pstrUsageSystemBreak [] PROGMEM = "Sys Break"; +const char pstrUsageSystemDebuggerBreak [] PROGMEM = "Sys Dbg Brk"; +const char pstrUsageApplicationBreak [] PROGMEM = "App Break"; +const char pstrUsageApplicationDebuggerBreak [] PROGMEM = "App Dbg Brk"; +const char pstrUsageSystemSpeakerMute [] PROGMEM = "Sys Spk Mute"; +const char pstrUsageSystemHibernate [] PROGMEM = "Sys Hiber"; +const char pstrUsageSystemDisplayInvert [] PROGMEM = "Sys Disp Inv"; +const char pstrUsageSystemDisplayInternal [] PROGMEM = "Sys Disp Int"; +const char pstrUsageSystemDisplayExternal [] PROGMEM = "Sys Disp Ext"; +const char pstrUsageSystemDisplayBoth [] PROGMEM = "Sys Disp Both"; +const char pstrUsageSystemDisplayDual [] PROGMEM = "Sys Disp Dual"; +const char pstrUsageSystemDisplayToggleIntExt [] PROGMEM = "Sys Disp Tgl Int/Ext"; +const char pstrUsageSystemDisplaySwapPriSec [] PROGMEM = "Sys Disp Swap Pri/Sec"; +const char pstrUsageSystemDisplayLCDAutoscale [] PROGMEM = "Sys Disp LCD Autoscale"; + +// Simulation Controls Page +const char pstrUsageFlightSimulationDevice [] PROGMEM = "Flight Simu Dev"; +const char pstrUsageAutomobileSimulationDevice [] PROGMEM = "Auto Simu Dev"; +const char pstrUsageTankSimulationDevice [] PROGMEM = "Tank Simu Dev"; +const char pstrUsageSpaceshipSimulationDevice [] PROGMEM = "Space Simu Dev"; +const char pstrUsageSubmarineSimulationDevice [] PROGMEM = "Subm Simu Dev"; +const char pstrUsageSailingSimulationDevice [] PROGMEM = "Sail Simu Dev"; +const char pstrUsageMotocicleSimulationDevice [] PROGMEM = "Moto Simu Dev"; +const char pstrUsageSportsSimulationDevice [] PROGMEM = "Sport Simu Dev"; +const char pstrUsageAirplaneSimulationDevice [] PROGMEM = "Airp Simu Dev"; +const char pstrUsageHelicopterSimulationDevice [] PROGMEM = "Heli Simu Dev"; +const char pstrUsageMagicCarpetSimulationDevice [] PROGMEM = "Magic Carpet Simu Dev"; +const char pstrUsageBicycleSimulationDevice [] PROGMEM = "Bike Simu Dev"; +const char pstrUsageFlightControlStick [] PROGMEM = "Flight Ctrl Stick"; +const char pstrUsageFlightStick [] PROGMEM = "Flight Stick"; +const char pstrUsageCyclicControl [] PROGMEM = "Cyclic Ctrl"; +const char pstrUsageCyclicTrim [] PROGMEM = "Cyclic Trim"; +const char pstrUsageFlightYoke [] PROGMEM = "Flight Yoke"; +const char pstrUsageTrackControl [] PROGMEM = "Track Ctrl"; +const char pstrUsageAileron [] PROGMEM = "Aileron"; +const char pstrUsageAileronTrim [] PROGMEM = "Aileron Trim"; +const char pstrUsageAntiTorqueControl [] PROGMEM = "Anti-Torque Ctrl"; +const char pstrUsageAutopilotEnable [] PROGMEM = "Autopilot Enable"; +const char pstrUsageChaffRelease [] PROGMEM = "Chaff Release"; +const char pstrUsageCollectiveControl [] PROGMEM = "Collective Ctrl"; +const char pstrUsageDiveBrake [] PROGMEM = "Dive Brake"; +const char pstrUsageElectronicCountermeasures [] PROGMEM = "El Countermeasures"; +const char pstrUsageElevator [] PROGMEM = "Elevator"; +const char pstrUsageElevatorTrim [] PROGMEM = "Elevator Trim"; +const char pstrUsageRudder [] PROGMEM = "Rudder"; +const char pstrUsageThrottle [] PROGMEM = "Throttle"; +const char pstrUsageFlightCommunications [] PROGMEM = "Flight Comm"; +const char pstrUsageFlareRelease [] PROGMEM = "Flare Release"; +const char pstrUsageLandingGear [] PROGMEM = "Landing Gear"; +const char pstrUsageToeBrake [] PROGMEM = "Toe Brake"; +const char pstrUsageTrigger [] PROGMEM = "Trigger"; +const char pstrUsageWeaponsArm [] PROGMEM = "Weapons Arm"; +const char pstrUsageWeaponsSelect [] PROGMEM = "Weapons Sel"; +const char pstrUsageWingFlaps [] PROGMEM = "Wing Flaps"; +const char pstrUsageAccelerator [] PROGMEM = "Accel"; +const char pstrUsageBrake [] PROGMEM = "Brake"; +const char pstrUsageClutch [] PROGMEM = "Clutch"; +const char pstrUsageShifter [] PROGMEM = "Shifter"; +const char pstrUsageSteering [] PROGMEM = "Steering"; +const char pstrUsageTurretDirection [] PROGMEM = "Turret Dir"; +const char pstrUsageBarrelElevation [] PROGMEM = "Barrel Ele"; +const char pstrUsageDivePlane [] PROGMEM = "Dive Plane"; +const char pstrUsageBallast [] PROGMEM = "Ballast"; +const char pstrUsageBicycleCrank [] PROGMEM = "Bicycle Crank"; +const char pstrUsageHandleBars [] PROGMEM = "Handle Bars"; +const char pstrUsageFrontBrake [] PROGMEM = "Front Brake"; +const char pstrUsageRearBrake [] PROGMEM = "Rear Brake"; + +// VR Controls Page +const char pstrUsageBelt [] PROGMEM = "Belt"; +const char pstrUsageBodySuit [] PROGMEM = "Body Suit"; +const char pstrUsageFlexor [] PROGMEM = "Flexor"; +const char pstrUsageGlove [] PROGMEM = "Glove"; +const char pstrUsageHeadTracker [] PROGMEM = "Head Track"; +const char pstrUsageHeadMountedDisplay [] PROGMEM = "Head Disp"; +const char pstrUsageHandTracker [] PROGMEM = "Hand Track"; +const char pstrUsageOculometer [] PROGMEM = "Oculometer"; +const char pstrUsageVest [] PROGMEM = "Vest"; +const char pstrUsageAnimatronicDevice [] PROGMEM = "Animat Dev"; +const char pstrUsageStereoEnable [] PROGMEM = "Stereo Enbl"; +const char pstrUsageDisplayEnable [] PROGMEM = "Display Enbl"; + +// Sport Controls Page +const char pstrUsageBaseballBat [] PROGMEM = "Baseball Bat"; +const char pstrUsageGolfClub [] PROGMEM = "Golf Club"; +const char pstrUsageRowingMachine [] PROGMEM = "Rowing Mach"; +const char pstrUsageTreadmill [] PROGMEM = "Treadmill"; +const char pstrUsageOar [] PROGMEM = "Oar"; +const char pstrUsageSlope [] PROGMEM = "Slope"; +const char pstrUsageRate [] PROGMEM = "Rate"; +const char pstrUsageStickSpeed [] PROGMEM = "Stick Speed"; +const char pstrUsageStickFaceAngle [] PROGMEM = "Stick Face Ang"; +const char pstrUsageStickHeelToe [] PROGMEM = "Stick Heel/Toe"; +const char pstrUsageStickFollowThough [] PROGMEM = "Stick Flw Thru"; +const char pstrUsageStickTempo [] PROGMEM = "Stick Tempo"; +const char pstrUsageStickType [] PROGMEM = "Stick Type"; +const char pstrUsageStickHeight [] PROGMEM = "Stick Hght"; +const char pstrUsagePutter [] PROGMEM = "Putter"; +const char pstrUsage1Iron [] PROGMEM = "1 Iron"; +const char pstrUsage2Iron [] PROGMEM = "2 Iron"; +const char pstrUsage3Iron [] PROGMEM = "3 Iron"; +const char pstrUsage4Iron [] PROGMEM = "4 Iron"; +const char pstrUsage5Iron [] PROGMEM = "5 Iron"; +const char pstrUsage6Iron [] PROGMEM = "6 Iron"; +const char pstrUsage7Iron [] PROGMEM = "7 Iron"; +const char pstrUsage8Iron [] PROGMEM = "8 Iron"; +const char pstrUsage9Iron [] PROGMEM = "9 Iron"; +const char pstrUsage10Iron [] PROGMEM = "10 Iron"; +const char pstrUsage11Iron [] PROGMEM = "11 Iron"; +const char pstrUsageSandWedge [] PROGMEM = "Sand Wedge"; +const char pstrUsageLoftWedge [] PROGMEM = "Loft Wedge"; +const char pstrUsagePowerWedge [] PROGMEM = "Pwr Wedge"; +const char pstrUsage1Wood [] PROGMEM = "1 Wood"; +const char pstrUsage3Wood [] PROGMEM = "3 Wood"; +const char pstrUsage5Wood [] PROGMEM = "5 Wood"; +const char pstrUsage7Wood [] PROGMEM = "7 Wood"; +const char pstrUsage9Wood [] PROGMEM = "9 Wood"; + +// Game Controls Page +const char pstrUsage3DGameController [] PROGMEM = "3D Game Ctrl"; +const char pstrUsagePinballDevice [] PROGMEM = "Pinball Dev"; +const char pstrUsageGunDevice [] PROGMEM = "Gun Dev"; +const char pstrUsagePointOfView [] PROGMEM = "POV"; +const char pstrUsageTurnRightLeft [] PROGMEM = "Turn Right Left"; +const char pstrUsagePitchForwardBackward [] PROGMEM = "Pitch Fwd/Back"; +const char pstrUsageRollRightLeft [] PROGMEM = "Roll Right/Left"; +const char pstrUsageMoveRightLeft [] PROGMEM = "Move Right/Left"; +const char pstrUsageMoveForwardBackward [] PROGMEM = "Move Fwd/Back"; +const char pstrUsageMoveUpDown [] PROGMEM = "Move Up/Down"; +const char pstrUsageLeanRightLeft [] PROGMEM = "Lean Right/Left"; +const char pstrUsageLeanForwardBackward [] PROGMEM = "Lean Fwd/Back"; +const char pstrUsageHeightOfPOV [] PROGMEM = "Height of POV"; +const char pstrUsageFlipper [] PROGMEM = "Flipper"; +const char pstrUsageSecondaryFlipper [] PROGMEM = "Second Flipper"; +const char pstrUsageBump [] PROGMEM = "Bump"; +const char pstrUsageNewGame [] PROGMEM = "New Game"; +const char pstrUsageShootBall [] PROGMEM = "Shoot Ball"; +const char pstrUsagePlayer [] PROGMEM = "Player"; +const char pstrUsageGunBolt [] PROGMEM = "Gun Bolt"; +const char pstrUsageGunClip [] PROGMEM = "Gun Clip"; +const char pstrUsageGunSelector [] PROGMEM = "Gun Sel"; +const char pstrUsageGunSingleShot [] PROGMEM = "Gun Sngl Shot"; +const char pstrUsageGunBurst [] PROGMEM = "Gun Burst"; +const char pstrUsageGunAutomatic [] PROGMEM = "Gun Auto"; +const char pstrUsageGunSafety [] PROGMEM = "Gun Safety"; +const char pstrUsageGamepadFireJump [] PROGMEM = "Gamepad Fire/Jump"; +const char pstrUsageGamepadTrigger [] PROGMEM = "Gamepad Trig"; + +// Generic Device Controls Page +const char pstrUsageBatteryStrength [] PROGMEM = "Bat Strength"; +const char pstrUsageWirelessChannel [] PROGMEM = "Wireless Ch"; +const char pstrUsageWirelessID [] PROGMEM = "Wireless ID"; +const char pstrUsageDiscoverWirelessControl [] PROGMEM = "Discover Wireless Ctrl"; +const char pstrUsageSecurityCodeCharEntered [] PROGMEM = "Sec Code Char Entrd"; +const char pstrUsageSecurityCodeCharErased [] PROGMEM = "Sec Code Char Erased"; +const char pstrUsageSecurityCodeCleared [] PROGMEM = "Sec Code Cleared"; + +// LED Page +const char pstrUsageNumLock [] PROGMEM = "Num Lock"; +const char pstrUsageCapsLock [] PROGMEM = "Caps Lock"; +const char pstrUsageScrollLock [] PROGMEM = "Scroll Lock"; +const char pstrUsageCompose [] PROGMEM = "Compose"; +const char pstrUsageKana [] PROGMEM = "Kana"; +const char pstrUsagePower [] PROGMEM = "Pwr"; +const char pstrUsageShift [] PROGMEM = "Shift"; +const char pstrUsageDoNotDisturb [] PROGMEM = "DND"; +const char pstrUsageMute [] PROGMEM = "Mute"; +const char pstrUsageToneEnable [] PROGMEM = "Tone Enbl"; +const char pstrUsageHighCutFilter [] PROGMEM = "High Cut Fltr"; +const char pstrUsageLowCutFilter [] PROGMEM = "Low Cut Fltr"; +const char pstrUsageEqualizerEnable [] PROGMEM = "Eq Enbl"; +const char pstrUsageSoundFieldOn [] PROGMEM = "Sound Field On"; +const char pstrUsageSurroundOn [] PROGMEM = "Surround On"; +const char pstrUsageRepeat [] PROGMEM = "Repeat"; +const char pstrUsageStereo [] PROGMEM = "Stereo"; +const char pstrUsageSamplingRateDetect [] PROGMEM = "Smpl Rate Detect"; +const char pstrUsageSpinning [] PROGMEM = "Spinning"; +const char pstrUsageCAV [] PROGMEM = "CAV"; +const char pstrUsageCLV [] PROGMEM = "CLV"; +const char pstrUsageRecordingFormatDetect [] PROGMEM = "Rec Format Detect"; +const char pstrUsageOffHook [] PROGMEM = "Off Hook"; +const char pstrUsageRing [] PROGMEM = "Ring"; +const char pstrUsageMessageWaiting [] PROGMEM = "Msg Wait"; +const char pstrUsageDataMode [] PROGMEM = "Data Mode"; +const char pstrUsageBatteryOperation [] PROGMEM = "Bat Op"; +const char pstrUsageBatteryOK [] PROGMEM = "Bat OK"; +const char pstrUsageBatteryLow [] PROGMEM = "Bat Low"; +const char pstrUsageSpeaker [] PROGMEM = "Speaker"; +const char pstrUsageHeadSet [] PROGMEM = "Head Set"; +const char pstrUsageHold [] PROGMEM = "Hold"; +const char pstrUsageMicrophone [] PROGMEM = "Mic"; +const char pstrUsageCoverage [] PROGMEM = "Coverage"; +const char pstrUsageNightMode [] PROGMEM = "Night Mode"; +const char pstrUsageSendCalls [] PROGMEM = "Send Calls"; +const char pstrUsageCallPickup [] PROGMEM = "Call Pickup"; +const char pstrUsageConference [] PROGMEM = "Conf"; +const char pstrUsageStandBy [] PROGMEM = "Stand-by"; +const char pstrUsageCameraOn [] PROGMEM = "Cam On"; +const char pstrUsageCameraOff [] PROGMEM = "Cam Off"; +const char pstrUsageOnLine [] PROGMEM = "On-Line"; +const char pstrUsageOffLine [] PROGMEM = "Off-Line"; +const char pstrUsageBusy [] PROGMEM = "Busy"; +const char pstrUsageReady [] PROGMEM = "Ready"; +const char pstrUsagePaperOut [] PROGMEM = "Paper Out"; +const char pstrUsagePaperJam [] PROGMEM = "Paper Jam"; +const char pstrUsageRemote [] PROGMEM = "Remote"; +const char pstrUsageForward [] PROGMEM = "Fwd"; +const char pstrUsageReverse [] PROGMEM = "Rev"; +const char pstrUsageStop [] PROGMEM = "Stop"; +const char pstrUsageRewind [] PROGMEM = "Rewind"; +const char pstrUsageFastForward [] PROGMEM = "Fast Fwd"; +const char pstrUsagePlay [] PROGMEM = "Play"; +const char pstrUsagePause [] PROGMEM = "Pause"; +const char pstrUsageRecord [] PROGMEM = "Rec"; +const char pstrUsageError [] PROGMEM = "Error"; +const char pstrUsageSelectedIndicator [] PROGMEM = "Usage Sel Ind"; +const char pstrUsageInUseIndicator [] PROGMEM = "Usage In Use Ind"; +const char pstrUsageMultiModeIndicator [] PROGMEM = "Usage Multi Mode Ind"; +const char pstrUsageIndicatorOn [] PROGMEM = "Ind On"; +const char pstrUsageIndicatorFlash [] PROGMEM = "Ind Flash"; +const char pstrUsageIndicatorSlowBlink [] PROGMEM = "Ind Slow Blk"; +const char pstrUsageIndicatorFastBlink [] PROGMEM = "Ind Fast Blk"; +const char pstrUsageIndicatorOff [] PROGMEM = "Ind Off"; +const char pstrUsageFlashOnTime [] PROGMEM = "Flash On Time"; +const char pstrUsageSlowBlinkOnTime [] PROGMEM = "Slow Blk On Time"; +const char pstrUsageSlowBlinkOffTime [] PROGMEM = "Slow Blk Off Time"; +const char pstrUsageFastBlinkOnTime [] PROGMEM = "Fast Blk On Time"; +const char pstrUsageFastBlinkOffTime [] PROGMEM = "Fast Blk Off Time"; +const char pstrUsageIndicatorColor [] PROGMEM = "Usage Ind Color"; +const char pstrUsageIndicatorRed [] PROGMEM = "Ind Red"; +const char pstrUsageIndicatorGreen [] PROGMEM = "Ind Green"; +const char pstrUsageIndicatorAmber [] PROGMEM = "Ind Amber"; +const char pstrUsageGenericIndicator [] PROGMEM = "Gen Ind"; +const char pstrUsageSystemSuspend [] PROGMEM = "Sys Suspend"; +const char pstrUsageExternalPowerConnected [] PROGMEM = "Ext Pwr Conn"; + +// Telephony Usage Page +const char pstrUsagePhone [] PROGMEM = "Phone"; +const char pstrUsageAnsweringMachine [] PROGMEM = "Answ Mach"; +const char pstrUsageMessageControls [] PROGMEM = "Msg Ctrls"; +const char pstrUsageHandset [] PROGMEM = "Handset"; +const char pstrUsageHeadset [] PROGMEM = "Headset"; +const char pstrUsageTelephonyKeyPad [] PROGMEM = "Tel Key Pad"; +const char pstrUsageProgrammableButton [] PROGMEM = "Prog Button"; +const char pstrUsageHookSwitch [] PROGMEM = "Hook Sw"; +const char pstrUsageFlash [] PROGMEM = "Flash"; +const char pstrUsageFeature [] PROGMEM = "Feature"; +//const char pstrUsageHold [] PROGMEM = "Hold"; +const char pstrUsageRedial [] PROGMEM = "Redial"; +const char pstrUsageTransfer [] PROGMEM = "Transfer"; +const char pstrUsageDrop [] PROGMEM = "Drop"; +const char pstrUsagePark [] PROGMEM = "Park"; +const char pstrUsageForwardCalls [] PROGMEM = "Fwd Calls"; +const char pstrUsageAlternateFunction [] PROGMEM = "Alt Func"; +const char pstrUsageLine [] PROGMEM = "Line"; +const char pstrUsageSpeakerPhone [] PROGMEM = "Spk Phone"; +//const char pstrUsageConference [] PROGMEM = "Conference"; +const char pstrUsageRingEnable [] PROGMEM = "Ring Enbl"; +const char pstrUsageRingSelect [] PROGMEM = "Ring Sel"; +const char pstrUsagePhoneMute [] PROGMEM = "Phone Mute"; +const char pstrUsageCallerID [] PROGMEM = "Caller ID"; +const char pstrUsageSend [] PROGMEM = "Send"; +const char pstrUsageSpeedDial [] PROGMEM = "Speed Dial"; +const char pstrUsageStoreNumber [] PROGMEM = "Store Num"; +const char pstrUsageRecallNumber [] PROGMEM = "Recall Num"; +const char pstrUsagePhoneDirectory [] PROGMEM = "Phone Dir"; +const char pstrUsageVoiceMail [] PROGMEM = "Voice Mail"; +const char pstrUsageScreenCalls [] PROGMEM = "Screen Calls"; +//const char pstrUsageDoNotDisturb [] PROGMEM = "Do Not Disturb"; +const char pstrUsageMessage [] PROGMEM = "Msg"; +const char pstrUsageAnswerOnOff [] PROGMEM = "Answer On/Off"; +const char pstrUsageInsideDialTone [] PROGMEM = "Inside Dial Tone"; +const char pstrUsageOutsideDialTone [] PROGMEM = "Outside Dial Tone"; +const char pstrUsageInsideRingTone [] PROGMEM = "Inside Ring Tone"; +const char pstrUsageOutsideRingTone [] PROGMEM = "Outside Ring Tone"; +const char pstrUsagePriorityRingTone [] PROGMEM = "Prior Ring Tone"; +const char pstrUsageInsideRingback [] PROGMEM = "Inside Ringback"; +const char pstrUsagePriorityRingback [] PROGMEM = "Priority Ringback"; +const char pstrUsageLineBusyTone [] PROGMEM = "Ln Busy Tone"; +const char pstrUsageReorderTone [] PROGMEM = "Reorder Tone"; +const char pstrUsageCallWaitingTone [] PROGMEM = "Call Wait Tone"; +const char pstrUsageConfirmationTone1 [] PROGMEM = "Cnfrm Tone1"; +const char pstrUsageConfirmationTone2 [] PROGMEM = "Cnfrm Tone2"; +const char pstrUsageTonesOff [] PROGMEM = "Tones Off"; +const char pstrUsageOutsideRingback [] PROGMEM = "Outside Ringback"; +const char pstrUsageRinger [] PROGMEM = "Ringer"; +const char pstrUsagePhoneKey0 [] PROGMEM = "0"; +const char pstrUsagePhoneKey1 [] PROGMEM = "1"; +const char pstrUsagePhoneKey2 [] PROGMEM = "2"; +const char pstrUsagePhoneKey3 [] PROGMEM = "3"; +const char pstrUsagePhoneKey4 [] PROGMEM = "4"; +const char pstrUsagePhoneKey5 [] PROGMEM = "5"; +const char pstrUsagePhoneKey6 [] PROGMEM = "6"; +const char pstrUsagePhoneKey7 [] PROGMEM = "7"; +const char pstrUsagePhoneKey8 [] PROGMEM = "8"; +const char pstrUsagePhoneKey9 [] PROGMEM = "9"; +const char pstrUsagePhoneKeyStar [] PROGMEM = "*"; +const char pstrUsagePhoneKeyPound [] PROGMEM = "#"; +const char pstrUsagePhoneKeyA [] PROGMEM = "A"; +const char pstrUsagePhoneKeyB [] PROGMEM = "B"; +const char pstrUsagePhoneKeyC [] PROGMEM = "C"; +const char pstrUsagePhoneKeyD [] PROGMEM = "D"; + +// Consumer Usage Page +const char pstrUsageConsumerControl [] PROGMEM = "Consumer Ctrl"; +const char pstrUsageNumericKeyPad [] PROGMEM = "Num Key Pad"; +//const char pstrUsageProgrammableButton [] PROGMEM = "Prog Btn"; +//const char pstrUsageMicrophone [] PROGMEM = "Mic"; +const char pstrUsageHeadphone [] PROGMEM = "Headphone"; +const char pstrUsageGraphicEqualizer [] PROGMEM = "Graph Eq"; +const char pstrUsagePlus10 [] PROGMEM = "+10"; +const char pstrUsagePlus100 [] PROGMEM = "+100"; +const char pstrUsageAMPM [] PROGMEM = "AM/PM"; +//const char pstrUsagePower [] PROGMEM = "Pwr"; +const char pstrUsageReset [] PROGMEM = "Reset"; +const char pstrUsageSleep [] PROGMEM = "Sleep"; +const char pstrUsageSleepAfter [] PROGMEM = "Sleep After"; +const char pstrUsageSleepMode [] PROGMEM = "Sleep Mode"; +const char pstrUsageIllumination [] PROGMEM = "Illumin"; +const char pstrUsageFunctionButtons [] PROGMEM = "Func Btns"; +const char pstrUsageMenu [] PROGMEM = "Menu"; +const char pstrUsageMenuPick [] PROGMEM = "Menu Pick"; +const char pstrUsageMenuUp [] PROGMEM = "Menu Up"; +const char pstrUsageMenuDown [] PROGMEM = "Menu Down"; +const char pstrUsageMenuLeft [] PROGMEM = "Menu Left"; +const char pstrUsageMenuRight [] PROGMEM = "Menu Right"; +const char pstrUsageMenuEscape [] PROGMEM = "Menu Esc"; +const char pstrUsageMenuValueIncrease [] PROGMEM = "Menu Val Inc"; +const char pstrUsageMenuValueDecrease [] PROGMEM = "Menu Val Dec"; +const char pstrUsageDataOnScreen [] PROGMEM = "Data On Scr"; +const char pstrUsageClosedCaption [] PROGMEM = "Closed Cptn"; +const char pstrUsageClosedCaptionSelect [] PROGMEM = "Closed Cptn Sel"; +const char pstrUsageVCRTV [] PROGMEM = "VCR/TV"; +const char pstrUsageBroadcastMode [] PROGMEM = "Brdcast Mode"; +const char pstrUsageSnapshot [] PROGMEM = "Snapshot"; +const char pstrUsageStill [] PROGMEM = "Still"; +const char pstrUsageSelection [] PROGMEM = "Sel"; +const char pstrUsageAssignSelection [] PROGMEM = "Assign Sel"; +const char pstrUsageModeStep [] PROGMEM = "Mode Step"; +const char pstrUsageRecallLast [] PROGMEM = "Recall Last"; +const char pstrUsageEnterChannel [] PROGMEM = "Entr Channel"; +const char pstrUsageOrderMovie [] PROGMEM = "Ord Movie"; +const char pstrUsageChannel [] PROGMEM = "Channel"; +const char pstrUsageMediaSelection [] PROGMEM = "Med Sel"; +const char pstrUsageMediaSelectComputer [] PROGMEM = "Med Sel Comp"; +const char pstrUsageMediaSelectTV [] PROGMEM = "Med Sel TV"; +const char pstrUsageMediaSelectWWW [] PROGMEM = "Med Sel WWW"; +const char pstrUsageMediaSelectDVD [] PROGMEM = "Med Sel DVD"; +const char pstrUsageMediaSelectTelephone [] PROGMEM = "Med Sel Tel"; +const char pstrUsageMediaSelectProgramGuide [] PROGMEM = "Med Sel PG"; +const char pstrUsageMediaSelectVideoPhone [] PROGMEM = "Med Sel Vid"; +const char pstrUsageMediaSelectGames [] PROGMEM = "Med Sel Games"; +const char pstrUsageMediaSelectMessages [] PROGMEM = "Med Sel Msg"; +const char pstrUsageMediaSelectCD [] PROGMEM = "Med Sel CD"; +const char pstrUsageMediaSelectVCR [] PROGMEM = "Med Sel VCR"; +const char pstrUsageMediaSelectTuner [] PROGMEM = "Med Sel Tuner"; +const char pstrUsageQuit [] PROGMEM = "Quit"; +const char pstrUsageHelp [] PROGMEM = "Help"; +const char pstrUsageMediaSelectTape [] PROGMEM = "Med Sel Tape"; +const char pstrUsageMediaSelectCable [] PROGMEM = "Med Sel Cbl"; +const char pstrUsageMediaSelectSatellite [] PROGMEM = "Med Sel Sat"; +const char pstrUsageMediaSelectSecurity [] PROGMEM = "Med Sel Secur"; +const char pstrUsageMediaSelectHome [] PROGMEM = "Med Sel Home"; +const char pstrUsageMediaSelectCall [] PROGMEM = "Med Sel Call"; +const char pstrUsageChannelIncrement [] PROGMEM = "Ch Inc"; +const char pstrUsageChannelDecrement [] PROGMEM = "Ch Dec"; +const char pstrUsageMediaSelectSAP [] PROGMEM = "Med Sel SAP"; +const char pstrUsageVCRPlus [] PROGMEM = "VCR+"; +const char pstrUsageOnce [] PROGMEM = "Once"; +const char pstrUsageDaily [] PROGMEM = "Daily"; +const char pstrUsageWeekly [] PROGMEM = "Weekly"; +const char pstrUsageMonthly [] PROGMEM = "Monthly"; +//const char pstrUsagePlay [] PROGMEM = "Play"; +//const char pstrUsagePause [] PROGMEM = "Pause"; +//const char pstrUsageRecord [] PROGMEM = "Rec"; +//const char pstrUsageFastForward [] PROGMEM = "FF"; +//const char pstrUsageRewind [] PROGMEM = "Rewind"; +const char pstrUsageScanNextTrack [] PROGMEM = "Next Track"; +const char pstrUsageScanPreviousTrack [] PROGMEM = "Prev Track"; +//const char pstrUsageStop [] PROGMEM = "Stop"; +const char pstrUsageEject [] PROGMEM = "Eject"; +const char pstrUsageRandomPlay [] PROGMEM = "Random"; +const char pstrUsageSelectDisk [] PROGMEM = "Sel Disk"; +const char pstrUsageEnterDisk [] PROGMEM = "Ent Disk"; +//const char pstrUsageRepeat [] PROGMEM = "Repeat"; +const char pstrUsageTracking [] PROGMEM = "Tracking"; +const char pstrUsageTrackNormal [] PROGMEM = "Trk Norm"; +const char pstrUsageSlowTracking [] PROGMEM = "Slow Trk"; +const char pstrUsageFrameForward [] PROGMEM = "Frm Fwd"; +const char pstrUsageFrameBackwards [] PROGMEM = "Frm Back"; +const char pstrUsageMark [] PROGMEM = "Mark"; +const char pstrUsageClearMark [] PROGMEM = "Clr Mark"; +const char pstrUsageRepeatFromMark [] PROGMEM = "Rpt Mark"; +const char pstrUsageReturnToMark [] PROGMEM = "Ret to Mark"; +const char pstrUsageSearchMarkForward [] PROGMEM = "Search Mark Fwd"; +const char pstrUsageSearchMarkBackwards [] PROGMEM = "Search Mark Back"; +const char pstrUsageCounterReset [] PROGMEM = "Counter Reset"; +const char pstrUsageShowCounter [] PROGMEM = "Show Counter"; +const char pstrUsageTrackingIncrement [] PROGMEM = "Track Inc"; +const char pstrUsageTrackingDecrement [] PROGMEM = "Track Dec"; +const char pstrUsageStopEject [] PROGMEM = "Stop/Eject"; +const char pstrUsagePlayPause [] PROGMEM = "Play/Pause"; +const char pstrUsagePlaySkip [] PROGMEM = "Play/Skip"; +const char pstrUsageVolume [] PROGMEM = "Vol"; +const char pstrUsageBalance [] PROGMEM = "Balance"; +//const char pstrUsageMute [] PROGMEM = "Mute"; +const char pstrUsageBass [] PROGMEM = "Bass"; +const char pstrUsageTreble [] PROGMEM = "Treble"; +const char pstrUsageBassBoost [] PROGMEM = "Bass Boost"; +const char pstrUsageSurroundMode [] PROGMEM = "Surround"; +const char pstrUsageLoudness [] PROGMEM = "Loud"; +const char pstrUsageMPX [] PROGMEM = "MPX"; +const char pstrUsageVolumeIncrement [] PROGMEM = "Vol Inc"; +const char pstrUsageVolumeDecrement [] PROGMEM = "Vol Dec"; +const char pstrUsageSpeedSelect [] PROGMEM = "Speed"; +const char pstrUsagePlaybackSpeed [] PROGMEM = "Play Speed"; +const char pstrUsageStandardPlay [] PROGMEM = "Std Play"; +const char pstrUsageLongPlay [] PROGMEM = "Long Play"; +const char pstrUsageExtendedPlay [] PROGMEM = "Ext Play"; +const char pstrUsageSlow [] PROGMEM = "Slow"; +const char pstrUsageFanEnable [] PROGMEM = "Fan Enbl"; +const char pstrUsageFanSpeed [] PROGMEM = "Fan Speed"; +const char pstrUsageLightEnable [] PROGMEM = "Light Enbl"; +const char pstrUsageLightIlluminationLevel [] PROGMEM = "Light Illum Lev"; +const char pstrUsageClimateControlEnable [] PROGMEM = "Climate Enbl"; +const char pstrUsageRoomTemperature [] PROGMEM = "Room Temp"; +const char pstrUsageSecurityEnable [] PROGMEM = "Secur Enbl"; +const char pstrUsageFireAlarm [] PROGMEM = "Fire Alm"; +const char pstrUsagePoliceAlarm [] PROGMEM = "Police Alm"; +const char pstrUsageProximity [] PROGMEM = "Prox"; +const char pstrUsageMotion [] PROGMEM = "Motion"; +const char pstrUsageDuresAlarm [] PROGMEM = "Dures Alm"; +const char pstrUsageHoldupAlarm [] PROGMEM = "Holdup Alm"; +const char pstrUsageMedicalAlarm [] PROGMEM = "Med Alm"; +const char pstrUsageBalanceRight [] PROGMEM = "Balance Right"; +const char pstrUsageBalanceLeft [] PROGMEM = "Balance Left"; +const char pstrUsageBassIncrement [] PROGMEM = "Bass Inc"; +const char pstrUsageBassDecrement [] PROGMEM = "Bass Dec"; +const char pstrUsageTrebleIncrement [] PROGMEM = "Treble Inc"; +const char pstrUsageTrebleDecrement [] PROGMEM = "Treble Dec"; +const char pstrUsageSpeakerSystem [] PROGMEM = "Spk Sys"; +const char pstrUsageChannelLeft [] PROGMEM = "Ch Left"; +const char pstrUsageChannelRight [] PROGMEM = "Ch Right"; +const char pstrUsageChannelCenter [] PROGMEM = "Ch Center"; +const char pstrUsageChannelFront [] PROGMEM = "Ch Front"; +const char pstrUsageChannelCenterFront [] PROGMEM = "Ch Cntr Front"; +const char pstrUsageChannelSide [] PROGMEM = "Ch Side"; +const char pstrUsageChannelSurround [] PROGMEM = "Ch Surround"; +const char pstrUsageChannelLowFreqEnhancement [] PROGMEM = "Ch Low Freq Enh"; +const char pstrUsageChannelTop [] PROGMEM = "Ch Top"; +const char pstrUsageChannelUnknown [] PROGMEM = "Ch Unk"; +const char pstrUsageSubChannel [] PROGMEM = "Sub-ch"; +const char pstrUsageSubChannelIncrement [] PROGMEM = "Sub-ch Inc"; +const char pstrUsageSubChannelDecrement [] PROGMEM = "Sub-ch Dec"; +const char pstrUsageAlternateAudioIncrement [] PROGMEM = "Alt Aud Inc"; +const char pstrUsageAlternateAudioDecrement [] PROGMEM = "Alt Aud Dec"; +const char pstrUsageApplicationLaunchButtons [] PROGMEM = "App Launch Btns"; +const char pstrUsageALLaunchButtonConfigTool [] PROGMEM = "AL Launch Conf Tl"; +const char pstrUsageALProgrammableButton [] PROGMEM = "AL Pgm Btn"; +const char pstrUsageALConsumerControlConfig [] PROGMEM = "AL Cons Ctrl Cfg"; +const char pstrUsageALWordProcessor [] PROGMEM = "AL Word Proc"; +const char pstrUsageALTextEditor [] PROGMEM = "AL Txt Edtr"; +const char pstrUsageALSpreadsheet [] PROGMEM = "AL Sprdsheet"; +const char pstrUsageALGraphicsEditor [] PROGMEM = "AL Graph Edtr"; +const char pstrUsageALPresentationApp [] PROGMEM = "AL Present App"; +const char pstrUsageALDatabaseApp [] PROGMEM = "AL DB App"; +const char pstrUsageALEmailReader [] PROGMEM = "AL E-mail Rdr"; +const char pstrUsageALNewsreader [] PROGMEM = "AL Newsrdr"; +const char pstrUsageALVoicemail [] PROGMEM = "AL Voicemail"; +const char pstrUsageALContactsAddressBook [] PROGMEM = "AL Addr Book"; +const char pstrUsageALCalendarSchedule [] PROGMEM = "AL Clndr/Schdlr"; +const char pstrUsageALTaskProjectManager [] PROGMEM = "AL Task/Prj Mgr"; +const char pstrUsageALLogJournalTimecard [] PROGMEM = "AL Log/Jrnl/Tmcrd"; +const char pstrUsageALCheckbookFinance [] PROGMEM = "AL Chckbook/Fin"; +const char pstrUsageALCalculator [] PROGMEM = "AL Calc"; +const char pstrUsageALAVCapturePlayback [] PROGMEM = "AL A/V Capt/Play"; +const char pstrUsageALLocalMachineBrowser [] PROGMEM = "AL Loc Mach Brow"; +const char pstrUsageALLANWANBrow [] PROGMEM = "AL LAN/WAN Brow"; +const char pstrUsageALInternetBrowser [] PROGMEM = "AL I-net Brow"; +const char pstrUsageALRemoteNetISPConnect [] PROGMEM = "AL Rem Net Con"; +const char pstrUsageALNetworkConference [] PROGMEM = "AL Net Conf"; +const char pstrUsageALNetworkChat [] PROGMEM = "AL Net Chat"; +const char pstrUsageALTelephonyDialer [] PROGMEM = "AL Tel/Dial"; +const char pstrUsageALLogon [] PROGMEM = "AL Logon"; +const char pstrUsageALLogoff [] PROGMEM = "AL Logoff"; +const char pstrUsageALLogonLogoff [] PROGMEM = "AL Logon/Logoff"; +const char pstrUsageALTermLockScrSav [] PROGMEM = "AL Term Lock/Scr Sav"; +const char pstrUsageALControlPannel [] PROGMEM = "AL Ctrl Pan"; +const char pstrUsageALCommandLineProcessorRun [] PROGMEM = "AL Cmd/Run"; +const char pstrUsageALProcessTaskManager [] PROGMEM = "AL Task Mgr"; +const char pstrUsageALSelectTaskApplication [] PROGMEM = "AL Sel App"; +const char pstrUsageALNextTaskApplication [] PROGMEM = "AL Next App"; +const char pstrUsageALPreviousTaskApplication [] PROGMEM = "AL Prev App"; +const char pstrUsageALPreemptiveHaltTaskApp [] PROGMEM = "AL Prmpt Halt App"; +const char pstrUsageALIntegratedHelpCenter [] PROGMEM = "AL Hlp Cntr"; +const char pstrUsageALDocuments [] PROGMEM = "AL Docs"; +const char pstrUsageALThesaurus [] PROGMEM = "AL Thsrs"; +const char pstrUsageALDictionary [] PROGMEM = "AL Dict"; +const char pstrUsageALDesktop [] PROGMEM = "AL Desktop"; +const char pstrUsageALSpellCheck [] PROGMEM = "AL Spell Chk"; +const char pstrUsageALGrammarCheck [] PROGMEM = "AL Gram Chk"; +const char pstrUsageALWirelessStatus [] PROGMEM = "AL Wireless Sts"; +const char pstrUsageALKeyboardLayout [] PROGMEM = "AL Kbd Layout"; +const char pstrUsageALVirusProtection [] PROGMEM = "AL Vir Protect"; +const char pstrUsageALEncryption [] PROGMEM = "AL Encrypt"; +const char pstrUsageALScreenSaver [] PROGMEM = "AL Scr Sav"; +const char pstrUsageALAlarms [] PROGMEM = "AL Alarms"; +const char pstrUsageALClock [] PROGMEM = "AL Clock"; +const char pstrUsageALFileBrowser [] PROGMEM = "AL File Brow"; +const char pstrUsageALPowerStatus [] PROGMEM = "AL Pwr Sts"; +const char pstrUsageALImageBrowser [] PROGMEM = "AL Img Brow"; +const char pstrUsageALAudioBrowser [] PROGMEM = "AL Aud Brow"; +const char pstrUsageALMovieBrowser [] PROGMEM = "AL Mov Brow"; +const char pstrUsageALDigitalRightsManager [] PROGMEM = "AL Dig Rights Mgr"; +const char pstrUsageALDigitalWallet [] PROGMEM = "AL Dig Wallet"; +const char pstrUsageALInstantMessaging [] PROGMEM = "AL Inst Msg"; +const char pstrUsageALOEMFeaturesBrowser [] PROGMEM = "AL OEM Tips Brow"; +const char pstrUsageALOEMHelp [] PROGMEM = "AL OEM Hlp"; +const char pstrUsageALOnlineCommunity [] PROGMEM = "AL Online Com"; +const char pstrUsageALEntertainmentContentBrow [] PROGMEM = "AL Ent Cont Brow"; +const char pstrUsageALOnlineShoppingBrowser [] PROGMEM = "AL Online Shop Brow"; +const char pstrUsageALSmartCardInfoHelp [] PROGMEM = "AL SmartCard Inf"; +const char pstrUsageALMarketMonitorFinBrowser [] PROGMEM = "AL Market Brow"; +const char pstrUsageALCustomCorpNewsBrowser [] PROGMEM = "AL Cust Corp News Brow"; +const char pstrUsageALOnlineActivityBrowser [] PROGMEM = "AL Online Act Brow"; +const char pstrUsageALResearchSearchBrowser [] PROGMEM = "AL Search Brow"; +const char pstrUsageALAudioPlayer [] PROGMEM = "AL Aud Player"; +const char pstrUsageGenericGUIAppControls [] PROGMEM = "Gen GUI App Ctrl"; +const char pstrUsageACNew [] PROGMEM = "AC New"; +const char pstrUsageACOpen [] PROGMEM = "AC Open"; +const char pstrUsageACClose [] PROGMEM = "AC Close"; +const char pstrUsageACExit [] PROGMEM = "AC Exit"; +const char pstrUsageACMaximize [] PROGMEM = "AC Max"; +const char pstrUsageACMinimize [] PROGMEM = "AC Min"; +const char pstrUsageACSave [] PROGMEM = "AC Save"; +const char pstrUsageACPrint [] PROGMEM = "AC Print"; +const char pstrUsageACProperties [] PROGMEM = "AC Prop"; +const char pstrUsageACUndo [] PROGMEM = "AC Undo"; +const char pstrUsageACCopy [] PROGMEM = "AC Copy"; +const char pstrUsageACCut [] PROGMEM = "AC Cut"; +const char pstrUsageACPaste [] PROGMEM = "AC Paste"; +const char pstrUsageACSelectAll [] PROGMEM = "AC Sel All"; +const char pstrUsageACFind [] PROGMEM = "AC Find"; +const char pstrUsageACFindAndReplace [] PROGMEM = "AC Find/Replace"; +const char pstrUsageACSearch [] PROGMEM = "AC Search"; +const char pstrUsageACGoto [] PROGMEM = "AC Goto"; +const char pstrUsageACHome [] PROGMEM = "AC Home"; +const char pstrUsageACBack [] PROGMEM = "AC Back"; +const char pstrUsageACForward [] PROGMEM = "AC Fwd"; +const char pstrUsageACStop [] PROGMEM = "AC Stop"; +const char pstrUsageACRefresh [] PROGMEM = "AC Refresh"; +const char pstrUsageACPreviousLink [] PROGMEM = "AC Prev Link"; +const char pstrUsageACNextLink [] PROGMEM = "AC Next Link"; +const char pstrUsageACBookmarks [] PROGMEM = "AC Bkmarks"; +const char pstrUsageACHistory [] PROGMEM = "AC Hist"; +const char pstrUsageACSubscriptions [] PROGMEM = "AC Subscr"; +const char pstrUsageACZoomIn [] PROGMEM = "AC Zoom In"; +const char pstrUsageACZoomOut [] PROGMEM = "AC Zoom Out"; +const char pstrUsageACZoom [] PROGMEM = "AC Zoom"; +const char pstrUsageACFullScreenView [] PROGMEM = "AC Full Scr"; +const char pstrUsageACNormalView [] PROGMEM = "AC Norm View"; +const char pstrUsageACViewToggle [] PROGMEM = "AC View Tgl"; +const char pstrUsageACScrollUp [] PROGMEM = "AC Scroll Up"; +const char pstrUsageACScrollDown [] PROGMEM = "AC Scroll Down"; +const char pstrUsageACScroll [] PROGMEM = "AC Scroll"; +const char pstrUsageACPanLeft [] PROGMEM = "AC Pan Left"; +const char pstrUsageACPanRight [] PROGMEM = "AC Pan Right"; +const char pstrUsageACPan [] PROGMEM = "AC Pan"; +const char pstrUsageACNewWindow [] PROGMEM = "AC New Wnd"; +const char pstrUsageACTileHoriz [] PROGMEM = "AC Tile Horiz"; +const char pstrUsageACTileVert [] PROGMEM = "AC Tile Vert"; +const char pstrUsageACFormat [] PROGMEM = "AC Frmt"; +const char pstrUsageACEdit [] PROGMEM = "AC Edit"; +const char pstrUsageACBold [] PROGMEM = "AC Bold"; +const char pstrUsageACItalics [] PROGMEM = "AC Ital"; +const char pstrUsageACUnderline [] PROGMEM = "AC Under"; +const char pstrUsageACStrikethrough [] PROGMEM = "AC Strike"; +const char pstrUsageACSubscript [] PROGMEM = "AC Sub"; +const char pstrUsageACSuperscript [] PROGMEM = "AC Super"; +const char pstrUsageACAllCaps [] PROGMEM = "AC All Caps"; +const char pstrUsageACRotate [] PROGMEM = "AC Rotate"; +const char pstrUsageACResize [] PROGMEM = "AC Resize"; +const char pstrUsageACFlipHorizontal [] PROGMEM = "AC Flp H"; +const char pstrUsageACFlipVertical [] PROGMEM = "AC Flp V"; +const char pstrUsageACMirrorHorizontal [] PROGMEM = "AC Mir H"; +const char pstrUsageACMirrorVertical [] PROGMEM = "AC Mir V"; +const char pstrUsageACFontSelect [] PROGMEM = "AC Fnt Sel"; +const char pstrUsageACFontColor [] PROGMEM = "AC Fnt Clr"; +const char pstrUsageACFontSize [] PROGMEM = "AC Fnt Size"; +const char pstrUsageACJustifyLeft [] PROGMEM = "AC Just Left"; +const char pstrUsageACJustifyCenterH [] PROGMEM = "AC Just Cent H"; +const char pstrUsageACJustifyRight [] PROGMEM = "AC Just Right"; +const char pstrUsageACJustifyBlockH [] PROGMEM = "AC Just Block H"; +const char pstrUsageACJustifyTop [] PROGMEM = "AC Just Top"; +const char pstrUsageACJustifyCenterV [] PROGMEM = "AC Just Cent V"; +const char pstrUsageACJustifyBottom [] PROGMEM = "AC Just Bot"; +const char pstrUsageACJustifyBlockV [] PROGMEM = "AC Just Block V"; +const char pstrUsageACIndentDecrease [] PROGMEM = "AC Indent Dec"; +const char pstrUsageACIndentIncrease [] PROGMEM = "AC Indent Inc"; +const char pstrUsageACNumberedList [] PROGMEM = "AC Num List"; +const char pstrUsageACRestartNumbering [] PROGMEM = "AC Res Num"; +const char pstrUsageACBulletedList [] PROGMEM = "AC Blt List"; +const char pstrUsageACPromote [] PROGMEM = "AC Promote"; +const char pstrUsageACDemote [] PROGMEM = "AC Demote"; +const char pstrUsageACYes [] PROGMEM = "AC Yes"; +const char pstrUsageACNo [] PROGMEM = "AC No"; +const char pstrUsageACCancel [] PROGMEM = "AC Cancel"; +const char pstrUsageACCatalog [] PROGMEM = "AC Ctlg"; +const char pstrUsageACBuyChkout [] PROGMEM = "AC Buy"; +const char pstrUsageACAddToCart [] PROGMEM = "AC Add2Cart"; +const char pstrUsageACExpand [] PROGMEM = "AC Xpnd"; +const char pstrUsageACExpandAll [] PROGMEM = "AC Xpand All"; +const char pstrUsageACCollapse [] PROGMEM = "AC Collapse"; +const char pstrUsageACCollapseAll [] PROGMEM = "AC Collapse All"; +const char pstrUsageACPrintPreview [] PROGMEM = "AC Prn Prevw"; +const char pstrUsageACPasteSpecial [] PROGMEM = "AC Paste Spec"; +const char pstrUsageACInsertMode [] PROGMEM = "AC Ins Mode"; +const char pstrUsageACDelete [] PROGMEM = "AC Del"; +const char pstrUsageACLock [] PROGMEM = "AC Lock"; +const char pstrUsageACUnlock [] PROGMEM = "AC Unlock"; +const char pstrUsageACProtect [] PROGMEM = "AC Prot"; +const char pstrUsageACUnprotect [] PROGMEM = "AC Unprot"; +const char pstrUsageACAttachComment [] PROGMEM = "AC Attach Cmnt"; +const char pstrUsageACDeleteComment [] PROGMEM = "AC Del Cmnt"; +const char pstrUsageACViewComment [] PROGMEM = "AC View Cmnt"; +const char pstrUsageACSelectWord [] PROGMEM = "AC Sel Word"; +const char pstrUsageACSelectSentence [] PROGMEM = "AC Sel Sntc"; +const char pstrUsageACSelectParagraph [] PROGMEM = "AC Sel Para"; +const char pstrUsageACSelectColumn [] PROGMEM = "AC Sel Col"; +const char pstrUsageACSelectRow [] PROGMEM = "AC Sel Row"; +const char pstrUsageACSelectTable [] PROGMEM = "AC Sel Tbl"; +const char pstrUsageACSelectObject [] PROGMEM = "AC Sel Obj"; +const char pstrUsageACRedoRepeat [] PROGMEM = "AC Redo"; +const char pstrUsageACSort [] PROGMEM = "AC Sort"; +const char pstrUsageACSortAscending [] PROGMEM = "AC Sort Asc"; +const char pstrUsageACSortDescending [] PROGMEM = "AC Sort Desc"; +const char pstrUsageACFilter [] PROGMEM = "AC Filt"; +const char pstrUsageACSetClock [] PROGMEM = "AC Set Clk"; +const char pstrUsageACViewClock [] PROGMEM = "AC View Clk"; +const char pstrUsageACSelectTimeZone [] PROGMEM = "AC Sel Time Z"; +const char pstrUsageACEditTimeZone [] PROGMEM = "AC Edt Time Z"; +const char pstrUsageACSetAlarm [] PROGMEM = "AC Set Alm"; +const char pstrUsageACClearAlarm [] PROGMEM = "AC Clr Alm"; +const char pstrUsageACSnoozeAlarm [] PROGMEM = "AC Snz Alm"; +const char pstrUsageACResetAlarm [] PROGMEM = "AC Rst Alm"; +const char pstrUsageACSyncronize [] PROGMEM = "AC Sync"; +const char pstrUsageACSendReceive [] PROGMEM = "AC Snd/Rcv"; +const char pstrUsageACSendTo [] PROGMEM = "AC Snd To"; +const char pstrUsageACReply [] PROGMEM = "AC Reply"; +const char pstrUsageACReplyAll [] PROGMEM = "AC Reply All"; +const char pstrUsageACForwardMessage [] PROGMEM = "AC Fwd Msg"; +const char pstrUsageACSend [] PROGMEM = "AC Snd"; +const char pstrUsageACAttachFile [] PROGMEM = "AC Att File"; +const char pstrUsageACUpload [] PROGMEM = "AC Upld"; +const char pstrUsageACDownload [] PROGMEM = "AC Dnld"; +const char pstrUsageACSetBorders [] PROGMEM = "AC Set Brd"; +const char pstrUsageACInsertRow [] PROGMEM = "AC Ins Row"; +const char pstrUsageACInsertColumn [] PROGMEM = "AC Ins Col"; +const char pstrUsageACInsertFile [] PROGMEM = "AC Ins File"; +const char pstrUsageACInsertPicture [] PROGMEM = "AC Ins Pic"; +const char pstrUsageACInsertObject [] PROGMEM = "AC Ins Obj"; +const char pstrUsageACInsertSymbol [] PROGMEM = "AC Ins Sym"; +const char pstrUsageACSaveAndClose [] PROGMEM = "AC Sav&Cls"; +const char pstrUsageACRename [] PROGMEM = "AC Rename"; +const char pstrUsageACMerge [] PROGMEM = "AC Merge"; +const char pstrUsageACSplit [] PROGMEM = "AC Split"; +const char pstrUsageACDistributeHorizontaly [] PROGMEM = "AC Dist Hor"; +const char pstrUsageACDistributeVerticaly [] PROGMEM = "AC Dist Ver"; + +// Digitaizers +const char pstrUsageDigitizer [] PROGMEM = "Digitizer"; +const char pstrUsagePen [] PROGMEM = "Pen"; +const char pstrUsageLightPen [] PROGMEM = "Light Pen"; +const char pstrUsageTouchScreen [] PROGMEM = "Touch Scr"; +const char pstrUsageTouchPad [] PROGMEM = "Touch Pad"; +const char pstrUsageWhiteBoard [] PROGMEM = "White Brd"; +const char pstrUsageCoordinateMeasuringMachine [] PROGMEM = "Coord Meas Mach"; +const char pstrUsage3DDigitizer [] PROGMEM = "3D Dgtz"; +const char pstrUsageStereoPlotter [] PROGMEM = "Stereo Plot"; +const char pstrUsageArticulatedArm [] PROGMEM = "Art Arm"; +const char pstrUsageArmature [] PROGMEM = "Armature"; +const char pstrUsageMultiplePointDigitizer [] PROGMEM = "Multi Point Dgtz"; +const char pstrUsageFreeSpaceWand [] PROGMEM = "Free Space Wand"; +const char pstrUsageStylus [] PROGMEM = "Stylus"; +const char pstrUsagePuck [] PROGMEM = "Puck"; +const char pstrUsageFinger [] PROGMEM = "Finger"; +const char pstrUsageTipPressure [] PROGMEM = "Tip Press"; +const char pstrUsageBarrelPressure [] PROGMEM = "Brl Press"; +const char pstrUsageInRange [] PROGMEM = "In Range"; +const char pstrUsageTouch [] PROGMEM = "Touch"; +const char pstrUsageUntouch [] PROGMEM = "Untouch"; +const char pstrUsageTap [] PROGMEM = "Tap"; +const char pstrUsageQuality [] PROGMEM = "Qlty"; +const char pstrUsageDataValid [] PROGMEM = "Data Valid"; +const char pstrUsageTransducerIndex [] PROGMEM = "Transducer Ind"; +const char pstrUsageTabletFunctionKeys [] PROGMEM = "Tabl Func Keys"; +const char pstrUsageProgramChangeKeys [] PROGMEM = "Pgm Chng Keys"; +//const char pstrUsageBatteryStrength [] PROGMEM = "Bat Strength"; +const char pstrUsageInvert [] PROGMEM = "Invert"; +const char pstrUsageXTilt [] PROGMEM = "X Tilt"; +const char pstrUsageYTilt [] PROGMEM = "Y Tilt"; +const char pstrUsageAzimuth [] PROGMEM = "Azimuth"; +const char pstrUsageAltitude [] PROGMEM = "Altitude"; +const char pstrUsageTwist [] PROGMEM = "Twist"; +const char pstrUsageTipSwitch [] PROGMEM = "Tip Sw"; +const char pstrUsageSecondaryTipSwitch [] PROGMEM = "Scnd Tip Sw"; +const char pstrUsageBarrelSwitch [] PROGMEM = "Brl Sw"; +const char pstrUsageEraser [] PROGMEM = "Eraser"; +const char pstrUsageTabletPick [] PROGMEM = "Tbl Pick"; + +// Alphanumeric Display Page +const char pstrUsageAlphanumericDisplay [] PROGMEM = "Alphanum Disp"; +const char pstrUsageBitmappedDisplay [] PROGMEM = "Bmp Disp"; +const char pstrUsageDisplayAttributesReport [] PROGMEM = "Disp Attr Rpt"; +const char pstrUsageASCIICharacterSet [] PROGMEM = "ASCII chset"; +const char pstrUsageDataReadBack [] PROGMEM = "Data Rd Back"; +const char pstrUsageFontReadBack [] PROGMEM = "Fnt Rd Back"; +const char pstrUsageDisplayControlReport [] PROGMEM = "Disp Ctrl Rpt"; +const char pstrUsageClearDisplay [] PROGMEM = "Clr Disp"; +//const char pstrUsageDisplayEnable [] PROGMEM = "Disp Enbl"; +const char pstrUsageScreenSaverDelay [] PROGMEM = "Scr Sav Delay"; +const char pstrUsageScreenSaverEnable [] PROGMEM = "Scr Sav Enbl"; +const char pstrUsageVerticalScroll [] PROGMEM = "V Scroll"; +const char pstrUsageHorizontalScroll [] PROGMEM = "H Scroll"; +const char pstrUsageCharacterReport [] PROGMEM = "Char Rpt"; +const char pstrUsageDisplayData [] PROGMEM = "Disp Data"; +const char pstrUsageDisplayStatus [] PROGMEM = "Disp Stat"; +const char pstrUsageStatusNotReady [] PROGMEM = "Stat !Ready"; +const char pstrUsageStatusReady [] PROGMEM = "Stat Ready"; +const char pstrUsageErrorNotALoadableCharacter [] PROGMEM = "Err Not Ld Char"; +const char pstrUsageErrorFotDataCanNotBeRead [] PROGMEM = "Fnt Data Rd Err"; +const char pstrUsageCursorPositionReport [] PROGMEM = "Cur Pos Rpt"; +const char pstrUsageRow [] PROGMEM = "Row"; +const char pstrUsageColumn [] PROGMEM = "Col"; +const char pstrUsageRows [] PROGMEM = "Rows"; +const char pstrUsageColumns [] PROGMEM = "Cols"; +const char pstrUsageCursorPixelPosition [] PROGMEM = "Cur Pix Pos"; +const char pstrUsageCursorMode [] PROGMEM = "Cur Mode"; +const char pstrUsageCursorEnable [] PROGMEM = "Cur Enbl"; +const char pstrUsageCursorBlink [] PROGMEM = "Cur Blnk"; +const char pstrUsageFontReport [] PROGMEM = "Fnt Rpt"; +const char pstrUsageFontData [] PROGMEM = "Fnt Data"; +const char pstrUsageCharacterWidth [] PROGMEM = "Char Wdth"; +const char pstrUsageCharacterHeight [] PROGMEM = "Char Hght"; +const char pstrUsageCharacterSpacingHorizontal [] PROGMEM = "Char Space H"; +const char pstrUsageCharacterSpacingVertical [] PROGMEM = "Char Space V"; +const char pstrUsageUnicodeCharset [] PROGMEM = "Unicode Char"; +const char pstrUsageFont7Segment [] PROGMEM = "Fnt 7-seg"; +const char pstrUsage7SegmentDirectMap [] PROGMEM = "7-seg map"; +const char pstrUsageFont14Segment [] PROGMEM = "Fnt 14-seg"; +const char pstrUsage14SegmentDirectMap [] PROGMEM = "14-seg map"; +const char pstrUsageDisplayBrightness [] PROGMEM = "Disp Bright"; +const char pstrUsageDisplayContrast [] PROGMEM = "Disp Cntrst"; +const char pstrUsageCharacterAttribute [] PROGMEM = "Char Attr"; +const char pstrUsageAttributeReadback [] PROGMEM = "Attr Readbk"; +const char pstrUsageAttributeData [] PROGMEM = "Attr Data"; +const char pstrUsageCharAttributeEnhance [] PROGMEM = "Char Attr Enh"; +const char pstrUsageCharAttributeUnderline [] PROGMEM = "Char Attr Undl"; +const char pstrUsageCharAttributeBlink [] PROGMEM = "Char Attr Blnk"; +const char pstrUsageBitmapSizeX [] PROGMEM = "Bmp Size X"; +const char pstrUsageBitmapSizeY [] PROGMEM = "Bmp Size Y"; +const char pstrUsageBitDepthFormat [] PROGMEM = "Bit Dpth Fmt"; +const char pstrUsageDisplayOrientation [] PROGMEM = "Disp Ornt"; +const char pstrUsagePaletteReport [] PROGMEM = "Pal Rpt"; +const char pstrUsagePaletteDataSize [] PROGMEM = "Pal Data Size"; +const char pstrUsagePaletteDataOffset [] PROGMEM = "Pal Data Off"; +const char pstrUsagePaletteData [] PROGMEM = "Pal Data"; +const char pstrUsageBlitReport [] PROGMEM = "Blit Rpt"; +const char pstrUsageBlitRectangleX1 [] PROGMEM = "Blit Rect X1"; +const char pstrUsageBlitRectangleY1 [] PROGMEM = "Blit Rect Y1"; +const char pstrUsageBlitRectangleX2 [] PROGMEM = "Blit Rect X2"; +const char pstrUsageBlitRectangleY2 [] PROGMEM = "Blit Rect Y2"; +const char pstrUsageBlitData [] PROGMEM = "Blit Data"; +const char pstrUsageSoftButton [] PROGMEM = "Soft Btn"; +const char pstrUsageSoftButtonID [] PROGMEM = "Soft Btn ID"; +const char pstrUsageSoftButtonSide [] PROGMEM = "Soft Btn Side"; +const char pstrUsageSoftButtonOffset1 [] PROGMEM = "Soft Btn Off1"; +const char pstrUsageSoftButtonOffset2 [] PROGMEM = "Soft Btn Off2"; +const char pstrUsageSoftButtonReport [] PROGMEM = "Soft Btn Rpt"; + +// Medical Instrument Page +const char pstrUsageMedicalUltrasound [] PROGMEM = "Med Ultrasnd"; +const char pstrUsageVCRAcquisition [] PROGMEM = "VCR/Acq"; +const char pstrUsageFreezeThaw [] PROGMEM = "Freeze"; +const char pstrUsageClipStore [] PROGMEM = "Clip Store"; +const char pstrUsageUpdate [] PROGMEM = "Update"; +const char pstrUsageNext [] PROGMEM = "Next"; +const char pstrUsageSave [] PROGMEM = "Save"; +const char pstrUsagePrint [] PROGMEM = "Print"; +const char pstrUsageMicrophoneEnable [] PROGMEM = "Mic Enbl"; +const char pstrUsageCine [] PROGMEM = "Cine"; +const char pstrUsageTransmitPower [] PROGMEM = "Trans Pwr"; +//const char pstrUsageVolume [] PROGMEM = "Vol"; +const char pstrUsageFocus [] PROGMEM = "Focus"; +const char pstrUsageDepth [] PROGMEM = "Depth"; +const char pstrUsageSoftStepPrimary [] PROGMEM = "Soft Stp-Pri"; +const char pstrUsageSoftStepSecondary [] PROGMEM = "Soft Stp-Sec"; +const char pstrUsageDepthGainCompensation [] PROGMEM = "Dpth Gain Comp"; +const char pstrUsageZoomSelect [] PROGMEM = "Zoom Sel"; +const char pstrUsageZoomAdjust [] PROGMEM = "Zoom Adj"; +const char pstrUsageSpectralDopplerModeSelect [] PROGMEM = "Spec Dop Mode Sel"; +const char pstrUsageSpectralDopplerModeAdjust [] PROGMEM = "Spec Dop Mode Adj"; +const char pstrUsageColorDopplerModeSelect [] PROGMEM = "Color Dop Mode Sel"; +const char pstrUsageColorDopplerModeAdjust [] PROGMEM = "Color Dop Mode Adj"; +const char pstrUsageMotionModeSelect [] PROGMEM = "Motion Mode Sel"; +const char pstrUsageMotionModeAdjust [] PROGMEM = "Motion Mode Adj"; +const char pstrUsage2DModeSelect [] PROGMEM = "2D Mode Sel"; +const char pstrUsage2DModeAdjust [] PROGMEM = "2D Mode Adj"; +const char pstrUsageSoftControlSelect [] PROGMEM = "Soft Ctrl Sel"; +const char pstrUsageSoftControlAdjust [] PROGMEM = "Soft Ctrl Adj"; + +//extern const char *usagePageTitles0[15]; +//const char *usagePageTitles1[]; +//const char *genDesktopTitles0[]; +//const char *genDesktopTitles1[]; +//const char *genDesktopTitles2[]; +//const char *genDesktopTitles3[]; +//const char *genDesktopTitles4[]; +//const char *simuTitles0[]; +//const char *simuTitles1[]; +//const char *simuTitles2[]; +//const char *vrTitles0[]; +//const char *vrTitles1[]; +//const char *sportsCtrlTitles0[]; +//const char *sportsCtrlTitles1[]; +//const char *sportsCtrlTitles2[]; +//const char *gameTitles0[]; +//const char *gameTitles1[]; +//const char *genDevCtrlTitles[]; +//const char *ledTitles[]; +//const char *telTitles0[]; +//const char *telTitles1[]; +//const char *telTitles2[]; +//const char *telTitles3[]; +//const char *telTitles4[]; +//const char *telTitles5[]; +//const char *consTitles0[]; +//const char *consTitles1[]; +//const char *consTitles2[]; +//const char *consTitles3[]; +//const char *consTitles4[]; +//const char *consTitles5[]; +//const char *consTitles6[]; +//const char *consTitles7[]; +//const char *consTitles8[]; +//const char *consTitles9[]; +//const char *consTitlesA[]; +//const char *consTitlesB[]; +//const char *consTitlesC[]; +//const char *consTitlesD[]; +//const char *consTitlesE[]; +//const char *digitTitles0[]; +//const char *digitTitles1[]; +//const char *digitTitles2[]; +//const char *aplphanumTitles0[]; +//const char *aplphanumTitles1[]; +//const char *aplphanumTitles2[]; +//const char *medInstrTitles0[]; +//const char *medInstrTitles1[]; +//const char *medInstrTitles2[]; +//const char *medInstrTitles3[]; +//const char *medInstrTitles4[]; + #endif //__HIDUSAGESTR_H__ \ No newline at end of file diff --git a/hidusagetitlearrays.cpp b/hidusagetitlearrays.cpp index e8cda978..09d59302 100644 --- a/hidusagetitlearrays.cpp +++ b/hidusagetitlearrays.cpp @@ -1,1047 +1,1047 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__HIDUSAGETITLEARRAYS_H__) -#define __HIDUSAGETITLEARRAYS_H__ - -#include -#include "hidusagestr.h" - -//const char *usagePageTitles0[] PROGMEM = -//{ -// pstrUsagePageGenericDesktopControls , -// pstrUsagePageSimulationControls , -// pstrUsagePageVRControls , -// pstrUsagePageSportControls , -// pstrUsagePageGameControls , -// pstrUsagePageGenericDeviceControls , -// pstrUsagePageKeyboardKeypad , -// pstrUsagePageLEDs , -// pstrUsagePageButton , -// pstrUsagePageOrdinal , -// pstrUsagePageTelephone , -// pstrUsagePageConsumer , -// pstrUsagePageDigitizer , -// pstrUsagePagePID , -// pstrUsagePageUnicode -//}; -// -//const char *usagePageTitles1[] PROGMEM = -//{ -// pstrUsagePageBarCodeScanner , -// pstrUsagePageScale , -// pstrUsagePageMSRDevices , -// pstrUsagePagePointOfSale , -// pstrUsagePageCameraControl , -// pstrUsagePageArcade -//}; -//const char *genDesktopTitles0[] PROGMEM = -//{ -// pstrUsagePointer , -// pstrUsageMouse , -// pstrUsageJoystick , -// pstrUsageGamePad , -// pstrUsageKeyboard , -// pstrUsageKeypad , -// pstrUsageMultiAxisController , -// pstrUsageTabletPCSystemControls -// -//}; -//const char *genDesktopTitles1[] PROGMEM = -//{ -// pstrUsageX , -// pstrUsageY , -// pstrUsageZ , -// pstrUsageRx , -// pstrUsageRy , -// pstrUsageRz , -// pstrUsageSlider , -// pstrUsageDial , -// pstrUsageWheel , -// pstrUsageHatSwitch , -// pstrUsageCountedBuffer , -// pstrUsageByteCount , -// pstrUsageMotionWakeup , -// pstrUsageStart , -// pstrUsageSelect , -// pstrUsagePageReserved , -// pstrUsageVx , -// pstrUsageVy , -// pstrUsageVz , -// pstrUsageVbrx , -// pstrUsageVbry , -// pstrUsageVbrz , -// pstrUsageVno , -// pstrUsageFeatureNotification , -// pstrUsageResolutionMultiplier -//}; -//const char *genDesktopTitles2[] PROGMEM = -//{ -// pstrUsageSystemControl , -// pstrUsageSystemPowerDown , -// pstrUsageSystemSleep , -// pstrUsageSystemWakeup , -// pstrUsageSystemContextMenu , -// pstrUsageSystemMainMenu , -// pstrUsageSystemAppMenu , -// pstrUsageSystemMenuHelp , -// pstrUsageSystemMenuExit , -// pstrUsageSystemMenuSelect , -// pstrUsageSystemMenuRight , -// pstrUsageSystemMenuLeft , -// pstrUsageSystemMenuUp , -// pstrUsageSystemMenuDown , -// pstrUsageSystemColdRestart , -// pstrUsageSystemWarmRestart , -// pstrUsageDPadUp , -// pstrUsageDPadDown , -// pstrUsageDPadRight , -// pstrUsageDPadLeft -//}; -//const char *genDesktopTitles3[] PROGMEM = -//{ -// pstrUsageSystemDock , -// pstrUsageSystemUndock , -// pstrUsageSystemSetup , -// pstrUsageSystemBreak , -// pstrUsageSystemDebuggerBreak , -// pstrUsageApplicationBreak , -// pstrUsageApplicationDebuggerBreak, -// pstrUsageSystemSpeakerMute , -// pstrUsageSystemHibernate -//}; -//const char *genDesktopTitles4[] PROGMEM = -//{ -// pstrUsageSystemDisplayInvert , -// pstrUsageSystemDisplayInternal , -// pstrUsageSystemDisplayExternal , -// pstrUsageSystemDisplayBoth , -// pstrUsageSystemDisplayDual , -// pstrUsageSystemDisplayToggleIntExt , -// pstrUsageSystemDisplaySwapPriSec , -// pstrUsageSystemDisplayLCDAutoscale -//}; -//const char *simuTitles0[] PROGMEM = -//{ -// pstrUsageFlightSimulationDevice , -// pstrUsageAutomobileSimulationDevice , -// pstrUsageTankSimulationDevice , -// pstrUsageSpaceshipSimulationDevice , -// pstrUsageSubmarineSimulationDevice , -// pstrUsageSailingSimulationDevice , -// pstrUsageMotocicleSimulationDevice , -// pstrUsageSportsSimulationDevice , -// pstrUsageAirplaneSimulationDevice , -// pstrUsageHelicopterSimulationDevice , -// pstrUsageMagicCarpetSimulationDevice, -// pstrUsageBicycleSimulationDevice -//}; -//const char *simuTitles1[] PROGMEM = -//{ -// pstrUsageFlightControlStick , -// pstrUsageFlightStick , -// pstrUsageCyclicControl , -// pstrUsageCyclicTrim , -// pstrUsageFlightYoke , -// pstrUsageTrackControl -//}; -//const char *simuTitles2[] PROGMEM = -//{ -// pstrUsageAileron , -// pstrUsageAileronTrim , -// pstrUsageAntiTorqueControl , -// pstrUsageAutopilotEnable , -// pstrUsageChaffRelease , -// pstrUsageCollectiveControl , -// pstrUsageDiveBrake , -// pstrUsageElectronicCountermeasures , -// pstrUsageElevator , -// pstrUsageElevatorTrim , -// pstrUsageRudder , -// pstrUsageThrottle , -// pstrUsageFlightCommunications , -// pstrUsageFlareRelease , -// pstrUsageLandingGear , -// pstrUsageToeBrake , -// pstrUsageTrigger , -// pstrUsageWeaponsArm , -// pstrUsageWeaponsSelect , -// pstrUsageWingFlaps , -// pstrUsageAccelerator , -// pstrUsageBrake , -// pstrUsageClutch , -// pstrUsageShifter , -// pstrUsageSteering , -// pstrUsageTurretDirection , -// pstrUsageBarrelElevation , -// pstrUsageDivePlane , -// pstrUsageBallast , -// pstrUsageBicycleCrank , -// pstrUsageHandleBars , -// pstrUsageFrontBrake , -// pstrUsageRearBrake -//}; -//const char *vrTitles0[] PROGMEM = -//{ -// pstrUsageBelt , -// pstrUsageBodySuit , -// pstrUsageFlexor , -// pstrUsageGlove , -// pstrUsageHeadTracker , -// pstrUsageHeadMountedDisplay , -// pstrUsageHandTracker , -// pstrUsageOculometer , -// pstrUsageVest , -// pstrUsageAnimatronicDevice -//}; -//const char *vrTitles1[] PROGMEM = -//{ -// pstrUsageStereoEnable , -// pstrUsageDisplayEnable -//}; -//const char *sportsCtrlTitles0[] PROGMEM = -//{ -// pstrUsageBaseballBat , -// pstrUsageGolfClub , -// pstrUsageRowingMachine , -// pstrUsageTreadmill -//}; -//const char *sportsCtrlTitles1[] PROGMEM = -//{ -// pstrUsageOar , -// pstrUsageSlope , -// pstrUsageRate , -// pstrUsageStickSpeed , -// pstrUsageStickFaceAngle , -// pstrUsageStickHeelToe , -// pstrUsageStickFollowThough , -// pstrUsageStickTempo , -// pstrUsageStickType , -// pstrUsageStickHeight -//}; -//const char *sportsCtrlTitles2[] PROGMEM = -//{ -// pstrUsagePutter , -// pstrUsage1Iron , -// pstrUsage2Iron , -// pstrUsage3Iron , -// pstrUsage4Iron , -// pstrUsage5Iron , -// pstrUsage6Iron , -// pstrUsage7Iron , -// pstrUsage8Iron , -// pstrUsage9Iron , -// pstrUsage10Iron , -// pstrUsage11Iron , -// pstrUsageSandWedge , -// pstrUsageLoftWedge , -// pstrUsagePowerWedge , -// pstrUsage1Wood , -// pstrUsage3Wood , -// pstrUsage5Wood , -// pstrUsage7Wood , -// pstrUsage9Wood -//}; -//const char *gameTitles0[] PROGMEM = -//{ -// pstrUsage3DGameController , -// pstrUsagePinballDevice , -// pstrUsageGunDevice -//}; -//const char *gameTitles1[] PROGMEM = -//{ -// pstrUsagePointOfView , -// pstrUsageTurnRightLeft , -// pstrUsagePitchForwardBackward , -// pstrUsageRollRightLeft , -// pstrUsageMoveRightLeft , -// pstrUsageMoveForwardBackward , -// pstrUsageMoveUpDown , -// pstrUsageLeanRightLeft , -// pstrUsageLeanForwardBackward , -// pstrUsageHeightOfPOV , -// pstrUsageFlipper , -// pstrUsageSecondaryFlipper , -// pstrUsageBump , -// pstrUsageNewGame , -// pstrUsageShootBall , -// pstrUsagePlayer , -// pstrUsageGunBolt , -// pstrUsageGunClip , -// pstrUsageGunSelector , -// pstrUsageGunSingleShot , -// pstrUsageGunBurst , -// pstrUsageGunAutomatic , -// pstrUsageGunSafety , -// pstrUsageGamepadFireJump , -// pstrUsageGamepadTrigger -//}; -//const char *genDevCtrlTitles[] PROGMEM = -//{ -// pstrUsageBatteryStrength, -// pstrUsageWirelessChannel, -// pstrUsageWirelessID, -// pstrUsageDiscoverWirelessControl, -// pstrUsageSecurityCodeCharEntered, -// pstrUsageSecurityCodeCharErased, -// pstrUsageSecurityCodeCleared -//}; -//const char *ledTitles[] PROGMEM = -//{ -// pstrUsageNumLock , -// pstrUsageCapsLock , -// pstrUsageScrollLock , -// pstrUsageCompose , -// pstrUsageKana , -// pstrUsagePower , -// pstrUsageShift , -// pstrUsageDoNotDisturb , -// pstrUsageMute , -// pstrUsageToneEnable , -// pstrUsageHighCutFilter , -// pstrUsageLowCutFilter , -// pstrUsageEqualizerEnable , -// pstrUsageSoundFieldOn , -// pstrUsageSurroundOn , -// pstrUsageRepeat , -// pstrUsageStereo , -// pstrUsageSamplingRateDetect , -// pstrUsageSpinning , -// pstrUsageCAV , -// pstrUsageCLV , -// pstrUsageRecordingFormatDetect , -// pstrUsageOffHook , -// pstrUsageRing , -// pstrUsageMessageWaiting , -// pstrUsageDataMode , -// pstrUsageBatteryOperation , -// pstrUsageBatteryOK , -// pstrUsageBatteryLow , -// pstrUsageSpeaker , -// pstrUsageHeadSet , -// pstrUsageHold , -// pstrUsageMicrophone , -// pstrUsageCoverage , -// pstrUsageNightMode , -// pstrUsageSendCalls , -// pstrUsageCallPickup , -// pstrUsageConference , -// pstrUsageStandBy , -// pstrUsageCameraOn , -// pstrUsageCameraOff , -// pstrUsageOnLine , -// pstrUsageOffLine , -// pstrUsageBusy , -// pstrUsageReady , -// pstrUsagePaperOut , -// pstrUsagePaperJam , -// pstrUsageRemote , -// pstrUsageForward , -// pstrUsageReverse , -// pstrUsageStop , -// pstrUsageRewind , -// pstrUsageFastForward , -// pstrUsagePlay , -// pstrUsagePause , -// pstrUsageRecord , -// pstrUsageError , -// pstrUsageSelectedIndicator , -// pstrUsageInUseIndicator , -// pstrUsageMultiModeIndicator , -// pstrUsageIndicatorOn , -// pstrUsageIndicatorFlash , -// pstrUsageIndicatorSlowBlink , -// pstrUsageIndicatorFastBlink , -// pstrUsageIndicatorOff , -// pstrUsageFlashOnTime , -// pstrUsageSlowBlinkOnTime , -// pstrUsageSlowBlinkOffTime , -// pstrUsageFastBlinkOnTime , -// pstrUsageFastBlinkOffTime , -// pstrUsageIndicatorColor , -// pstrUsageIndicatorRed , -// pstrUsageIndicatorGreen , -// pstrUsageIndicatorAmber , -// pstrUsageGenericIndicator , -// pstrUsageSystemSuspend , -// pstrUsageExternalPowerConnected -//}; -//const char *telTitles0 [] PROGMEM = -//{ -// pstrUsagePhone , -// pstrUsageAnsweringMachine , -// pstrUsageMessageControls , -// pstrUsageHandset , -// pstrUsageHeadset , -// pstrUsageTelephonyKeyPad , -// pstrUsageProgrammableButton -//}; -//const char *telTitles1 [] PROGMEM = -//{ -// pstrUsageHookSwitch , -// pstrUsageFlash , -// pstrUsageFeature , -// pstrUsageHold , -// pstrUsageRedial , -// pstrUsageTransfer , -// pstrUsageDrop , -// pstrUsagePark , -// pstrUsageForwardCalls , -// pstrUsageAlternateFunction , -// pstrUsageLine , -// pstrUsageSpeakerPhone , -// pstrUsageConference , -// pstrUsageRingEnable , -// pstrUsageRingSelect , -// pstrUsagePhoneMute , -// pstrUsageCallerID , -// pstrUsageSend -//}; -//const char *telTitles2 [] PROGMEM = -//{ -// pstrUsageSpeedDial , -// pstrUsageStoreNumber , -// pstrUsageRecallNumber , -// pstrUsagePhoneDirectory -//}; -//const char *telTitles3 [] PROGMEM = -//{ -// pstrUsageVoiceMail , -// pstrUsageScreenCalls , -// pstrUsageDoNotDisturb , -// pstrUsageMessage , -// pstrUsageAnswerOnOff -//}; -//const char *telTitles4 [] PROGMEM = -//{ -// pstrUsageInsideDialTone , -// pstrUsageOutsideDialTone , -// pstrUsageInsideRingTone , -// pstrUsageOutsideRingTone , -// pstrUsagePriorityRingTone , -// pstrUsageInsideRingback , -// pstrUsagePriorityRingback , -// pstrUsageLineBusyTone , -// pstrUsageReorderTone , -// pstrUsageCallWaitingTone , -// pstrUsageConfirmationTone1 , -// pstrUsageConfirmationTone2 , -// pstrUsageTonesOff , -// pstrUsageOutsideRingback , -// pstrUsageRinger -//}; -//const char *telTitles5 [] PROGMEM = -//{ -// pstrUsagePhoneKey0 , -// pstrUsagePhoneKey1 , -// pstrUsagePhoneKey2 , -// pstrUsagePhoneKey3 , -// pstrUsagePhoneKey4 , -// pstrUsagePhoneKey5 , -// pstrUsagePhoneKey6 , -// pstrUsagePhoneKey7 , -// pstrUsagePhoneKey8 , -// pstrUsagePhoneKey9 , -// pstrUsagePhoneKeyStar , -// pstrUsagePhoneKeyPound , -// pstrUsagePhoneKeyA , -// pstrUsagePhoneKeyB , -// pstrUsagePhoneKeyC , -// pstrUsagePhoneKeyD -//}; -//const char *consTitles0[] PROGMEM = -//{ -// pstrUsageConsumerControl, -// pstrUsageNumericKeyPad, -// pstrUsageProgrammableButton, -// pstrUsageMicrophone, -// pstrUsageHeadphone, -// pstrUsageGraphicEqualizer -//}; -//const char *consTitles1[] PROGMEM = -//{ -// pstrUsagePlus10 , -// pstrUsagePlus100, -// pstrUsageAMPM -//}; -//const char *consTitles2[] PROGMEM = -//{ -// pstrUsagePower , -// pstrUsageReset , -// pstrUsageSleep , -// pstrUsageSleepAfter , -// pstrUsageSleepMode , -// pstrUsageIllumination , -// pstrUsageFunctionButtons -// -//}; -//const char *consTitles3[] PROGMEM = -//{ -// pstrUsageMenu , -// pstrUsageMenuPick , -// pstrUsageMenuUp , -// pstrUsageMenuDown , -// pstrUsageMenuLeft , -// pstrUsageMenuRight , -// pstrUsageMenuEscape , -// pstrUsageMenuValueIncrease, -// pstrUsageMenuValueDecrease -//}; -//const char *consTitles4[] PROGMEM = -//{ -// pstrUsageDataOnScreen , -// pstrUsageClosedCaption , -// pstrUsageClosedCaptionSelect, -// pstrUsageVCRTV , -// pstrUsageBroadcastMode , -// pstrUsageSnapshot , -// pstrUsageStill -//}; -//const char *consTitles5[] PROGMEM = -//{ -// pstrUsageSelection , -// pstrUsageAssignSelection , -// pstrUsageModeStep , -// pstrUsageRecallLast , -// pstrUsageEnterChannel , -// pstrUsageOrderMovie , -// pstrUsageChannel , -// pstrUsageMediaSelection , -// pstrUsageMediaSelectComputer , -// pstrUsageMediaSelectTV , -// pstrUsageMediaSelectWWW , -// pstrUsageMediaSelectDVD , -// pstrUsageMediaSelectTelephone , -// pstrUsageMediaSelectProgramGuide , -// pstrUsageMediaSelectVideoPhone , -// pstrUsageMediaSelectGames , -// pstrUsageMediaSelectMessages , -// pstrUsageMediaSelectCD , -// pstrUsageMediaSelectVCR , -// pstrUsageMediaSelectTuner , -// pstrUsageQuit , -// pstrUsageHelp , -// pstrUsageMediaSelectTape , -// pstrUsageMediaSelectCable , -// pstrUsageMediaSelectSatellite , -// pstrUsageMediaSelectSecurity , -// pstrUsageMediaSelectHome , -// pstrUsageMediaSelectCall , -// pstrUsageChannelIncrement , -// pstrUsageChannelDecrement , -// pstrUsageMediaSelectSAP , -// pstrUsagePageReserved , -// pstrUsageVCRPlus , -// pstrUsageOnce , -// pstrUsageDaily , -// pstrUsageWeekly , -// pstrUsageMonthly -//}; -//const char *consTitles6[] PROGMEM = -//{ -// pstrUsagePlay , -// pstrUsagePause , -// pstrUsageRecord , -// pstrUsageFastForward , -// pstrUsageRewind , -// pstrUsageScanNextTrack , -// pstrUsageScanPreviousTrack , -// pstrUsageStop , -// pstrUsageEject , -// pstrUsageRandomPlay , -// pstrUsageSelectDisk , -// pstrUsageEnterDisk , -// pstrUsageRepeat , -// pstrUsageTracking , -// pstrUsageTrackNormal , -// pstrUsageSlowTracking , -// pstrUsageFrameForward , -// pstrUsageFrameBackwards , -// pstrUsageMark , -// pstrUsageClearMark , -// pstrUsageRepeatFromMark , -// pstrUsageReturnToMark , -// pstrUsageSearchMarkForward , -// pstrUsageSearchMarkBackwards , -// pstrUsageCounterReset , -// pstrUsageShowCounter , -// pstrUsageTrackingIncrement , -// pstrUsageTrackingDecrement , -// pstrUsageStopEject , -// pstrUsagePlayPause , -// pstrUsagePlaySkip -//}; -//const char *consTitles7[] PROGMEM = -//{ -// pstrUsageVolume , -// pstrUsageBalance , -// pstrUsageMute , -// pstrUsageBass , -// pstrUsageTreble , -// pstrUsageBassBoost , -// pstrUsageSurroundMode , -// pstrUsageLoudness , -// pstrUsageMPX , -// pstrUsageVolumeIncrement , -// pstrUsageVolumeDecrement -//}; -//const char *consTitles8[] PROGMEM = -//{ -// pstrUsageSpeedSelect , -// pstrUsagePlaybackSpeed , -// pstrUsageStandardPlay , -// pstrUsageLongPlay , -// pstrUsageExtendedPlay , -// pstrUsageSlow -//}; -//const char *consTitles9[] PROGMEM = -//{ -// pstrUsageFanEnable , -// pstrUsageFanSpeed , -// pstrUsageLightEnable , -// pstrUsageLightIlluminationLevel , -// pstrUsageClimateControlEnable , -// pstrUsageRoomTemperature , -// pstrUsageSecurityEnable , -// pstrUsageFireAlarm , -// pstrUsagePoliceAlarm , -// pstrUsageProximity , -// pstrUsageMotion , -// pstrUsageDuresAlarm , -// pstrUsageHoldupAlarm , -// pstrUsageMedicalAlarm -//}; -//const char *consTitlesA[] PROGMEM = -//{ -// pstrUsageBalanceRight , -// pstrUsageBalanceLeft , -// pstrUsageBassIncrement , -// pstrUsageBassDecrement , -// pstrUsageTrebleIncrement , -// pstrUsageTrebleDecrement -//}; -//const char *consTitlesB[] PROGMEM = -//{ -// pstrUsageSpeakerSystem , -// pstrUsageChannelLeft , -// pstrUsageChannelRight , -// pstrUsageChannelCenter , -// pstrUsageChannelFront , -// pstrUsageChannelCenterFront , -// pstrUsageChannelSide , -// pstrUsageChannelSurround , -// pstrUsageChannelLowFreqEnhancement , -// pstrUsageChannelTop , -// pstrUsageChannelUnknown -//}; -//const char *consTitlesC[] PROGMEM = -//{ -// pstrUsageSubChannel , -// pstrUsageSubChannelIncrement , -// pstrUsageSubChannelDecrement , -// pstrUsageAlternateAudioIncrement , -// pstrUsageAlternateAudioDecrement -//}; -//const char *consTitlesD[] PROGMEM = -//{ -// pstrUsageApplicationLaunchButtons , -// pstrUsageALLaunchButtonConfigTool , -// pstrUsageALProgrammableButton , -// pstrUsageALConsumerControlConfig , -// pstrUsageALWordProcessor , -// pstrUsageALTextEditor , -// pstrUsageALSpreadsheet , -// pstrUsageALGraphicsEditor , -// pstrUsageALPresentationApp , -// pstrUsageALDatabaseApp , -// pstrUsageALEmailReader , -// pstrUsageALNewsreader , -// pstrUsageALVoicemail , -// pstrUsageALContactsAddressBook , -// pstrUsageALCalendarSchedule , -// pstrUsageALTaskProjectManager , -// pstrUsageALLogJournalTimecard , -// pstrUsageALCheckbookFinance , -// pstrUsageALCalculator , -// pstrUsageALAVCapturePlayback , -// pstrUsageALLocalMachineBrowser , -// pstrUsageALLANWANBrow , -// pstrUsageALInternetBrowser , -// pstrUsageALRemoteNetISPConnect , -// pstrUsageALNetworkConference , -// pstrUsageALNetworkChat , -// pstrUsageALTelephonyDialer , -// pstrUsageALLogon , -// pstrUsageALLogoff , -// pstrUsageALLogonLogoff , -// pstrUsageALTermLockScrSav , -// pstrUsageALControlPannel , -// pstrUsageALCommandLineProcessorRun , -// pstrUsageALProcessTaskManager , -// pstrUsageALSelectTaskApplication , -// pstrUsageALNextTaskApplication , -// pstrUsageALPreviousTaskApplication , -// pstrUsageALPreemptiveHaltTaskApp , -// pstrUsageALIntegratedHelpCenter , -// pstrUsageALDocuments , -// pstrUsageALThesaurus , -// pstrUsageALDictionary , -// pstrUsageALDesktop , -// pstrUsageALSpellCheck , -// pstrUsageALGrammarCheck , -// pstrUsageALWirelessStatus , -// pstrUsageALKeyboardLayout , -// pstrUsageALVirusProtection , -// pstrUsageALEncryption , -// pstrUsageALScreenSaver , -// pstrUsageALAlarms , -// pstrUsageALClock , -// pstrUsageALFileBrowser , -// pstrUsageALPowerStatus , -// pstrUsageALImageBrowser , -// pstrUsageALAudioBrowser , -// pstrUsageALMovieBrowser , -// pstrUsageALDigitalRightsManager , -// pstrUsageALDigitalWallet , -// pstrUsagePageReserved , -// pstrUsageALInstantMessaging , -// pstrUsageALOEMFeaturesBrowser , -// pstrUsageALOEMHelp , -// pstrUsageALOnlineCommunity , -// pstrUsageALEntertainmentContentBrow , -// pstrUsageALOnlineShoppingBrowser , -// pstrUsageALSmartCardInfoHelp , -// pstrUsageALMarketMonitorFinBrowser , -// pstrUsageALCustomCorpNewsBrowser , -// pstrUsageALOnlineActivityBrowser , -// pstrUsageALResearchSearchBrowser , -// pstrUsageALAudioPlayer -//}; -//const char *consTitlesE[] PROGMEM = -//{ -// pstrUsageGenericGUIAppControls , -// pstrUsageACNew , -// pstrUsageACOpen , -// pstrUsageACClose , -// pstrUsageACExit , -// pstrUsageACMaximize , -// pstrUsageACMinimize , -// pstrUsageACSave , -// pstrUsageACPrint , -// pstrUsageACProperties , -// pstrUsageACUndo , -// pstrUsageACCopy , -// pstrUsageACCut , -// pstrUsageACPaste , -// pstrUsageACSelectAll , -// pstrUsageACFind , -// pstrUsageACFindAndReplace , -// pstrUsageACSearch , -// pstrUsageACGoto , -// pstrUsageACHome , -// pstrUsageACBack , -// pstrUsageACForward , -// pstrUsageACStop , -// pstrUsageACRefresh , -// pstrUsageACPreviousLink , -// pstrUsageACNextLink , -// pstrUsageACBookmarks , -// pstrUsageACHistory , -// pstrUsageACSubscriptions , -// pstrUsageACZoomIn , -// pstrUsageACZoomOut , -// pstrUsageACZoom , -// pstrUsageACFullScreenView , -// pstrUsageACNormalView , -// pstrUsageACViewToggle , -// pstrUsageACScrollUp , -// pstrUsageACScrollDown , -// pstrUsageACScroll , -// pstrUsageACPanLeft , -// pstrUsageACPanRight , -// pstrUsageACPan , -// pstrUsageACNewWindow , -// pstrUsageACTileHoriz , -// pstrUsageACTileVert , -// pstrUsageACFormat , -// pstrUsageACEdit , -// pstrUsageACBold , -// pstrUsageACItalics , -// pstrUsageACUnderline , -// pstrUsageACStrikethrough , -// pstrUsageACSubscript , -// pstrUsageACSuperscript , -// pstrUsageACAllCaps , -// pstrUsageACRotate , -// pstrUsageACResize , -// pstrUsageACFlipHorizontal , -// pstrUsageACFlipVertical , -// pstrUsageACMirrorHorizontal , -// pstrUsageACMirrorVertical , -// pstrUsageACFontSelect , -// pstrUsageACFontColor , -// pstrUsageACFontSize , -// pstrUsageACJustifyLeft , -// pstrUsageACJustifyCenterH , -// pstrUsageACJustifyRight , -// pstrUsageACJustifyBlockH , -// pstrUsageACJustifyTop , -// pstrUsageACJustifyCenterV , -// pstrUsageACJustifyBottom , -// pstrUsageACJustifyBlockV , -// pstrUsageACIndentDecrease , -// pstrUsageACIndentIncrease , -// pstrUsageACNumberedList , -// pstrUsageACRestartNumbering , -// pstrUsageACBulletedList , -// pstrUsageACPromote , -// pstrUsageACDemote , -// pstrUsageACYes , -// pstrUsageACNo , -// pstrUsageACCancel , -// pstrUsageACCatalog , -// pstrUsageACBuyChkout , -// pstrUsageACAddToCart , -// pstrUsageACExpand , -// pstrUsageACExpandAll , -// pstrUsageACCollapse , -// pstrUsageACCollapseAll , -// pstrUsageACPrintPreview , -// pstrUsageACPasteSpecial , -// pstrUsageACInsertMode , -// pstrUsageACDelete , -// pstrUsageACLock , -// pstrUsageACUnlock , -// pstrUsageACProtect , -// pstrUsageACUnprotect , -// pstrUsageACAttachComment , -// pstrUsageACDeleteComment , -// pstrUsageACViewComment , -// pstrUsageACSelectWord , -// pstrUsageACSelectSentence , -// pstrUsageACSelectParagraph , -// pstrUsageACSelectColumn , -// pstrUsageACSelectRow , -// pstrUsageACSelectTable , -// pstrUsageACSelectObject , -// pstrUsageACRedoRepeat , -// pstrUsageACSort , -// pstrUsageACSortAscending , -// pstrUsageACSortDescending , -// pstrUsageACFilter , -// pstrUsageACSetClock , -// pstrUsageACViewClock , -// pstrUsageACSelectTimeZone , -// pstrUsageACEditTimeZone , -// pstrUsageACSetAlarm , -// pstrUsageACClearAlarm , -// pstrUsageACSnoozeAlarm , -// pstrUsageACResetAlarm , -// pstrUsageACSyncronize , -// pstrUsageACSendReceive , -// pstrUsageACSendTo , -// pstrUsageACReply , -// pstrUsageACReplyAll , -// pstrUsageACForwardMessage , -// pstrUsageACSend , -// pstrUsageACAttachFile , -// pstrUsageACUpload , -// pstrUsageACDownload , -// pstrUsageACSetBorders , -// pstrUsageACInsertRow , -// pstrUsageACInsertColumn , -// pstrUsageACInsertFile , -// pstrUsageACInsertPicture , -// pstrUsageACInsertObject , -// pstrUsageACInsertSymbol , -// pstrUsageACSaveAndClose , -// pstrUsageACRename , -// pstrUsageACMerge , -// pstrUsageACSplit , -// pstrUsageACDistributeHorizontaly , -// pstrUsageACDistributeVerticaly -//}; -//const char *digitTitles0[] PROGMEM = -//{ -// pstrUsageDigitizer , -// pstrUsagePen , -// pstrUsageLightPen , -// pstrUsageTouchScreen , -// pstrUsageTouchPad , -// pstrUsageWhiteBoard , -// pstrUsageCoordinateMeasuringMachine , -// pstrUsage3DDigitizer , -// pstrUsageStereoPlotter , -// pstrUsageArticulatedArm , -// pstrUsageArmature , -// pstrUsageMultiplePointDigitizer , -// pstrUsageFreeSpaceWand -//}; -//const char *digitTitles1[] PROGMEM = -//{ -// pstrUsageStylus , -// pstrUsagePuck , -// pstrUsageFinger -// -//}; -//const char *digitTitles2[] PROGMEM = -//{ -// pstrUsageTipPressure , -// pstrUsageBarrelPressure , -// pstrUsageInRange , -// pstrUsageTouch , -// pstrUsageUntouch , -// pstrUsageTap , -// pstrUsageQuality , -// pstrUsageDataValid , -// pstrUsageTransducerIndex , -// pstrUsageTabletFunctionKeys , -// pstrUsageProgramChangeKeys , -// pstrUsageBatteryStrength , -// pstrUsageInvert , -// pstrUsageXTilt , -// pstrUsageYTilt , -// pstrUsageAzimuth , -// pstrUsageAltitude , -// pstrUsageTwist , -// pstrUsageTipSwitch , -// pstrUsageSecondaryTipSwitch , -// pstrUsageBarrelSwitch , -// pstrUsageEraser , -// pstrUsageTabletPick -//}; -//const char *aplphanumTitles0[] PROGMEM = -//{ -// pstrUsageAlphanumericDisplay, -// pstrUsageBitmappedDisplay -//}; -//const char *aplphanumTitles1[] PROGMEM = -//{ -// pstrUsageDisplayAttributesReport , -// pstrUsageASCIICharacterSet , -// pstrUsageDataReadBack , -// pstrUsageFontReadBack , -// pstrUsageDisplayControlReport , -// pstrUsageClearDisplay , -// pstrUsageDisplayEnable , -// pstrUsageScreenSaverDelay , -// pstrUsageScreenSaverEnable , -// pstrUsageVerticalScroll , -// pstrUsageHorizontalScroll , -// pstrUsageCharacterReport , -// pstrUsageDisplayData , -// pstrUsageDisplayStatus , -// pstrUsageStatusNotReady , -// pstrUsageStatusReady , -// pstrUsageErrorNotALoadableCharacter , -// pstrUsageErrorFotDataCanNotBeRead , -// pstrUsageCursorPositionReport , -// pstrUsageRow , -// pstrUsageColumn , -// pstrUsageRows , -// pstrUsageColumns , -// pstrUsageCursorPixelPosition , -// pstrUsageCursorMode , -// pstrUsageCursorEnable , -// pstrUsageCursorBlink , -// pstrUsageFontReport , -// pstrUsageFontData , -// pstrUsageCharacterWidth , -// pstrUsageCharacterHeight , -// pstrUsageCharacterSpacingHorizontal , -// pstrUsageCharacterSpacingVertical , -// pstrUsageUnicodeCharset , -// pstrUsageFont7Segment , -// pstrUsage7SegmentDirectMap , -// pstrUsageFont14Segment , -// pstrUsage14SegmentDirectMap , -// pstrUsageDisplayBrightness , -// pstrUsageDisplayContrast , -// pstrUsageCharacterAttribute , -// pstrUsageAttributeReadback , -// pstrUsageAttributeData , -// pstrUsageCharAttributeEnhance , -// pstrUsageCharAttributeUnderline , -// pstrUsageCharAttributeBlink -//}; -//const char *aplphanumTitles2[] PROGMEM = -//{ -// pstrUsageBitmapSizeX , -// pstrUsageBitmapSizeY , -// pstrUsagePageReserved , -// pstrUsageBitDepthFormat , -// pstrUsageDisplayOrientation , -// pstrUsagePaletteReport , -// pstrUsagePaletteDataSize , -// pstrUsagePaletteDataOffset , -// pstrUsagePaletteData , -// pstrUsageBlitReport , -// pstrUsageBlitRectangleX1 , -// pstrUsageBlitRectangleY1 , -// pstrUsageBlitRectangleX2 , -// pstrUsageBlitRectangleY2 , -// pstrUsageBlitData , -// pstrUsageSoftButton , -// pstrUsageSoftButtonID , -// pstrUsageSoftButtonSide , -// pstrUsageSoftButtonOffset1 , -// pstrUsageSoftButtonOffset2 , -// pstrUsageSoftButtonReport -//}; -//const char *medInstrTitles0[] PROGMEM = -//{ -// pstrUsageVCRAcquisition , -// pstrUsageFreezeThaw , -// pstrUsageClipStore , -// pstrUsageUpdate , -// pstrUsageNext , -// pstrUsageSave , -// pstrUsagePrint , -// pstrUsageMicrophoneEnable -//}; -//const char *medInstrTitles1[] PROGMEM = -//{ -// pstrUsageCine , -// pstrUsageTransmitPower , -// pstrUsageVolume , -// pstrUsageFocus , -// pstrUsageDepth -//}; -//const char *medInstrTitles2[] PROGMEM = -//{ -// pstrUsageSoftStepPrimary , -// pstrUsageSoftStepSecondary -//}; -//const char *medInstrTitles3[] PROGMEM = -//{ -// pstrUsageZoomSelect , -// pstrUsageZoomAdjust , -// pstrUsageSpectralDopplerModeSelect , -// pstrUsageSpectralDopplerModeAdjust , -// pstrUsageColorDopplerModeSelect , -// pstrUsageColorDopplerModeAdjust , -// pstrUsageMotionModeSelect , -// pstrUsageMotionModeAdjust , -// pstrUsage2DModeSelect , -// pstrUsage2DModeAdjust -//}; -//const char *medInstrTitles4[] PROGMEM = -//{ -// pstrUsageSoftControlSelect , -// pstrUsageSoftControlAdjust -//}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__HIDUSAGETITLEARRAYS_H__) +#define __HIDUSAGETITLEARRAYS_H__ + +#include +#include "hidusagestr.h" + +//const char *usagePageTitles0[] PROGMEM = +//{ +// pstrUsagePageGenericDesktopControls , +// pstrUsagePageSimulationControls , +// pstrUsagePageVRControls , +// pstrUsagePageSportControls , +// pstrUsagePageGameControls , +// pstrUsagePageGenericDeviceControls , +// pstrUsagePageKeyboardKeypad , +// pstrUsagePageLEDs , +// pstrUsagePageButton , +// pstrUsagePageOrdinal , +// pstrUsagePageTelephone , +// pstrUsagePageConsumer , +// pstrUsagePageDigitizer , +// pstrUsagePagePID , +// pstrUsagePageUnicode +//}; +// +//const char *usagePageTitles1[] PROGMEM = +//{ +// pstrUsagePageBarCodeScanner , +// pstrUsagePageScale , +// pstrUsagePageMSRDevices , +// pstrUsagePagePointOfSale , +// pstrUsagePageCameraControl , +// pstrUsagePageArcade +//}; +//const char *genDesktopTitles0[] PROGMEM = +//{ +// pstrUsagePointer , +// pstrUsageMouse , +// pstrUsageJoystick , +// pstrUsageGamePad , +// pstrUsageKeyboard , +// pstrUsageKeypad , +// pstrUsageMultiAxisController , +// pstrUsageTabletPCSystemControls +// +//}; +//const char *genDesktopTitles1[] PROGMEM = +//{ +// pstrUsageX , +// pstrUsageY , +// pstrUsageZ , +// pstrUsageRx , +// pstrUsageRy , +// pstrUsageRz , +// pstrUsageSlider , +// pstrUsageDial , +// pstrUsageWheel , +// pstrUsageHatSwitch , +// pstrUsageCountedBuffer , +// pstrUsageByteCount , +// pstrUsageMotionWakeup , +// pstrUsageStart , +// pstrUsageSelect , +// pstrUsagePageReserved , +// pstrUsageVx , +// pstrUsageVy , +// pstrUsageVz , +// pstrUsageVbrx , +// pstrUsageVbry , +// pstrUsageVbrz , +// pstrUsageVno , +// pstrUsageFeatureNotification , +// pstrUsageResolutionMultiplier +//}; +//const char *genDesktopTitles2[] PROGMEM = +//{ +// pstrUsageSystemControl , +// pstrUsageSystemPowerDown , +// pstrUsageSystemSleep , +// pstrUsageSystemWakeup , +// pstrUsageSystemContextMenu , +// pstrUsageSystemMainMenu , +// pstrUsageSystemAppMenu , +// pstrUsageSystemMenuHelp , +// pstrUsageSystemMenuExit , +// pstrUsageSystemMenuSelect , +// pstrUsageSystemMenuRight , +// pstrUsageSystemMenuLeft , +// pstrUsageSystemMenuUp , +// pstrUsageSystemMenuDown , +// pstrUsageSystemColdRestart , +// pstrUsageSystemWarmRestart , +// pstrUsageDPadUp , +// pstrUsageDPadDown , +// pstrUsageDPadRight , +// pstrUsageDPadLeft +//}; +//const char *genDesktopTitles3[] PROGMEM = +//{ +// pstrUsageSystemDock , +// pstrUsageSystemUndock , +// pstrUsageSystemSetup , +// pstrUsageSystemBreak , +// pstrUsageSystemDebuggerBreak , +// pstrUsageApplicationBreak , +// pstrUsageApplicationDebuggerBreak, +// pstrUsageSystemSpeakerMute , +// pstrUsageSystemHibernate +//}; +//const char *genDesktopTitles4[] PROGMEM = +//{ +// pstrUsageSystemDisplayInvert , +// pstrUsageSystemDisplayInternal , +// pstrUsageSystemDisplayExternal , +// pstrUsageSystemDisplayBoth , +// pstrUsageSystemDisplayDual , +// pstrUsageSystemDisplayToggleIntExt , +// pstrUsageSystemDisplaySwapPriSec , +// pstrUsageSystemDisplayLCDAutoscale +//}; +//const char *simuTitles0[] PROGMEM = +//{ +// pstrUsageFlightSimulationDevice , +// pstrUsageAutomobileSimulationDevice , +// pstrUsageTankSimulationDevice , +// pstrUsageSpaceshipSimulationDevice , +// pstrUsageSubmarineSimulationDevice , +// pstrUsageSailingSimulationDevice , +// pstrUsageMotocicleSimulationDevice , +// pstrUsageSportsSimulationDevice , +// pstrUsageAirplaneSimulationDevice , +// pstrUsageHelicopterSimulationDevice , +// pstrUsageMagicCarpetSimulationDevice, +// pstrUsageBicycleSimulationDevice +//}; +//const char *simuTitles1[] PROGMEM = +//{ +// pstrUsageFlightControlStick , +// pstrUsageFlightStick , +// pstrUsageCyclicControl , +// pstrUsageCyclicTrim , +// pstrUsageFlightYoke , +// pstrUsageTrackControl +//}; +//const char *simuTitles2[] PROGMEM = +//{ +// pstrUsageAileron , +// pstrUsageAileronTrim , +// pstrUsageAntiTorqueControl , +// pstrUsageAutopilotEnable , +// pstrUsageChaffRelease , +// pstrUsageCollectiveControl , +// pstrUsageDiveBrake , +// pstrUsageElectronicCountermeasures , +// pstrUsageElevator , +// pstrUsageElevatorTrim , +// pstrUsageRudder , +// pstrUsageThrottle , +// pstrUsageFlightCommunications , +// pstrUsageFlareRelease , +// pstrUsageLandingGear , +// pstrUsageToeBrake , +// pstrUsageTrigger , +// pstrUsageWeaponsArm , +// pstrUsageWeaponsSelect , +// pstrUsageWingFlaps , +// pstrUsageAccelerator , +// pstrUsageBrake , +// pstrUsageClutch , +// pstrUsageShifter , +// pstrUsageSteering , +// pstrUsageTurretDirection , +// pstrUsageBarrelElevation , +// pstrUsageDivePlane , +// pstrUsageBallast , +// pstrUsageBicycleCrank , +// pstrUsageHandleBars , +// pstrUsageFrontBrake , +// pstrUsageRearBrake +//}; +//const char *vrTitles0[] PROGMEM = +//{ +// pstrUsageBelt , +// pstrUsageBodySuit , +// pstrUsageFlexor , +// pstrUsageGlove , +// pstrUsageHeadTracker , +// pstrUsageHeadMountedDisplay , +// pstrUsageHandTracker , +// pstrUsageOculometer , +// pstrUsageVest , +// pstrUsageAnimatronicDevice +//}; +//const char *vrTitles1[] PROGMEM = +//{ +// pstrUsageStereoEnable , +// pstrUsageDisplayEnable +//}; +//const char *sportsCtrlTitles0[] PROGMEM = +//{ +// pstrUsageBaseballBat , +// pstrUsageGolfClub , +// pstrUsageRowingMachine , +// pstrUsageTreadmill +//}; +//const char *sportsCtrlTitles1[] PROGMEM = +//{ +// pstrUsageOar , +// pstrUsageSlope , +// pstrUsageRate , +// pstrUsageStickSpeed , +// pstrUsageStickFaceAngle , +// pstrUsageStickHeelToe , +// pstrUsageStickFollowThough , +// pstrUsageStickTempo , +// pstrUsageStickType , +// pstrUsageStickHeight +//}; +//const char *sportsCtrlTitles2[] PROGMEM = +//{ +// pstrUsagePutter , +// pstrUsage1Iron , +// pstrUsage2Iron , +// pstrUsage3Iron , +// pstrUsage4Iron , +// pstrUsage5Iron , +// pstrUsage6Iron , +// pstrUsage7Iron , +// pstrUsage8Iron , +// pstrUsage9Iron , +// pstrUsage10Iron , +// pstrUsage11Iron , +// pstrUsageSandWedge , +// pstrUsageLoftWedge , +// pstrUsagePowerWedge , +// pstrUsage1Wood , +// pstrUsage3Wood , +// pstrUsage5Wood , +// pstrUsage7Wood , +// pstrUsage9Wood +//}; +//const char *gameTitles0[] PROGMEM = +//{ +// pstrUsage3DGameController , +// pstrUsagePinballDevice , +// pstrUsageGunDevice +//}; +//const char *gameTitles1[] PROGMEM = +//{ +// pstrUsagePointOfView , +// pstrUsageTurnRightLeft , +// pstrUsagePitchForwardBackward , +// pstrUsageRollRightLeft , +// pstrUsageMoveRightLeft , +// pstrUsageMoveForwardBackward , +// pstrUsageMoveUpDown , +// pstrUsageLeanRightLeft , +// pstrUsageLeanForwardBackward , +// pstrUsageHeightOfPOV , +// pstrUsageFlipper , +// pstrUsageSecondaryFlipper , +// pstrUsageBump , +// pstrUsageNewGame , +// pstrUsageShootBall , +// pstrUsagePlayer , +// pstrUsageGunBolt , +// pstrUsageGunClip , +// pstrUsageGunSelector , +// pstrUsageGunSingleShot , +// pstrUsageGunBurst , +// pstrUsageGunAutomatic , +// pstrUsageGunSafety , +// pstrUsageGamepadFireJump , +// pstrUsageGamepadTrigger +//}; +//const char *genDevCtrlTitles[] PROGMEM = +//{ +// pstrUsageBatteryStrength, +// pstrUsageWirelessChannel, +// pstrUsageWirelessID, +// pstrUsageDiscoverWirelessControl, +// pstrUsageSecurityCodeCharEntered, +// pstrUsageSecurityCodeCharErased, +// pstrUsageSecurityCodeCleared +//}; +//const char *ledTitles[] PROGMEM = +//{ +// pstrUsageNumLock , +// pstrUsageCapsLock , +// pstrUsageScrollLock , +// pstrUsageCompose , +// pstrUsageKana , +// pstrUsagePower , +// pstrUsageShift , +// pstrUsageDoNotDisturb , +// pstrUsageMute , +// pstrUsageToneEnable , +// pstrUsageHighCutFilter , +// pstrUsageLowCutFilter , +// pstrUsageEqualizerEnable , +// pstrUsageSoundFieldOn , +// pstrUsageSurroundOn , +// pstrUsageRepeat , +// pstrUsageStereo , +// pstrUsageSamplingRateDetect , +// pstrUsageSpinning , +// pstrUsageCAV , +// pstrUsageCLV , +// pstrUsageRecordingFormatDetect , +// pstrUsageOffHook , +// pstrUsageRing , +// pstrUsageMessageWaiting , +// pstrUsageDataMode , +// pstrUsageBatteryOperation , +// pstrUsageBatteryOK , +// pstrUsageBatteryLow , +// pstrUsageSpeaker , +// pstrUsageHeadSet , +// pstrUsageHold , +// pstrUsageMicrophone , +// pstrUsageCoverage , +// pstrUsageNightMode , +// pstrUsageSendCalls , +// pstrUsageCallPickup , +// pstrUsageConference , +// pstrUsageStandBy , +// pstrUsageCameraOn , +// pstrUsageCameraOff , +// pstrUsageOnLine , +// pstrUsageOffLine , +// pstrUsageBusy , +// pstrUsageReady , +// pstrUsagePaperOut , +// pstrUsagePaperJam , +// pstrUsageRemote , +// pstrUsageForward , +// pstrUsageReverse , +// pstrUsageStop , +// pstrUsageRewind , +// pstrUsageFastForward , +// pstrUsagePlay , +// pstrUsagePause , +// pstrUsageRecord , +// pstrUsageError , +// pstrUsageSelectedIndicator , +// pstrUsageInUseIndicator , +// pstrUsageMultiModeIndicator , +// pstrUsageIndicatorOn , +// pstrUsageIndicatorFlash , +// pstrUsageIndicatorSlowBlink , +// pstrUsageIndicatorFastBlink , +// pstrUsageIndicatorOff , +// pstrUsageFlashOnTime , +// pstrUsageSlowBlinkOnTime , +// pstrUsageSlowBlinkOffTime , +// pstrUsageFastBlinkOnTime , +// pstrUsageFastBlinkOffTime , +// pstrUsageIndicatorColor , +// pstrUsageIndicatorRed , +// pstrUsageIndicatorGreen , +// pstrUsageIndicatorAmber , +// pstrUsageGenericIndicator , +// pstrUsageSystemSuspend , +// pstrUsageExternalPowerConnected +//}; +//const char *telTitles0 [] PROGMEM = +//{ +// pstrUsagePhone , +// pstrUsageAnsweringMachine , +// pstrUsageMessageControls , +// pstrUsageHandset , +// pstrUsageHeadset , +// pstrUsageTelephonyKeyPad , +// pstrUsageProgrammableButton +//}; +//const char *telTitles1 [] PROGMEM = +//{ +// pstrUsageHookSwitch , +// pstrUsageFlash , +// pstrUsageFeature , +// pstrUsageHold , +// pstrUsageRedial , +// pstrUsageTransfer , +// pstrUsageDrop , +// pstrUsagePark , +// pstrUsageForwardCalls , +// pstrUsageAlternateFunction , +// pstrUsageLine , +// pstrUsageSpeakerPhone , +// pstrUsageConference , +// pstrUsageRingEnable , +// pstrUsageRingSelect , +// pstrUsagePhoneMute , +// pstrUsageCallerID , +// pstrUsageSend +//}; +//const char *telTitles2 [] PROGMEM = +//{ +// pstrUsageSpeedDial , +// pstrUsageStoreNumber , +// pstrUsageRecallNumber , +// pstrUsagePhoneDirectory +//}; +//const char *telTitles3 [] PROGMEM = +//{ +// pstrUsageVoiceMail , +// pstrUsageScreenCalls , +// pstrUsageDoNotDisturb , +// pstrUsageMessage , +// pstrUsageAnswerOnOff +//}; +//const char *telTitles4 [] PROGMEM = +//{ +// pstrUsageInsideDialTone , +// pstrUsageOutsideDialTone , +// pstrUsageInsideRingTone , +// pstrUsageOutsideRingTone , +// pstrUsagePriorityRingTone , +// pstrUsageInsideRingback , +// pstrUsagePriorityRingback , +// pstrUsageLineBusyTone , +// pstrUsageReorderTone , +// pstrUsageCallWaitingTone , +// pstrUsageConfirmationTone1 , +// pstrUsageConfirmationTone2 , +// pstrUsageTonesOff , +// pstrUsageOutsideRingback , +// pstrUsageRinger +//}; +//const char *telTitles5 [] PROGMEM = +//{ +// pstrUsagePhoneKey0 , +// pstrUsagePhoneKey1 , +// pstrUsagePhoneKey2 , +// pstrUsagePhoneKey3 , +// pstrUsagePhoneKey4 , +// pstrUsagePhoneKey5 , +// pstrUsagePhoneKey6 , +// pstrUsagePhoneKey7 , +// pstrUsagePhoneKey8 , +// pstrUsagePhoneKey9 , +// pstrUsagePhoneKeyStar , +// pstrUsagePhoneKeyPound , +// pstrUsagePhoneKeyA , +// pstrUsagePhoneKeyB , +// pstrUsagePhoneKeyC , +// pstrUsagePhoneKeyD +//}; +//const char *consTitles0[] PROGMEM = +//{ +// pstrUsageConsumerControl, +// pstrUsageNumericKeyPad, +// pstrUsageProgrammableButton, +// pstrUsageMicrophone, +// pstrUsageHeadphone, +// pstrUsageGraphicEqualizer +//}; +//const char *consTitles1[] PROGMEM = +//{ +// pstrUsagePlus10 , +// pstrUsagePlus100, +// pstrUsageAMPM +//}; +//const char *consTitles2[] PROGMEM = +//{ +// pstrUsagePower , +// pstrUsageReset , +// pstrUsageSleep , +// pstrUsageSleepAfter , +// pstrUsageSleepMode , +// pstrUsageIllumination , +// pstrUsageFunctionButtons +// +//}; +//const char *consTitles3[] PROGMEM = +//{ +// pstrUsageMenu , +// pstrUsageMenuPick , +// pstrUsageMenuUp , +// pstrUsageMenuDown , +// pstrUsageMenuLeft , +// pstrUsageMenuRight , +// pstrUsageMenuEscape , +// pstrUsageMenuValueIncrease, +// pstrUsageMenuValueDecrease +//}; +//const char *consTitles4[] PROGMEM = +//{ +// pstrUsageDataOnScreen , +// pstrUsageClosedCaption , +// pstrUsageClosedCaptionSelect, +// pstrUsageVCRTV , +// pstrUsageBroadcastMode , +// pstrUsageSnapshot , +// pstrUsageStill +//}; +//const char *consTitles5[] PROGMEM = +//{ +// pstrUsageSelection , +// pstrUsageAssignSelection , +// pstrUsageModeStep , +// pstrUsageRecallLast , +// pstrUsageEnterChannel , +// pstrUsageOrderMovie , +// pstrUsageChannel , +// pstrUsageMediaSelection , +// pstrUsageMediaSelectComputer , +// pstrUsageMediaSelectTV , +// pstrUsageMediaSelectWWW , +// pstrUsageMediaSelectDVD , +// pstrUsageMediaSelectTelephone , +// pstrUsageMediaSelectProgramGuide , +// pstrUsageMediaSelectVideoPhone , +// pstrUsageMediaSelectGames , +// pstrUsageMediaSelectMessages , +// pstrUsageMediaSelectCD , +// pstrUsageMediaSelectVCR , +// pstrUsageMediaSelectTuner , +// pstrUsageQuit , +// pstrUsageHelp , +// pstrUsageMediaSelectTape , +// pstrUsageMediaSelectCable , +// pstrUsageMediaSelectSatellite , +// pstrUsageMediaSelectSecurity , +// pstrUsageMediaSelectHome , +// pstrUsageMediaSelectCall , +// pstrUsageChannelIncrement , +// pstrUsageChannelDecrement , +// pstrUsageMediaSelectSAP , +// pstrUsagePageReserved , +// pstrUsageVCRPlus , +// pstrUsageOnce , +// pstrUsageDaily , +// pstrUsageWeekly , +// pstrUsageMonthly +//}; +//const char *consTitles6[] PROGMEM = +//{ +// pstrUsagePlay , +// pstrUsagePause , +// pstrUsageRecord , +// pstrUsageFastForward , +// pstrUsageRewind , +// pstrUsageScanNextTrack , +// pstrUsageScanPreviousTrack , +// pstrUsageStop , +// pstrUsageEject , +// pstrUsageRandomPlay , +// pstrUsageSelectDisk , +// pstrUsageEnterDisk , +// pstrUsageRepeat , +// pstrUsageTracking , +// pstrUsageTrackNormal , +// pstrUsageSlowTracking , +// pstrUsageFrameForward , +// pstrUsageFrameBackwards , +// pstrUsageMark , +// pstrUsageClearMark , +// pstrUsageRepeatFromMark , +// pstrUsageReturnToMark , +// pstrUsageSearchMarkForward , +// pstrUsageSearchMarkBackwards , +// pstrUsageCounterReset , +// pstrUsageShowCounter , +// pstrUsageTrackingIncrement , +// pstrUsageTrackingDecrement , +// pstrUsageStopEject , +// pstrUsagePlayPause , +// pstrUsagePlaySkip +//}; +//const char *consTitles7[] PROGMEM = +//{ +// pstrUsageVolume , +// pstrUsageBalance , +// pstrUsageMute , +// pstrUsageBass , +// pstrUsageTreble , +// pstrUsageBassBoost , +// pstrUsageSurroundMode , +// pstrUsageLoudness , +// pstrUsageMPX , +// pstrUsageVolumeIncrement , +// pstrUsageVolumeDecrement +//}; +//const char *consTitles8[] PROGMEM = +//{ +// pstrUsageSpeedSelect , +// pstrUsagePlaybackSpeed , +// pstrUsageStandardPlay , +// pstrUsageLongPlay , +// pstrUsageExtendedPlay , +// pstrUsageSlow +//}; +//const char *consTitles9[] PROGMEM = +//{ +// pstrUsageFanEnable , +// pstrUsageFanSpeed , +// pstrUsageLightEnable , +// pstrUsageLightIlluminationLevel , +// pstrUsageClimateControlEnable , +// pstrUsageRoomTemperature , +// pstrUsageSecurityEnable , +// pstrUsageFireAlarm , +// pstrUsagePoliceAlarm , +// pstrUsageProximity , +// pstrUsageMotion , +// pstrUsageDuresAlarm , +// pstrUsageHoldupAlarm , +// pstrUsageMedicalAlarm +//}; +//const char *consTitlesA[] PROGMEM = +//{ +// pstrUsageBalanceRight , +// pstrUsageBalanceLeft , +// pstrUsageBassIncrement , +// pstrUsageBassDecrement , +// pstrUsageTrebleIncrement , +// pstrUsageTrebleDecrement +//}; +//const char *consTitlesB[] PROGMEM = +//{ +// pstrUsageSpeakerSystem , +// pstrUsageChannelLeft , +// pstrUsageChannelRight , +// pstrUsageChannelCenter , +// pstrUsageChannelFront , +// pstrUsageChannelCenterFront , +// pstrUsageChannelSide , +// pstrUsageChannelSurround , +// pstrUsageChannelLowFreqEnhancement , +// pstrUsageChannelTop , +// pstrUsageChannelUnknown +//}; +//const char *consTitlesC[] PROGMEM = +//{ +// pstrUsageSubChannel , +// pstrUsageSubChannelIncrement , +// pstrUsageSubChannelDecrement , +// pstrUsageAlternateAudioIncrement , +// pstrUsageAlternateAudioDecrement +//}; +//const char *consTitlesD[] PROGMEM = +//{ +// pstrUsageApplicationLaunchButtons , +// pstrUsageALLaunchButtonConfigTool , +// pstrUsageALProgrammableButton , +// pstrUsageALConsumerControlConfig , +// pstrUsageALWordProcessor , +// pstrUsageALTextEditor , +// pstrUsageALSpreadsheet , +// pstrUsageALGraphicsEditor , +// pstrUsageALPresentationApp , +// pstrUsageALDatabaseApp , +// pstrUsageALEmailReader , +// pstrUsageALNewsreader , +// pstrUsageALVoicemail , +// pstrUsageALContactsAddressBook , +// pstrUsageALCalendarSchedule , +// pstrUsageALTaskProjectManager , +// pstrUsageALLogJournalTimecard , +// pstrUsageALCheckbookFinance , +// pstrUsageALCalculator , +// pstrUsageALAVCapturePlayback , +// pstrUsageALLocalMachineBrowser , +// pstrUsageALLANWANBrow , +// pstrUsageALInternetBrowser , +// pstrUsageALRemoteNetISPConnect , +// pstrUsageALNetworkConference , +// pstrUsageALNetworkChat , +// pstrUsageALTelephonyDialer , +// pstrUsageALLogon , +// pstrUsageALLogoff , +// pstrUsageALLogonLogoff , +// pstrUsageALTermLockScrSav , +// pstrUsageALControlPannel , +// pstrUsageALCommandLineProcessorRun , +// pstrUsageALProcessTaskManager , +// pstrUsageALSelectTaskApplication , +// pstrUsageALNextTaskApplication , +// pstrUsageALPreviousTaskApplication , +// pstrUsageALPreemptiveHaltTaskApp , +// pstrUsageALIntegratedHelpCenter , +// pstrUsageALDocuments , +// pstrUsageALThesaurus , +// pstrUsageALDictionary , +// pstrUsageALDesktop , +// pstrUsageALSpellCheck , +// pstrUsageALGrammarCheck , +// pstrUsageALWirelessStatus , +// pstrUsageALKeyboardLayout , +// pstrUsageALVirusProtection , +// pstrUsageALEncryption , +// pstrUsageALScreenSaver , +// pstrUsageALAlarms , +// pstrUsageALClock , +// pstrUsageALFileBrowser , +// pstrUsageALPowerStatus , +// pstrUsageALImageBrowser , +// pstrUsageALAudioBrowser , +// pstrUsageALMovieBrowser , +// pstrUsageALDigitalRightsManager , +// pstrUsageALDigitalWallet , +// pstrUsagePageReserved , +// pstrUsageALInstantMessaging , +// pstrUsageALOEMFeaturesBrowser , +// pstrUsageALOEMHelp , +// pstrUsageALOnlineCommunity , +// pstrUsageALEntertainmentContentBrow , +// pstrUsageALOnlineShoppingBrowser , +// pstrUsageALSmartCardInfoHelp , +// pstrUsageALMarketMonitorFinBrowser , +// pstrUsageALCustomCorpNewsBrowser , +// pstrUsageALOnlineActivityBrowser , +// pstrUsageALResearchSearchBrowser , +// pstrUsageALAudioPlayer +//}; +//const char *consTitlesE[] PROGMEM = +//{ +// pstrUsageGenericGUIAppControls , +// pstrUsageACNew , +// pstrUsageACOpen , +// pstrUsageACClose , +// pstrUsageACExit , +// pstrUsageACMaximize , +// pstrUsageACMinimize , +// pstrUsageACSave , +// pstrUsageACPrint , +// pstrUsageACProperties , +// pstrUsageACUndo , +// pstrUsageACCopy , +// pstrUsageACCut , +// pstrUsageACPaste , +// pstrUsageACSelectAll , +// pstrUsageACFind , +// pstrUsageACFindAndReplace , +// pstrUsageACSearch , +// pstrUsageACGoto , +// pstrUsageACHome , +// pstrUsageACBack , +// pstrUsageACForward , +// pstrUsageACStop , +// pstrUsageACRefresh , +// pstrUsageACPreviousLink , +// pstrUsageACNextLink , +// pstrUsageACBookmarks , +// pstrUsageACHistory , +// pstrUsageACSubscriptions , +// pstrUsageACZoomIn , +// pstrUsageACZoomOut , +// pstrUsageACZoom , +// pstrUsageACFullScreenView , +// pstrUsageACNormalView , +// pstrUsageACViewToggle , +// pstrUsageACScrollUp , +// pstrUsageACScrollDown , +// pstrUsageACScroll , +// pstrUsageACPanLeft , +// pstrUsageACPanRight , +// pstrUsageACPan , +// pstrUsageACNewWindow , +// pstrUsageACTileHoriz , +// pstrUsageACTileVert , +// pstrUsageACFormat , +// pstrUsageACEdit , +// pstrUsageACBold , +// pstrUsageACItalics , +// pstrUsageACUnderline , +// pstrUsageACStrikethrough , +// pstrUsageACSubscript , +// pstrUsageACSuperscript , +// pstrUsageACAllCaps , +// pstrUsageACRotate , +// pstrUsageACResize , +// pstrUsageACFlipHorizontal , +// pstrUsageACFlipVertical , +// pstrUsageACMirrorHorizontal , +// pstrUsageACMirrorVertical , +// pstrUsageACFontSelect , +// pstrUsageACFontColor , +// pstrUsageACFontSize , +// pstrUsageACJustifyLeft , +// pstrUsageACJustifyCenterH , +// pstrUsageACJustifyRight , +// pstrUsageACJustifyBlockH , +// pstrUsageACJustifyTop , +// pstrUsageACJustifyCenterV , +// pstrUsageACJustifyBottom , +// pstrUsageACJustifyBlockV , +// pstrUsageACIndentDecrease , +// pstrUsageACIndentIncrease , +// pstrUsageACNumberedList , +// pstrUsageACRestartNumbering , +// pstrUsageACBulletedList , +// pstrUsageACPromote , +// pstrUsageACDemote , +// pstrUsageACYes , +// pstrUsageACNo , +// pstrUsageACCancel , +// pstrUsageACCatalog , +// pstrUsageACBuyChkout , +// pstrUsageACAddToCart , +// pstrUsageACExpand , +// pstrUsageACExpandAll , +// pstrUsageACCollapse , +// pstrUsageACCollapseAll , +// pstrUsageACPrintPreview , +// pstrUsageACPasteSpecial , +// pstrUsageACInsertMode , +// pstrUsageACDelete , +// pstrUsageACLock , +// pstrUsageACUnlock , +// pstrUsageACProtect , +// pstrUsageACUnprotect , +// pstrUsageACAttachComment , +// pstrUsageACDeleteComment , +// pstrUsageACViewComment , +// pstrUsageACSelectWord , +// pstrUsageACSelectSentence , +// pstrUsageACSelectParagraph , +// pstrUsageACSelectColumn , +// pstrUsageACSelectRow , +// pstrUsageACSelectTable , +// pstrUsageACSelectObject , +// pstrUsageACRedoRepeat , +// pstrUsageACSort , +// pstrUsageACSortAscending , +// pstrUsageACSortDescending , +// pstrUsageACFilter , +// pstrUsageACSetClock , +// pstrUsageACViewClock , +// pstrUsageACSelectTimeZone , +// pstrUsageACEditTimeZone , +// pstrUsageACSetAlarm , +// pstrUsageACClearAlarm , +// pstrUsageACSnoozeAlarm , +// pstrUsageACResetAlarm , +// pstrUsageACSyncronize , +// pstrUsageACSendReceive , +// pstrUsageACSendTo , +// pstrUsageACReply , +// pstrUsageACReplyAll , +// pstrUsageACForwardMessage , +// pstrUsageACSend , +// pstrUsageACAttachFile , +// pstrUsageACUpload , +// pstrUsageACDownload , +// pstrUsageACSetBorders , +// pstrUsageACInsertRow , +// pstrUsageACInsertColumn , +// pstrUsageACInsertFile , +// pstrUsageACInsertPicture , +// pstrUsageACInsertObject , +// pstrUsageACInsertSymbol , +// pstrUsageACSaveAndClose , +// pstrUsageACRename , +// pstrUsageACMerge , +// pstrUsageACSplit , +// pstrUsageACDistributeHorizontaly , +// pstrUsageACDistributeVerticaly +//}; +//const char *digitTitles0[] PROGMEM = +//{ +// pstrUsageDigitizer , +// pstrUsagePen , +// pstrUsageLightPen , +// pstrUsageTouchScreen , +// pstrUsageTouchPad , +// pstrUsageWhiteBoard , +// pstrUsageCoordinateMeasuringMachine , +// pstrUsage3DDigitizer , +// pstrUsageStereoPlotter , +// pstrUsageArticulatedArm , +// pstrUsageArmature , +// pstrUsageMultiplePointDigitizer , +// pstrUsageFreeSpaceWand +//}; +//const char *digitTitles1[] PROGMEM = +//{ +// pstrUsageStylus , +// pstrUsagePuck , +// pstrUsageFinger +// +//}; +//const char *digitTitles2[] PROGMEM = +//{ +// pstrUsageTipPressure , +// pstrUsageBarrelPressure , +// pstrUsageInRange , +// pstrUsageTouch , +// pstrUsageUntouch , +// pstrUsageTap , +// pstrUsageQuality , +// pstrUsageDataValid , +// pstrUsageTransducerIndex , +// pstrUsageTabletFunctionKeys , +// pstrUsageProgramChangeKeys , +// pstrUsageBatteryStrength , +// pstrUsageInvert , +// pstrUsageXTilt , +// pstrUsageYTilt , +// pstrUsageAzimuth , +// pstrUsageAltitude , +// pstrUsageTwist , +// pstrUsageTipSwitch , +// pstrUsageSecondaryTipSwitch , +// pstrUsageBarrelSwitch , +// pstrUsageEraser , +// pstrUsageTabletPick +//}; +//const char *aplphanumTitles0[] PROGMEM = +//{ +// pstrUsageAlphanumericDisplay, +// pstrUsageBitmappedDisplay +//}; +//const char *aplphanumTitles1[] PROGMEM = +//{ +// pstrUsageDisplayAttributesReport , +// pstrUsageASCIICharacterSet , +// pstrUsageDataReadBack , +// pstrUsageFontReadBack , +// pstrUsageDisplayControlReport , +// pstrUsageClearDisplay , +// pstrUsageDisplayEnable , +// pstrUsageScreenSaverDelay , +// pstrUsageScreenSaverEnable , +// pstrUsageVerticalScroll , +// pstrUsageHorizontalScroll , +// pstrUsageCharacterReport , +// pstrUsageDisplayData , +// pstrUsageDisplayStatus , +// pstrUsageStatusNotReady , +// pstrUsageStatusReady , +// pstrUsageErrorNotALoadableCharacter , +// pstrUsageErrorFotDataCanNotBeRead , +// pstrUsageCursorPositionReport , +// pstrUsageRow , +// pstrUsageColumn , +// pstrUsageRows , +// pstrUsageColumns , +// pstrUsageCursorPixelPosition , +// pstrUsageCursorMode , +// pstrUsageCursorEnable , +// pstrUsageCursorBlink , +// pstrUsageFontReport , +// pstrUsageFontData , +// pstrUsageCharacterWidth , +// pstrUsageCharacterHeight , +// pstrUsageCharacterSpacingHorizontal , +// pstrUsageCharacterSpacingVertical , +// pstrUsageUnicodeCharset , +// pstrUsageFont7Segment , +// pstrUsage7SegmentDirectMap , +// pstrUsageFont14Segment , +// pstrUsage14SegmentDirectMap , +// pstrUsageDisplayBrightness , +// pstrUsageDisplayContrast , +// pstrUsageCharacterAttribute , +// pstrUsageAttributeReadback , +// pstrUsageAttributeData , +// pstrUsageCharAttributeEnhance , +// pstrUsageCharAttributeUnderline , +// pstrUsageCharAttributeBlink +//}; +//const char *aplphanumTitles2[] PROGMEM = +//{ +// pstrUsageBitmapSizeX , +// pstrUsageBitmapSizeY , +// pstrUsagePageReserved , +// pstrUsageBitDepthFormat , +// pstrUsageDisplayOrientation , +// pstrUsagePaletteReport , +// pstrUsagePaletteDataSize , +// pstrUsagePaletteDataOffset , +// pstrUsagePaletteData , +// pstrUsageBlitReport , +// pstrUsageBlitRectangleX1 , +// pstrUsageBlitRectangleY1 , +// pstrUsageBlitRectangleX2 , +// pstrUsageBlitRectangleY2 , +// pstrUsageBlitData , +// pstrUsageSoftButton , +// pstrUsageSoftButtonID , +// pstrUsageSoftButtonSide , +// pstrUsageSoftButtonOffset1 , +// pstrUsageSoftButtonOffset2 , +// pstrUsageSoftButtonReport +//}; +//const char *medInstrTitles0[] PROGMEM = +//{ +// pstrUsageVCRAcquisition , +// pstrUsageFreezeThaw , +// pstrUsageClipStore , +// pstrUsageUpdate , +// pstrUsageNext , +// pstrUsageSave , +// pstrUsagePrint , +// pstrUsageMicrophoneEnable +//}; +//const char *medInstrTitles1[] PROGMEM = +//{ +// pstrUsageCine , +// pstrUsageTransmitPower , +// pstrUsageVolume , +// pstrUsageFocus , +// pstrUsageDepth +//}; +//const char *medInstrTitles2[] PROGMEM = +//{ +// pstrUsageSoftStepPrimary , +// pstrUsageSoftStepSecondary +//}; +//const char *medInstrTitles3[] PROGMEM = +//{ +// pstrUsageZoomSelect , +// pstrUsageZoomAdjust , +// pstrUsageSpectralDopplerModeSelect , +// pstrUsageSpectralDopplerModeAdjust , +// pstrUsageColorDopplerModeSelect , +// pstrUsageColorDopplerModeAdjust , +// pstrUsageMotionModeSelect , +// pstrUsageMotionModeAdjust , +// pstrUsage2DModeSelect , +// pstrUsage2DModeAdjust +//}; +//const char *medInstrTitles4[] PROGMEM = +//{ +// pstrUsageSoftControlSelect , +// pstrUsageSoftControlAdjust +//}; + #endif // __HIDUSAGETITLEARRAYS_H__ \ No newline at end of file diff --git a/masstorage.cpp b/masstorage.cpp index e95fd0d0..dde10114 100644 --- a/masstorage.cpp +++ b/masstorage.cpp @@ -1,646 +1,861 @@ -#include "masstorage.h" - - -//bool BulkReadParser::IsValidCSW(uint8_t size, uint8_t *pcsw) -//{ -// if (size != 0x0d) -// { -// Notify(PSTR("CSW:Size error")); -// return false; -// } -// if (*((uint32_t*)pcsw) != MASS_CSW_SIGNATURE) -// { -// Notify(PSTR("CSW:Sig error")); -// return false; -// } -// //if (size != 0x0d || *((uint32_t*)pcsw) != MASS_CSW_SIGNATURE || -// // ((CommandStatusWrapper*)pcsw)->dCSWTag != dCBWTag) -// // return false; -// return true; -//} - -//bool BulkReadParser::IsMeaningfulCSW(uint8_t size, uint8_t *pcsw) -//{ -// if (((CommandStatusWrapper*)pcsw)->bCSWStatus < 2 && -// ((CommandStatusWrapper*)pcsw)->dCSWDataResidue <= dCBWDataTransferLength ) -// return true; -// if ( ((CommandStatusWrapper*)pcsw)->bCSWStatus == 2 ) -// return true; -// return false; -//} - -//void BulkReadParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) -//{ -// if (offset == 0 && len > sizeof(CommandStatusWrapper)) -// if (IsValidCSW(sizeof(CommandStatusWrapper), pbuf) && IsMeaningfulCSW(sizeof(CommandStatusWrapper), pbuf)) -// { -// CommandStatusWrapper *pCSW = (CommandStatusWrapper*)pbuf; -// -// Serial.println("Sig:"); -// PrintHex(pCSW->dCSWSignature); -// Serial.println("Tag:"); -// PrintHex(pCSW->dCSWTag); -// Serial.println("Res:"); -// PrintHex(pCSW->dCSWDataResidue); -// Serial.println("Ret:"); -// PrintHex(pCSW->bCSWStatus); -// } -//} - -const uint8_t BulkOnly::epDataInIndex = 1; -const uint8_t BulkOnly::epDataOutIndex = 2; -const uint8_t BulkOnly::epInterruptInIndex = 3; - -BulkOnly::BulkOnly(USB *p /*, CDCAsyncOper *pasync*/) : - pUsb(p), - //pAsync(pasync), - bAddress(0), - qNextPollTime(0), - bPollEnable(false), - bIface(0), - bNumEP(1) -{ - for(uint8_t i=0; iRegisterDeviceClass(this); -} - -uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); - - uint8_t buf[constBufSize]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t num_of_conf; // number of configurations - - AddressPool &addrPool = pUsb->GetAddressPool(); - - USBTRACE("MS Init\r\n"); - - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - if (!p->epinfo) - { - USBTRACE("epinfo\r\n"); - 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, constBufSize, (uint8_t*)buf ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; - - if( rcode ) - goto FailGetDevDescr; - - // 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 the 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; - USBTRACE2("setAddr:",rcode); - return rcode; - } - - USBTRACE2("Addr:", bAddress); - - p->lowspeed = false; - - p = addrPool.GetUsbDevicePtr(bAddress); - - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - - p->lowspeed = lowspeed; - - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); - - if (rcode) - goto FailSetDevTblEntry; - - USBTRACE2("NC:", num_of_conf); - - for (uint8_t i=0; i HexDump; - ConfigDescParser< USB_CLASS_MASS_STORAGE, - MASS_SUBCLASS_SCSI, - MASS_PROTO_BBB, - CP_MASK_COMPARE_CLASS | - CP_MASK_COMPARE_SUBCLASS | - CP_MASK_COMPARE_PROTOCOL> BulkOnlyParser(this); - - rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); - rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); - - - if (bNumEP > 1) - break; - } // for - - if (bNumEP < 3) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - - USBTRACE2("Conf:", bConfNum); - - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, bConfNum); - - if (rcode) - goto FailSetConf; - - delay(5000); - - //rcode = pAsync->OnInit(this); - - //if (rcode) - // goto FailOnInit; - - rcode = GetMaxLUN(&bMaxLUN); - - if (rcode) - goto FailGetMaxLUN; - - delay(10); - - { - InquiryResponse response; - rcode = Inquiry(bMaxLUN, sizeof(InquiryResponse), (uint8_t*)&response); - - if (rcode) - goto FailInquiry; - - //if (response.DeviceType != 0) - // goto FailInvalidDevice; - } - - delay(10); - - USBTRACE("MS configured\r\n"); - - bPollEnable = true; - - //USBTRACE("Poll enabled\r\n"); - return 0; - -FailGetDevDescr: - USBTRACE("getDevDescr:"); - goto Fail; - -FailSetDevTblEntry: - USBTRACE("setDevTblEn:"); - goto Fail; - -FailGetConfDescr: - USBTRACE("getConf:"); - goto Fail; - -FailSetConf: - USBTRACE("setConf:"); - goto Fail; - -FailOnInit: - USBTRACE("OnInit:"); - goto Fail; - -FailGetMaxLUN: - USBTRACE("GetMaxLUN:"); - goto Fail; - -FailInquiry: - USBTRACE("Inquiry:"); - goto Fail; - -Fail: - Serial.println(rcode, HEX); - Release(); - return rcode; -} - - -void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) -{ - ErrorMessage(PSTR("Conf.Val"), conf); - ErrorMessage(PSTR("Iface Num"),iface); - ErrorMessage(PSTR("Alt.Set"), alt); - - bConfNum = conf; - - uint8_t index; - - if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - if ((pep->bmAttributes & 0x02) == 2) - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; - else - return; - - // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; - epInfo[index].epAttribs = 0; - - bNumEP ++; - - PrintEndpointDescriptor(pep); -} - -uint8_t BulkOnly::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); - - bIface = 0; - bNumEP = 1; - - bAddress = 0; - qNextPollTime = 0; - bPollEnable = false; - return 0; -} - -uint8_t BulkOnly::Poll() -{ - uint8_t rcode = 0; - - if (!bPollEnable) - return 0; - - uint32_t time_now = millis(); - - //if (qNextPollTime <= time_now) - //{ - // qNextPollTime = time_now + 100; - - // uint8_t rcode; - // const uint8_t constBufSize = 16; - // uint8_t buf[constBufSize]; - - // for (uint8_t i=0; i epInfo[epInterruptInIndex].maxPktSize) - // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; - // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); - - // if (rcode) - // return rcode; - - // for (uint8_t i=0; i(buf[i]); - // Serial.print(" "); - // } - // USBTRACE("\r\n"); - //} - return rcode; -} - -bool BulkOnly::IsValidCBW(uint8_t size, uint8_t *pcbw) -{ - if (size != 0x1f || *((uint32_t*)pcbw) != MASS_CBW_SIGNATURE) - return false; - return true; -} - -bool BulkOnly::IsMeaningfulCBW(uint8_t size, uint8_t *pcbw) -{ - if (((CommandBlockWrapper*)pcbw)->bmReserved1 != 0 || - ((CommandBlockWrapper*)pcbw)->bmReserved2 != 0 || - ((CommandBlockWrapper*)pcbw)->bmCBWLUN > bMaxLUN || - ((CommandBlockWrapper*)pcbw)->bmCBWCBLength > 0x10 ) - return false; - return true; -} - -uint8_t BulkOnly::Reset() -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL )); -} - -uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) -{ - uint8_t cnt = 3; - - bLastUsbError = pUsb->ctrlReq( bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL ); - - delay(10); - //Serial.println(F("bLastUsbError: ")); - //Serial.println(bLastUsbError); - - if (bLastUsbError == hrSTALL) - { - *plun = 0; - bLastUsbError = ClearEpHalt(epDataInIndex); - return MASS_ERR_SUCCESS; - } - if (bLastUsbError == hrJERR) - return MASS_ERR_DEVICE_DISCONNECTED; - else if (bLastUsbError) - return MASS_ERR_GENERAL_USB_ERROR; - return MASS_ERR_SUCCESS; -} - -uint8_t BulkOnly::HandleUsbError(uint8_t index) -{ - uint8_t count = 3; - - while (bLastUsbError && count) - { - switch (bLastUsbError) - { - case hrSUCCESS: - return MASS_ERR_SUCCESS; - case hrJERR: - bLastUsbError = hrSUCCESS; - return MASS_ERR_DEVICE_DISCONNECTED; - case hrSTALL: - bLastUsbError = ClearEpHalt(index); - break; - default: - return MASS_ERR_GENERAL_USB_ERROR; - } - count --; - } // while - - return MASS_ERR_SUCCESS; -} - -uint8_t BulkOnly::ClearEpHalt(uint8_t index) -{ - return (pUsb->ctrlReq( bAddress, 0, USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_ENDPOINT, - USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, epInfo[index].epAddr, 0, 0, NULL, NULL )); -} - -uint8_t BulkOnly::ResetRecovery() -{ - bLastUsbError = Reset(); - - if (bLastUsbError) - return bLastUsbError; - - delay(6); - - bLastUsbError = ClearEpHalt(epDataInIndex); - - if (bLastUsbError) - return bLastUsbError; - - delay(6); - - bLastUsbError = ClearEpHalt(epDataOutIndex); - - delay(6); - - return bLastUsbError; -} - -uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) -{ - CommandBlockWrapper cbw; - - cbw.dCBWSignature = MASS_CBW_SIGNATURE; - cbw.dCBWTag = 0xdeadbeef; - cbw.dCBWDataTransferLength = bsize; - cbw.bmCBWFlags = MASS_CMD_DIR_IN, - cbw.bmCBWLUN = lun; - cbw.bmCBWCBLength = 6; - - for (uint8_t i=0; i<16; i++) - cbw.CBWCB[i] = 0; - - cbw.CBWCB[0] = SCSI_CMD_INQUIRY; - cbw.CBWCB[4] = bsize; - - return Transaction(&cbw, bsize, buf, 0); -} - -uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) -{ - CommandBlockWrapper cbw; - - cbw.dCBWSignature = MASS_CBW_SIGNATURE; - cbw.dCBWTag = 0xdeadbeef; - cbw.dCBWDataTransferLength = size; - cbw.bmCBWFlags = MASS_CMD_DIR_IN, - cbw.bmCBWLUN = lun; - cbw.bmCBWCBLength = 6; - - for (uint8_t i=0; i<16; i++) - cbw.CBWCB[i] = 0; - - cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE; - cbw.CBWCB[4] = size; - - return Transaction(&cbw, size, buf, 0); -} - -uint8_t BulkOnly::ReadCapacity(uint8_t lun, uint16_t bsize, uint8_t *buf) -{ - CommandBlockWrapper cbw; - - cbw.dCBWSignature = MASS_CBW_SIGNATURE; - cbw.dCBWTag = 0xdeadbeef; - cbw.dCBWDataTransferLength = bsize; - cbw.bmCBWFlags = MASS_CMD_DIR_IN, - cbw.bmCBWLUN = lun; - cbw.bmCBWCBLength = 10; - - for (uint8_t i=0; i<16; i++) - cbw.CBWCB[i] = 0; - - cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10; - cbw.CBWCB[4] = bsize; - - return Transaction(&cbw, bsize, buf, 0); -} - -uint8_t BulkOnly::TestUnitReady(uint8_t lun) -{ - CommandBlockWrapper cbw; - - cbw.dCBWSignature = MASS_CBW_SIGNATURE; - cbw.dCBWTag = 0xdeadbeef; - cbw.dCBWDataTransferLength = 0; - cbw.bmCBWFlags = MASS_CMD_DIR_OUT, - cbw.bmCBWLUN = lun; - cbw.bmCBWCBLength = 6; - - for (uint8_t i=0; i<16; i++) - cbw.CBWCB[i] = 0; - - cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY; - - return Transaction(&cbw, 0, NULL, 0); -} - -uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs) -{ - CommandBlockWrapper cbw; - - cbw.dCBWSignature = MASS_CBW_SIGNATURE; - cbw.dCBWTag = 0xdeadbeef; - cbw.dCBWDataTransferLength = bsize; - cbw.bmCBWFlags = MASS_CMD_DIR_IN, - cbw.bmCBWLUN = lun; - cbw.bmCBWCBLength = 10; - - for (uint8_t i=0; i<16; i++) - cbw.CBWCB[i] = 0; - - cbw.CBWCB[0] = SCSI_CMD_READ_10; - cbw.CBWCB[8] = 1; - cbw.CBWCB[5] = (addr & 0xff); - cbw.CBWCB[4] = ((addr >> 8) & 0xff); - cbw.CBWCB[3] = ((addr >> 16) & 0xff); - cbw.CBWCB[2] = ((addr >> 24) & 0xff); - - return Transaction(&cbw, bsize, prs, 1); -} - -uint8_t BulkOnly::Transaction(CommandBlockWrapper *cbw, uint16_t size, void *buf, uint8_t flags) -{ - uint16_t read; - { - bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof(CommandBlockWrapper), (uint8_t*)cbw); - - uint8_t ret = HandleUsbError(epDataOutIndex); - - if (ret) - { - ErrorMessage(PSTR("CBW"), ret); - return ret; - } - } - - if (size && buf) - { - read = size; - - if (cbw->bmCBWFlags & MASS_CMD_DIR_IN) - { - if ((flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK) - { - const uint8_t bufSize = 64; - uint16_t total = size; - uint16_t count = 0; - uint8_t rbuf[bufSize]; - - read = bufSize; - - while(count < total && - ((bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)rbuf)) == hrSUCCESS) - ) - { - ((USBReadParser*)buf)->Parse(read, rbuf, count); - - count += read; - read = bufSize; - } - - if (bLastUsbError == hrSTALL) - bLastUsbError = ClearEpHalt(epDataInIndex); - - if (bLastUsbError) - { - ErrorMessage(PSTR("RDR"), bLastUsbError); - return MASS_ERR_GENERAL_USB_ERROR; - } - } // if ((flags & 1) == 1) - else - bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)buf); - } // if (cbw->bmCBWFlags & MASS_CMD_DIR_IN) - - else if (cbw->bmCBWFlags & MASS_CMD_DIR_OUT) - bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, read, (uint8_t*)buf); - } - - uint8_t ret = HandleUsbError((cbw->bmCBWFlags & MASS_CMD_DIR_IN) ? epDataInIndex : epDataOutIndex); - - if (ret) - { - ErrorMessage(PSTR("RSP"), ret); - return MASS_ERR_GENERAL_USB_ERROR; - } - { - CommandStatusWrapper csw; - read = sizeof(CommandStatusWrapper); - - bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)&csw); - - uint8_t ret = HandleUsbError(epDataInIndex); - - if (ret) - { - ErrorMessage(PSTR("CSW"), ret); - return ret; - } - //if (csw.bCSWStatus == MASS_ERR_PHASE_ERROR) - // bLastUsbError = ResetRecovery(); - - return csw.bCSWStatus; - } - //return MASS_ERR_SUCCESS; -} - -void BulkOnly::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) -{ - Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval); - Notify(PSTR("\r\n")); -} +#include "masstorage.h" +const uint8_t BulkOnly::epDataInIndex = 1; +const uint8_t BulkOnly::epDataOutIndex = 2; +const uint8_t BulkOnly::epInterruptInIndex = 3; + +bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) { + if (pcsw->dCSWSignature != MASS_CSW_SIGNATURE) { + Notify(PSTR("CSW:Sig error\r\n"), 0x80); + return false; + } + if (pcsw->dCSWTag != pcbw->dCBWTag) { + Notify(PSTR("CSW:Wrong tag\r\n"), 0x80); + return false; + } + return true; +} + +BulkOnly::BulkOnly(USB *p) : +pUsb(p), +bAddress(0), +bIface(0), +bNumEP(1), +qNextPollTime(0), +bPollEnable(false), +dCBWTag(0), +bLastUsbError(0) { + for (uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + + if (!i) + epInfo[i].bmNakPower = USB_NAK_MAX_POWER; + } + if (pUsb) + pUsb->RegisterDeviceClass(this); +} + +uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { + + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + for (uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + + if (!i) + epInfo[i].bmNakPower = USB_NAK_MAX_POWER; + } + + AddressPool &addrPool = pUsb->GetAddressPool(); + + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + USBTRACE("MS Init\r\n"); + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { + USBTRACE("epinfo\r\n"); + 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, constBufSize, (uint8_t*)buf); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) { + goto FailGetDevDescr; + } + // 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 the 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; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i = 0; i < num_of_conf; i++) { + ConfigDescParser< USB_CLASS_MASS_STORAGE, + MASS_SUBCLASS_SCSI, + MASS_PROTO_BBB, + CP_MASK_COMPARE_CLASS | + CP_MASK_COMPARE_SUBCLASS | + CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); + + if (rcode) + goto FailGetConfDescr; + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 3) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConf; + + delay(10000); + + rcode = GetMaxLUN(&bMaxLUN); + if (rcode) + goto FailGetMaxLUN; + + ErrorMessage (PSTR("MaxLUN"), bMaxLUN); + + delay(10); + + bTheLUN = bMaxLUN; + + //if (bMaxLUN > 0) + { + for (uint8_t lun = 0; lun <= bMaxLUN; lun++) { + ErrorMessage (PSTR("\r\nLUN"), lun); + Notify(PSTR("--------\r\n"), 0x80); + + uint8_t count = 0; + + MediaCTL(lun, 0x01); + while (rcode = TestUnitReady(lun)) { + if (rcode == MASS_ERR_NO_MEDIA) + break; + + if (rcode == MASS_ERR_DEVICE_DISCONNECTED) + goto Fail; + + if (!count) + Notify(PSTR("Not ready...\r\n"), 0x80); + + if (count == 0xff) + break; + + delay(100); + count++; + } + if (count == 0xff) + continue; + + rcode = 0; + InquiryResponse response; + rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); + + if (rcode) + ErrorMessage (PSTR("Inquiry"), rcode); + + rcode = 0; + Capacity capacity; + rcode = ReadCapacity(lun, sizeof (Capacity), (uint8_t*) & capacity); + + if (rcode) + ErrorMessage (PSTR("ReadCapacity"), rcode); + else { + for (uint8_t i = 0; i (capacity.data[i], 0x80); + Notify(PSTR("\r\n\r\n"), 0x80); + // Only 512/1024/2048/4096 are valid values! + uint32_t c = ((uint32_t)capacity.data[4] << 24) + ((uint32_t)capacity.data[5] << 16) + ((uint32_t)capacity.data[6] << 8) + (uint32_t)capacity.data[7]; + if (c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) { + rcode = 255; + goto FailInvalidSectorSize; + } + } + + rcode = 0; +#if 0 + { + uint8_t buf[512]; + rcode = Read(lun, 0, 512, 1, buf); + + if (rcode) + ErrorMessage (PSTR("Read"), rcode); + else { + Notify(PSTR("Read: OK\r\n\r\n"), 0x80); + /* + for(int i=0; i<512; i++) { + PrintHex(buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n\r\n"), 0x80); + */ + } + } + { + uint8_t buf[192]; + rcode = ModeSense(lun, 0, 0x3f, 0, 192, buf); + + if (rcode) + ErrorMessage (PSTR("ModeSense"), rcode); + else + Notify(PSTR("ModeSense: OK\r\n\r\n"), 0x80); + } +#endif + } + Notify(PSTR("==========\r\n"), 0x80); + } + + if (TestUnitReady(bTheLUN)) { + Notify(PSTR("Unit not ready\r\n"), 0x80); + + rcode = MASS_ERR_UNIT_NOT_READY; + //goto FailOnInit; + } + + rcode = OnInit(); + + if (rcode) + goto FailOnInit; + + USBTRACE("MS configured\r\n\r\n"); + + bPollEnable = true; + + //USBTRACE("Poll enabled\r\n"); + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConf: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +FailGetMaxLUN: + USBTRACE("GetMaxLUN:"); + goto Fail; + +FailInquiry: + USBTRACE("Inquiry:"); + goto Fail; + +FailReadCapacity: + USBTRACE("ReadCapacity:"); + goto Fail; + +FailInvalidSectorSize: + USBTRACE("Sector Size is NOT VALID: "); + goto Fail; + +FailRead0: + USBTRACE("Read0:"); + goto Fail; + +FailModeSense0: + USBTRACE("ModeSense0:"); + goto Fail; + +FailModeSense1: + USBTRACE("ModeSense1:"); + goto Fail; + +Fail: + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); + //Serial.println(rcode, HEX); + Release(); + return rcode; +} + +void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { + ErrorMessage (PSTR("Conf.Val"), conf); + ErrorMessage (PSTR("Iface Num"), iface); + ErrorMessage (PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if ((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + + PrintEndpointDescriptor(pep); +} + +uint8_t BulkOnly::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + bIface = 0; + bNumEP = 1; + + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + bLastUsbError = 0; + bMaxLUN = 0; + bTheLUN = 0; + dCBWTag = 0; + return 0; +} + +uint8_t BulkOnly::Poll() { + uint8_t rcode = 0; + + if (!bPollEnable) + return 0; + + return rcode; +} + +uint8_t BulkOnly::Reset() { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL)); +} + +uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) { + uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL); + + if (ret == hrSTALL) + *plun = 0; + + return 0; +} + +uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { + uint8_t count = 3; + + bLastUsbError = error; + + while (error && count) { + if (error != hrSUCCESS) { + ErrorMessage (PSTR("USB Error"), error); + ErrorMessage (PSTR("Index"), index); + } + switch (error) { + case hrSUCCESS: return MASS_ERR_SUCCESS; + case hrBUSY: return MASS_ERR_UNIT_BUSY; + case hrTIMEOUT: + case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; + case hrSTALL: + if (index == 0) + return MASS_ERR_SUCCESS; + + error = ClearEpHalt(index); + //return MASS_ERR_STALL; + return MASS_ERR_SUCCESS; + + //error = ClearEpHalt(index); + //break; + case hrTOGERR: + if (bAddress && bConfNum) { + error = pUsb->setConf(bAddress, 0, bConfNum); + + if (error) + break; + } + return MASS_ERR_SUCCESS; + default: + ErrorMessage (PSTR("\r\nUSB"), error); + return MASS_ERR_GENERAL_USB_ERROR; + } + count--; + } // while + + return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); +} + +uint8_t BulkOnly::ClearEpHalt(uint8_t index) { + if (index == 0) + return 0; + + uint8_t ret = 0; + + ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, + USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)); + + ////ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE|USB_SETUP_RECIPIENT_ENDPOINT|USB_SETUP_TYPE_STANDARD, + ////USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, epInfo[index].epAddr, 0, 0, NULL, NULL)); + //// + if (ret) { + ErrorMessage (PSTR("ClearEpHalt"), ret); + ErrorMessage (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr)); + return ret; + } + epInfo[index].epAttribs = 0; + return 0; +} + +uint8_t BulkOnly::ResetRecovery() { + Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); + Notify(PSTR("-----------------\r\n"), 0x80); + + bLastUsbError = Reset(); + + if (bLastUsbError) { + return bLastUsbError; + } + delay(6); + + bLastUsbError = ClearEpHalt(epDataInIndex); + + if (bLastUsbError) { + return bLastUsbError; + } + delay(6); + + bLastUsbError = ClearEpHalt(epDataOutIndex); + + delay(6); + + return bLastUsbError; +} + +uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { + Notify(PSTR("\r\nInquiry\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = bsize; + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 6; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_INQUIRY; + cbw.CBWCB[4] = bsize; + + return HandleSCSIError(Transaction(&cbw, bsize, buf, 0)); +} + +uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) { + Notify(PSTR("\r\nRequestSense\r\n"), 0x80); + Notify(PSTR("----------------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = size; + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 6; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE; + cbw.CBWCB[4] = size; + + return HandleSCSIError(Transaction(&cbw, size, buf, 0)); +} + +uint8_t BulkOnly::ReadCapacity(uint8_t lun, uint16_t bsize, uint8_t *buf) { + Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); + Notify(PSTR("---------------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = bsize; + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 10; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10; + //cbw.CBWCB[4] = bsize; + + return HandleSCSIError(Transaction(&cbw, bsize, buf, 0)); +} + +uint8_t BulkOnly::TestUnitReady(uint8_t lun) { + if (!bAddress) // || !bPollEnable) + return MASS_ERR_UNIT_NOT_READY; + + Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80); + Notify(PSTR("-----------------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = 0; + cbw.bmCBWFlags = MASS_CMD_DIR_OUT, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 6; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY; + + return HandleSCSIError(Transaction(&cbw, 0, NULL, 0)); +} + +/* Media control: 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media */ +uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { + uint8_t rcode = MASS_ERR_UNIT_NOT_READY; + if (bAddress) { + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = 0; + cbw.bmCBWFlags = MASS_CMD_DIR_OUT, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 6; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_START_STOP_UNIT; + cbw.CBWCB[4] = ctl & 0x03; + + rcode = HandleSCSIError(Transaction(&cbw, 0, NULL, 0)); + } + return rcode; +} + +uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) { + Notify(PSTR("\r\nRead\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 10; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_READ_10; + cbw.CBWCB[8] = blocks; + cbw.CBWCB[2] = ((addr >> 24) & 0xff); + cbw.CBWCB[3] = ((addr >> 16) & 0xff); + cbw.CBWCB[4] = ((addr >> 8) & 0xff); + cbw.CBWCB[5] = (addr & 0xff); + return HandleSCSIError(Transaction(&cbw, bsize, buf, 0)); +} + +/* We won't be needing this... */ +uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs) { +#if 0 + Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 10; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_READ_10; + cbw.CBWCB[8] = blocks; + cbw.CBWCB[2] = ((addr >> 24) & 0xff); + cbw.CBWCB[3] = ((addr >> 16) & 0xff); + cbw.CBWCB[4] = ((addr >> 8) & 0xff); + cbw.CBWCB[5] = (addr & 0xff); + + return HandleSCSIError(Transaction(&cbw, bsize, prs, 1)); +#endif +} + +uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf) { + Notify(PSTR("\r\nWrite\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + //MediaCTL(lun, 0x01); + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); + cbw.bmCBWFlags = MASS_CMD_DIR_OUT, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 10; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_WRITE_10; + cbw.CBWCB[8] = 1; + cbw.CBWCB[5] = (addr & 0xff); + cbw.CBWCB[4] = ((addr >> 8) & 0xff); + cbw.CBWCB[3] = ((addr >> 16) & 0xff); + cbw.CBWCB[2] = ((addr >> 24) & 0xff); + + return HandleSCSIError(Transaction(&cbw, bsize, (void*)buf, 0)); +} + +uint8_t BulkOnly::ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *pbuf) { + Notify(PSTR("\r\rModeSense\r\n"), 0x80); + Notify(PSTR("------------\r\n"), 0x80); + + CommandBlockWrapper cbw; + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = len; + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 6; + + for (uint8_t i = 0; i < 16; i++) + cbw.CBWCB[i] = 0; + + cbw.CBWCB[0] = SCSI_CMD_MODE_SENSE_6; + cbw.CBWCB[2] = ((pc << 6) | page); + cbw.CBWCB[3] = subpage; + cbw.CBWCB[4] = len; + + return HandleSCSIError(Transaction(&cbw, 512, pbuf, 0)); +} + +uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, uint8_t flags) { + uint16_t read; + uint8_t ret = 0; + + ErrorMessage (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); + + ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); + + if (ret) { + ErrorMessage (PSTR("CBW"), ret); + return ret; + } + Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); + + ret = 0; + + read = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; + + if (read) { + if (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) { + if ((flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK) { + uint8_t rbuf[read]; + uint8_t err = 0; + ret = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, rbuf); + if (ret == hrSUCCESS) ((USBReadParser*)buf)->Parse(read, rbuf, 0); + if (ret == hrSTALL) err = ClearEpHalt(epDataInIndex); + if (ret) { + ErrorMessage (PSTR("RDR"), err); + return MASS_ERR_GENERAL_USB_ERROR; + } + } else + ret = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)buf); + } else + ret = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, read, (uint8_t*)buf); + + ret = HandleUsbError(ret, (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) ? epDataInIndex : epDataOutIndex); + + if (ret) { + ErrorMessage (PSTR("DAT"), ret); + return MASS_ERR_GENERAL_USB_ERROR; + } + + Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); + } + + uint8_t count = 2; + + while (count) { + CommandStatusWrapper csw; + read = sizeof (CommandStatusWrapper); + + ret = HandleUsbError(pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*) & csw), epDataInIndex); + + if (ret) { + ErrorMessage (PSTR("CSW"), ret); + count--; + continue; //return ret; + } + if (IsValidCSW(&csw, pcbw)) { + ErrorMessage (PSTR("CSW.dCBWTag"), csw.dCSWTag); + ErrorMessage (PSTR("bCSWStatus"), csw.bCSWStatus); + ErrorMessage (PSTR("dCSWDataResidue"), csw.dCSWDataResidue); + Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); + return csw.bCSWStatus; + } else { + Notify(PSTR("Invalid CSW\r\n"), 0x80); + ResetRecovery(); + return MASS_ERR_SUCCESS; //MASS_ERR_INVALID_CSW; + } + count--; + } + if (count) + ResetRecovery(); + + return MASS_ERR_SUCCESS; +} + +uint8_t BulkOnly::SetCurLUN(uint8_t lun) { + if (lun > bMaxLUN) + return MASS_ERR_INVALID_LUN; + + bTheLUN = lun; + return MASS_ERR_SUCCESS; +}; + +uint8_t BulkOnly::HandleSCSIError(uint8_t status) { + uint8_t ret = 0; + + switch (status) { + case 0: return MASS_ERR_SUCCESS; + //case 4: return MASS_ERR_UNIT_BUSY; + case 2: + ErrorMessage (PSTR("Phase"), status); + ResetRecovery(); + return MASS_ERR_GENERAL_SCSI_ERROR; + case 1: + ErrorMessage (PSTR("SCSI Error"), status); + RequestSenseResponce rsp; + + ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); + + if (ret) + return MASS_ERR_GENERAL_SCSI_ERROR; + + ErrorMessage (PSTR("Response Code"), rsp.bResponseCode); + ErrorMessage (PSTR("Sense Key"), rsp.bmSenseKey); + ErrorMessage (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); + ErrorMessage (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); + switch (rsp.bmSenseKey) { + case 0: + return MASS_ERR_SUCCESS; + case SCSI_S_NOT_READY: + switch (rsp.bAdditionalSenseCode) { + case SCSI_ASC_MEDIUM_NOT_PRESENT: + return MASS_ERR_NO_MEDIA; + default: + return MASS_ERR_UNIT_NOT_READY; + } + case SCSI_S_ILLEGAL_REQUEST: + switch (rsp.bAdditionalSenseCode) { + case SCSI_ASC_LBA_OUT_OF_RANGE: + return MASS_ERR_BAD_LBA; + default: + return MASS_ERR_CMD_NOT_SUPPORTED; + } + default: return MASS_ERR_GENERAL_SCSI_ERROR; + } + + default: + Reset(); + ErrorMessage (PSTR("Gen SCSI Err"), status); + return status; //MASS_ERR_GENERAL_SCSI_ERROR; + } // switch +} + +void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + PrintHex (ep_ptr->bInterval, 0x80); + Notify(PSTR("\r\n"), 0x80); +} diff --git a/masstorage.h b/masstorage.h index e856cb70..c30f4ae6 100644 --- a/masstorage.h +++ b/masstorage.h @@ -1,252 +1,276 @@ -#if !defined(__MASSTORAGE_H__) -#define __MASSTORAGE_H__ - -#include -#include -#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 -#endif - -#include "printhex.h" -#include "hexdump.h" -#include "message.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 - -// Mass Storage Subclass Constants -#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use -#define MASS_SUBCLASS_RBC 0x01 -#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI) -#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157 -#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB -#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i -#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set -#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI -#define MASS_SUBCLASS_IEEE1667 0x08 - -// Mass Storage Class Protocols -#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt) -#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt) -#define MASS_PROTO_OBSOLETE 0x02 -#define MASS_PROTO_BBB 0x50 // Bulk Only Transport -#define MASS_PROTO_UAS 0x62 - -// Request Codes -#define MASS_REQ_ADSC 0x00 -#define MASS_REQ_GET 0xFC -#define MASS_REQ_PUT 0xFD -#define MASS_REQ_GET_MAX_LUN 0xFE -#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset - -#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 SCSI_CMD_INQUIRY 0x12 -#define SCSI_CMD_REPORT_LUNS 0xA0 -#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_MODE_SENSE_6 0x1A -#define SCSI_CMD_MODE_SENSE_10 0x5A - -#define MASS_ERR_SUCCESS 0x00 -#define MASS_ERR_PHASE_ERROR 0x01 -#define MASS_ERR_DEVICE_DISCONNECTED 0x11 -#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error -#define MASS_ERR_GENERAL_USB_ERROR 0xFF - -#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved -#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 - - -struct Capacity -{ - uint8_t data[8]; - //uint32_t dwBlockAddress; - //uint32_t dwBlockLength; -}; - -struct InquiryResponse -{ - uint8_t DeviceType : 5; - uint8_t PeripheralQualifier : 3; - - unsigned Reserved : 7; - unsigned Removable : 1; - - uint8_t Version; - - unsigned ResponseDataFormat : 4; - unsigned Reserved2 : 1; - unsigned NormACA : 1; - unsigned TrmTsk : 1; - unsigned AERC : 1; - - uint8_t AdditionalLength; - uint8_t Reserved3[2]; - - unsigned SoftReset : 1; - unsigned CmdQue : 1; - unsigned Reserved4 : 1; - unsigned Linked : 1; - unsigned Sync : 1; - unsigned WideBus16Bit : 1; - unsigned WideBus32Bit : 1; - unsigned RelAddr : 1; - - uint8_t VendorID[8]; - uint8_t ProductID[16]; - uint8_t RevisionID[4]; -}; - -struct CommandBlockWrapper -{ - uint32_t dCBWSignature; - uint32_t dCBWTag; - uint32_t dCBWDataTransferLength; - uint8_t bmCBWFlags; - - struct - { - uint8_t bmCBWLUN : 4; - uint8_t bmReserved1 : 4; - }; - struct - { - uint8_t bmCBWCBLength : 4; - uint8_t bmReserved2 : 4; - }; - - uint8_t CBWCB[16]; -} ; - -struct CommandStatusWrapper -{ - uint32_t dCSWSignature; - uint32_t dCSWTag; - uint32_t dCSWDataResidue; - uint8_t bCSWStatus; -}; - -struct RequestSenseResponce -{ - uint8_t bResponseCode; - uint8_t bSegmentNumber; - - uint8_t bmSenseKey : 4; - uint8_t bmReserved : 1; - uint8_t bmILI : 1; - uint8_t bmEOM : 1; - uint8_t bmFileMark : 1; - - uint8_t Information[4]; - uint8_t bAdditionalLength; - uint8_t CmdSpecificInformation[4]; - uint8_t bAdditionalSenseCode; - uint8_t bAdditionalSenseQualifier; - uint8_t bFieldReplaceableUnitCode; - uint8_t SenseKeySpecific[3]; -}; - -//class BulkReadParser : public USBReadParser -//{ -//protected: -// bool IsValidCSW(uint8_t size, uint8_t *pcsw); -// bool IsMeaningfulCSW(uint8_t size, uint8_t *pcsw); -// -//public: -// virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; -//}; - -#define MASS_MAX_ENDPOINTS 3 - -class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter -{ -protected: - static const uint8_t epDataInIndex; // DataIn endpoint index - static const uint8_t epDataOutIndex; // DataOUT endpoint index - static const uint8_t epInterruptInIndex; // InterruptIN endpoint index - - USB *pUsb; - uint8_t bAddress; - uint8_t bConfNum; // configuration number - uint8_t bIface; // interface value - uint8_t bNumEP; // total number of EP in the configuration - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag - - EpInfo epInfo[MASS_MAX_ENDPOINTS]; - - uint32_t dCBWTag; // Tag - uint32_t dCBWDataTransferLength; // Data Transfer Length - uint8_t bMaxLUN; // Max LUN - uint8_t bLastUsbError; // Last USB error - -protected: - //union TransFlags - //{ - // uint8_t nValue; - - // struct { - // uint8_t bmCallback : 1; - // uint8_t bmCheckPhaseErr : 1; - // uint8_t bmDummy : 6; - // }; - //}; - void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); - - bool IsValidCBW(uint8_t size, uint8_t *pcbw); - bool IsMeaningfulCBW(uint8_t size, uint8_t *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 index); - -public: - BulkOnly(USB *p); - uint8_t GetLastUsbError() { return bLastUsbError; }; - - uint8_t Reset(); - uint8_t GetMaxLUN(uint8_t *max_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 Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t *buf); - uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs); - - // USBDeviceConfig implementation - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; - - // UsbConfigXtracter implementation - virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); -}; - -#endif // __MASSTORAGE_H__ \ No newline at end of file +#if !defined(__MASSTORAGE_H__) +#define __MASSTORAGE_H__ + +#include +#include "avrpins.h" +#include +#include "max3421e.h" +#include "usbhost.h" +#include "usb_ch9.h" +#include "Usb.h" + +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include + +#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 + +// Mass Storage Subclass Constants +#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use +#define MASS_SUBCLASS_RBC 0x01 +#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI) +#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157 +#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB +#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i +#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set +#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI +#define MASS_SUBCLASS_IEEE1667 0x08 + +// Mass Storage Class Protocols +#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt) +#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt) +#define MASS_PROTO_OBSOLETE 0x02 +#define MASS_PROTO_BBB 0x50 // Bulk Only Transport +#define MASS_PROTO_UAS 0x62 + +// Request Codes +#define MASS_REQ_ADSC 0x00 +#define MASS_REQ_GET 0xFC +#define MASS_REQ_PUT 0xFD +#define MASS_REQ_GET_MAX_LUN 0xFE +#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset + +#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 SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_REPORT_LUNS 0xA0 +#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_MODE_SENSE_6 0x1A +#define SCSI_CMD_MODE_SENSE_10 0x5A +#define SCSI_CMD_START_STOP_UNIT 0x1B + +#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 MASS_ERR_SUCCESS 0x00 +#define MASS_ERR_PHASE_ERROR 0x02 +#define MASS_ERR_UNIT_NOT_READY 0x03 +#define MASS_ERR_UNIT_BUSY 0x04 +#define MASS_ERR_STALL 0x05 +#define MASS_ERR_CMD_NOT_SUPPORTED 0x06 +#define MASS_ERR_INVALID_CSW 0x07 +#define MASS_ERR_NO_MEDIA 0x08 +#define MASS_ERR_BAD_LBA 0x09 +#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_GENERAL_SCSI_ERROR 0xFE +#define MASS_ERR_GENERAL_USB_ERROR 0xFF +#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes + +#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved +#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 + +struct Capacity { + uint8_t data[8]; + //uint32_t dwBlockAddress; + //uint32_t dwBlockLength; +} __attribute__((packed)); + +struct InquiryResponse { + uint8_t DeviceType : 5; + uint8_t PeripheralQualifier : 3; + + unsigned Reserved : 7; + unsigned Removable : 1; + + uint8_t Version; + + unsigned ResponseDataFormat : 4; + unsigned Reserved2 : 1; + unsigned NormACA : 1; + unsigned TrmTsk : 1; + unsigned AERC : 1; + + uint8_t AdditionalLength; + uint8_t Reserved3[2]; + + unsigned SoftReset : 1; + unsigned CmdQue : 1; + unsigned Reserved4 : 1; + unsigned Linked : 1; + unsigned Sync : 1; + unsigned WideBus16Bit : 1; + unsigned WideBus32Bit : 1; + unsigned RelAddr : 1; + + uint8_t VendorID[8]; + uint8_t ProductID[16]; + uint8_t RevisionID[4]; +} __attribute__((packed)); + +struct CommandBlockWrapperBase { + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; +} __attribute__((packed)); + +struct CommandBlockWrapper : public CommandBlockWrapperBase { + + struct { + uint8_t bmCBWLUN : 4; + uint8_t bmReserved1 : 4; + }; + + struct { + uint8_t bmCBWCBLength : 4; + uint8_t bmReserved2 : 4; + }; + + uint8_t CBWCB[16]; +} __attribute__((packed)); + +struct CommandStatusWrapper { + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} __attribute__((packed)); + +struct RequestSenseResponce { + uint8_t bResponseCode; + uint8_t bSegmentNumber; + + uint8_t bmSenseKey : 4; + uint8_t bmReserved : 1; + uint8_t bmILI : 1; + uint8_t bmEOM : 1; + uint8_t bmFileMark : 1; + + uint8_t Information[4]; + uint8_t bAdditionalLength; + uint8_t CmdSpecificInformation[4]; + uint8_t bAdditionalSenseCode; + uint8_t bAdditionalSenseQualifier; + uint8_t bFieldReplaceableUnitCode; + 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 + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + USB *pUsb; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bIface; // interface value + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + EpInfo epInfo[MASS_MAX_ENDPOINTS]; + + uint32_t dCBWTag; // Tag + uint32_t dCBWDataTransferLength; // Data Transfer Length + uint8_t bLastUsbError; // Last USB error + uint8_t bMaxLUN; // Max LUN + uint8_t bTheLUN; // Active LUN + +protected: + 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); + +public: + BulkOnly(USB *p); + + uint8_t GetLastUsbError() { + return bLastUsbError; + }; + + uint8_t GetbMaxLUN() { + return bMaxLUN; // Max LUN + } + + uint8_t GetbTheLUN() { + 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); + 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); + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // 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 uint8_t OnInit() { + return 0; + }; +}; + +#endif // __MASSTORAGE_H__ diff --git a/max3421e.h b/max3421e.h index cab2359c..9fdff593 100644 --- a/max3421e.h +++ b/max3421e.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* MAX3421E register/bit names and bitmasks */ #ifndef _max3421e_h_ @@ -37,7 +37,7 @@ e-mail : support@circuitsathome.com /* MAX3421E command byte format: rrrrr0wa where 'r' is register number */ // -// MAX3421E Registers in HOST mode. +// MAX3421E Registers in HOST mode. // #define rRCVFIFO 0x08 //1<<3 #define rSNDFIFO 0x10 //2<<3 @@ -141,7 +141,7 @@ e-mail : support@circuitsathome.com #define rHIRQ 0xc8 //25<<3 /* HIRQ Bits */ -#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume +#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume #define bmRWUIRQ 0x02 #define bmRCVDAVIRQ 0x04 #define bmSNDBAVIRQ 0x08 @@ -194,7 +194,7 @@ e-mail : support@circuitsathome.com #define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0 #define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0 #define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0 -#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 +#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 #define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0 #define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0 @@ -206,7 +206,7 @@ e-mail : support@circuitsathome.com #define bmKSTATUS 0x40 #define bmJSTATUS 0x80 #define bmSE0 0x00 //SE0 - disconnect state -#define bmSE1 0xc0 //SE1 - illegal state +#define bmSE1 0xc0 //SE1 - illegal state /* Host error result codes, the 4 LSB's in the HRSL register */ #define hrSUCCESS 0x00 diff --git a/max_LCD.cpp b/max_LCD.cpp index 307f6409..1ea842d1 100644 --- a/max_LCD.cpp +++ b/max_LCD.cpp @@ -1,250 +1,256 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "max_LCD.h" -#include "max3421e.h" - -#include -#include -#include - -#if defined(ARDUINO) && ARDUINO >=100 -#include "Arduino.h" -#else -#include -#endif - -// pin definition and set/clear - -#define RS 0x04 // RS pin -#define E 0x08 // E pin - -#define SET_RS lcdPins |= RS -#define CLR_RS lcdPins &= ~RS -#define SET_E lcdPins |= E -#define CLR_E lcdPins &= ~E - -#define SENDlcdPins() pUsb->gpioWr( lcdPins ) - -#define LCD_sendcmd(a) { CLR_RS; \ - sendbyte(a); \ - } - -#define LCD_sendchar(a) { SET_RS; \ - sendbyte(a); \ - } - -static byte lcdPins; //copy of LCD pins - -Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) -{ - lcdPins = 0; -} - - -void Max_LCD::init() -{ - _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; - - // MAX3421E::gpioWr(0x55); - - begin(16, 1); -} - -void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { - if (lines > 1) { - _displayfunction |= LCD_2LINE; - } - _numlines = lines; - _currline = 0; - - // for some 1 line displays you can select a 10 pixel high font - if ((dotsize != 0) && (lines == 1)) { - _displayfunction |= LCD_5x10DOTS; - } - - // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! - // according to datasheet, we need at least 40ms after power rises above 2.7V - // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 - delayMicroseconds(50000); - lcdPins = 0x30; - SET_E; - SENDlcdPins(); - CLR_E; - SENDlcdPins(); - delayMicroseconds(10000); // wait min 4.1ms - //second try - SET_E; - SENDlcdPins(); - CLR_E; - SENDlcdPins(); - delayMicroseconds(10000); // wait min 4.1ms - // third go! - SET_E; - SENDlcdPins(); - CLR_E; - SENDlcdPins(); - delayMicroseconds(10000); - // finally, set to 4-bit interface - lcdPins = 0x20; - //SET_RS; - SET_E; - SENDlcdPins(); - //CLR_RS; - CLR_E; - SENDlcdPins(); - delayMicroseconds(10000); - // finally, set # lines, font size, etc. - command(LCD_FUNCTIONSET | _displayfunction); - - // turn the display on with no cursor or blinking default - _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; - display(); - - // clear it off - clear(); - - // Initialize to default text direction (for romance languages) - _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; - // set the entry mode - command(LCD_ENTRYMODESET | _displaymode); -} - -/********** high level commands, for the user! */ -void Max_LCD::clear() -{ - command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero - delayMicroseconds(2000); // this command takes a long time! -} - -void Max_LCD::home() -{ - command(LCD_RETURNHOME); // set cursor position to zero - delayMicroseconds(2000); // this command takes a long time! -} - -void Max_LCD::setCursor(uint8_t col, uint8_t row) -{ - int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; - if ( row > _numlines ) { - row = _numlines-1; // we count rows starting w/0 - } - - command(LCD_SETDDRAMADDR | (col + row_offsets[row])); -} - -// Turn the display on/off (quickly) -void Max_LCD::noDisplay() { - _displaycontrol &= ~LCD_DISPLAYON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} -void Max_LCD::display() { - _displaycontrol |= LCD_DISPLAYON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} - -// Turns the underline cursor on/off -void Max_LCD::noCursor() { - _displaycontrol &= ~LCD_CURSORON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} -void Max_LCD::cursor() { - _displaycontrol |= LCD_CURSORON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} - - -// Turn on and off the blinking cursor -void Max_LCD::noBlink() { - _displaycontrol &= ~LCD_BLINKON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} -void Max_LCD::blink() { - _displaycontrol |= LCD_BLINKON; - command(LCD_DISPLAYCONTROL | _displaycontrol); -} - -// These commands scroll the display without changing the RAM -void Max_LCD::scrollDisplayLeft(void) { - command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); -} -void Max_LCD::scrollDisplayRight(void) { - command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); -} - -// This is for text that flows Left to Right -void Max_LCD::leftToRight(void) { - _displaymode |= LCD_ENTRYLEFT; - command(LCD_ENTRYMODESET | _displaymode); -} - -// This is for text that flows Right to Left -void Max_LCD::rightToLeft(void) { - _displaymode &= ~LCD_ENTRYLEFT; - command(LCD_ENTRYMODESET | _displaymode); -} - -// This will 'right justify' text from the cursor -void Max_LCD::autoscroll(void) { - _displaymode |= LCD_ENTRYSHIFTINCREMENT; - command(LCD_ENTRYMODESET | _displaymode); -} - -// This will 'left justify' text from the cursor -void Max_LCD::noAutoscroll(void) { - _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; - command(LCD_ENTRYMODESET | _displaymode); -} - -// Allows us to fill the first 8 CGRAM locations -// with custom characters -void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) { - location &= 0x7; // we only have 8 locations 0-7 - command(LCD_SETCGRAMADDR | (location << 3)); - for (int i=0; i<8; i++) { - write(charmap[i]); - } -} - -/*********** mid level commands, for sending data/cmds */ - -inline void Max_LCD::command(uint8_t value) { - LCD_sendcmd(value); - delayMicroseconds(100); -} - -inline void Max_LCD::write(uint8_t value) { - LCD_sendchar(value); -} - -void Max_LCD::sendbyte( uint8_t val ) -{ - lcdPins &= 0x0f; //prepare place for the upper nibble - lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable - SET_E; //send - SENDlcdPins(); - delayMicroseconds(2); - CLR_E; - delayMicroseconds(2); - SENDlcdPins(); - lcdPins &= 0x0f; //prepare place for the lower nibble - lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable - SET_E; //send - SENDlcdPins(); - CLR_E; - SENDlcdPins(); - delayMicroseconds(100); -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "max_LCD.h" +#include "max3421e.h" + +#include +#include +#include + +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif + +// pin definition and set/clear + +#define RS 0x04 // RS pin +#define E 0x08 // E pin + +#define SET_RS lcdPins |= RS +#define CLR_RS lcdPins &= ~RS +#define SET_E lcdPins |= E +#define CLR_E lcdPins &= ~E + +#define SENDlcdPins() pUsb->gpioWr( lcdPins ) + +#define LCD_sendcmd(a) { CLR_RS; \ + sendbyte(a); \ + } + +#define LCD_sendchar(a) { SET_RS; \ + sendbyte(a); \ + } + +static byte lcdPins; //copy of LCD pins + +Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) { + lcdPins = 0; +} + +void Max_LCD::init() { + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + + // MAX3421E::gpioWr(0x55); + + begin(16, 1); +} + +void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + if (lines > 1) { + _displayfunction |= LCD_2LINE; + } + _numlines = lines; + _currline = 0; + + // for some 1 line displays you can select a 10 pixel high font + if ((dotsize != 0) && (lines == 1)) { + _displayfunction |= LCD_5x10DOTS; + } + + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40ms after power rises above 2.7V + // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 + delayMicroseconds(50000); + lcdPins = 0x30; + SET_E; + SENDlcdPins(); + CLR_E; + SENDlcdPins(); + delayMicroseconds(10000); // wait min 4.1ms + //second try + SET_E; + SENDlcdPins(); + CLR_E; + SENDlcdPins(); + delayMicroseconds(10000); // wait min 4.1ms + // third go! + SET_E; + SENDlcdPins(); + CLR_E; + SENDlcdPins(); + delayMicroseconds(10000); + // finally, set to 4-bit interface + lcdPins = 0x20; + //SET_RS; + SET_E; + SENDlcdPins(); + //CLR_RS; + CLR_E; + SENDlcdPins(); + delayMicroseconds(10000); + // finally, set # lines, font size, etc. + command(LCD_FUNCTIONSET | _displayfunction); + + // turn the display on with no cursor or blinking default + _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + display(); + + // clear it off + clear(); + + // Initialize to default text direction (for romance languages) + _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + // set the entry mode + command(LCD_ENTRYMODESET | _displaymode); +} + +/********** high level commands, for the user! */ +void Max_LCD::clear() { + command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void Max_LCD::home() { + command(LCD_RETURNHOME); // set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void Max_LCD::setCursor(uint8_t col, uint8_t row) { + int row_offsets[] = {0x00, 0x40, 0x14, 0x54}; + if (row > _numlines) { + row = _numlines - 1; // we count rows starting w/0 + } + + command(LCD_SETDDRAMADDR | (col + row_offsets[row])); +} + +// Turn the display on/off (quickly) + +void Max_LCD::noDisplay() { + _displaycontrol &= ~LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void Max_LCD::display() { + _displaycontrol |= LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off + +void Max_LCD::noCursor() { + _displaycontrol &= ~LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void Max_LCD::cursor() { + _displaycontrol |= LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + + +// Turn on and off the blinking cursor + +void Max_LCD::noBlink() { + _displaycontrol &= ~LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void Max_LCD::blink() { + _displaycontrol |= LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM + +void Max_LCD::scrollDisplayLeft(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} + +void Max_LCD::scrollDisplayRight(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right + +void Max_LCD::leftToRight(void) { + _displaymode |= LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left + +void Max_LCD::rightToLeft(void) { + _displaymode &= ~LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor + +void Max_LCD::autoscroll(void) { + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor + +void Max_LCD::noAutoscroll(void) { + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// Allows us to fill the first 8 CGRAM locations +// with custom characters + +void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) { + location &= 0x7; // we only have 8 locations 0-7 + command(LCD_SETCGRAMADDR | (location << 3)); + for (int i = 0; i < 8; i++) { + write(charmap[i]); + } +} + +/*********** mid level commands, for sending data/cmds */ + +inline void Max_LCD::command(uint8_t value) { + LCD_sendcmd(value); + delayMicroseconds(100); +} + +inline void Max_LCD::write(uint8_t value) { + LCD_sendchar(value); +} + +void Max_LCD::sendbyte(uint8_t val) { + lcdPins &= 0x0f; //prepare place for the upper nibble + lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable + SET_E; //send + SENDlcdPins(); + delayMicroseconds(2); + CLR_E; + delayMicroseconds(2); + SENDlcdPins(); + lcdPins &= 0x0f; //prepare place for the lower nibble + lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable + SET_E; //send + SENDlcdPins(); + CLR_E; + SENDlcdPins(); + delayMicroseconds(100); +} diff --git a/max_LCD.h b/max_LCD.h index c42d78e3..1cce6fc5 100644 --- a/max_LCD.h +++ b/max_LCD.h @@ -1,102 +1,102 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -//HD44780 compatible LCD display via MAX3421E GPOUT support header -//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3] -// - -#ifndef _Max_LCD_h_ -#define _Max_LCD_h_ - -#include -#include "Print.h" -#include "Usb.h" - -// commands -#define LCD_CLEARDISPLAY 0x01 -#define LCD_RETURNHOME 0x02 -#define LCD_ENTRYMODESET 0x04 -#define LCD_DISPLAYCONTROL 0x08 -#define LCD_CURSORSHIFT 0x10 -#define LCD_FUNCTIONSET 0x20 -#define LCD_SETCGRAMADDR 0x40 -#define LCD_SETDDRAMADDR 0x80 - -// flags for display entry mode -#define LCD_ENTRYRIGHT 0x00 -#define LCD_ENTRYLEFT 0x02 -#define LCD_ENTRYSHIFTINCREMENT 0x01 -#define LCD_ENTRYSHIFTDECREMENT 0x00 - -// flags for display on/off control -#define LCD_DISPLAYON 0x04 -#define LCD_DISPLAYOFF 0x00 -#define LCD_CURSORON 0x02 -#define LCD_CURSOROFF 0x00 -#define LCD_BLINKON 0x01 -#define LCD_BLINKOFF 0x00 - -// flags for display/cursor shift -#define LCD_DISPLAYMOVE 0x08 -#define LCD_CURSORMOVE 0x00 -#define LCD_MOVERIGHT 0x04 -#define LCD_MOVELEFT 0x00 - -// flags for function set -#define LCD_8BITMODE 0x10 -#define LCD_4BITMODE 0x00 -#define LCD_2LINE 0x08 -#define LCD_1LINE 0x00 -#define LCD_5x10DOTS 0x04 -#define LCD_5x8DOTS 0x00 - -class Max_LCD //: public Print -{ - USB *pUsb; - -public: - Max_LCD(USB *pusb); - void init(); - void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); - void clear(); - void home(); - void noDisplay(); - void display(); - void noBlink(); - void blink(); - void noCursor(); - void cursor(); - void scrollDisplayLeft(); - void scrollDisplayRight(); - void leftToRight(); - void rightToLeft(); - void autoscroll(); - void noAutoscroll(); - void createChar(uint8_t, uint8_t[]); - void setCursor(uint8_t, uint8_t); - virtual void write(uint8_t); - void command(uint8_t); - -private: - void sendbyte( uint8_t val ); - uint8_t _displayfunction; //tokill - uint8_t _displaycontrol; - uint8_t _displaymode; - uint8_t _initialized; - uint8_t _numlines,_currline; -}; - +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +//HD44780 compatible LCD display via MAX3421E GPOUT support header +//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3] +// + +#ifndef _Max_LCD_h_ +#define _Max_LCD_h_ + +#include +#include "Print.h" +#include "Usb.h" + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +class Max_LCD //: public Print +{ + USB *pUsb; + +public: + Max_LCD(USB *pusb); + void init(); + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); + void clear(); + void home(); + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void leftToRight(); + void rightToLeft(); + void autoscroll(); + void noAutoscroll(); + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); + virtual void write(uint8_t); + void command(uint8_t); + +private: + void sendbyte(uint8_t val); + uint8_t _displayfunction; //tokill + uint8_t _displaycontrol; + uint8_t _displaymode; + uint8_t _initialized; + uint8_t _numlines, _currline; +}; + #endif \ No newline at end of file diff --git a/message.cpp b/message.cpp index edb1b5b4..47268b48 100644 --- a/message.cpp +++ b/message.cpp @@ -1,31 +1,47 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "message.h" - -void Notify(char const * msg) -//void Notify(const char* msg) -{ - if(!msg) return; - char c; - - while((c = pgm_read_byte(msg++))) -#if defined(ARDUINO) && ARDUINO >=100 - Serial.print(c); -#else - Serial.print(c,BYTE); -#endif -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "message.h" +// 0x80 is the default (i.e. trace) to turn off set this global to something lower. +// this allows for 126 other debugging levels. +// TO-DO: Allow assignment to a different serial port +int UsbDEBUGlvl = 0x80; + +void Notifyc(char c, int lvl) { + if (UsbDEBUGlvl < lvl) return; +#if defined(ARDUINO) && ARDUINO >=100 + Serial.print(c); +#else + Serial.print(c, BYTE); +#endif + Serial.flush(); +} + +void Notify(char const * msg, int lvl) { + if (UsbDEBUGlvl < lvl) return; + if (!msg) return; + char c; + + while ((c = pgm_read_byte(msg++))) Notifyc(c, lvl); +} + +void NotifyStr(char const * msg, int lvl) { + if (UsbDEBUGlvl < lvl) return; + if (!msg) return; + char c; + + while (c = *msg++) Notifyc(c, lvl); +} diff --git a/message.h b/message.h index e276a275..fa339487 100644 --- a/message.h +++ b/message.h @@ -1,37 +1,39 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__MESSAGE_H__) -#define __MESSAGE_H__ - -#include -#include -#include "printhex.h" - -void Notify(char const * msg); -//void Notify(const char* msg); - -template -void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) -{ - Notify(msg); - Notify(PSTR(": ")); - PrintHex(rcode); - Notify(PSTR("\r\n")); -} - - -#endif // __MESSAGE_H__ +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__MESSAGE_H__) +#define __MESSAGE_H__ + +#include +#include + +void Notify(char const * msg, int lvl); +void NotifyStr(char const * msg, int lvl); + +#include "printhex.h" + +//void Notify(const char* msg); + +template +void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) { + Notify(msg, 0x80); + Notify(PSTR(": "), 0x80); + PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); +} + + +#endif // __MESSAGE_H__ diff --git a/parsetools.cpp b/parsetools.cpp index bbcca772..c302dd2a 100644 --- a/parsetools.cpp +++ b/parsetools.cpp @@ -1,72 +1,67 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#include "parsetools.h" - -bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) -{ - if (!pBuf) - { - Notify(PSTR("Buffer pointer is NULL!\r\n")); - return false; - } - for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++) - pBuf[valueSize-countDown] = (**pp); - - if (countDown) - return false; - - countDown = valueSize; - return true; -} - -bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) -{ - switch (nStage) - { - case 0: - pBuf->valueSize = lenSize; - theParser.Initialize(pBuf); - nStage = 1; - - case 1: - if (!theParser.Parse(pp, pcntdn)) - return false; - - arLen = 0; - arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue)); - arLenCntdn = arLen; - nStage = 2; - - case 2: - pBuf->valueSize = valSize; - theParser.Initialize(pBuf); - nStage = 3; - - case 3: - for (; arLenCntdn; arLenCntdn--) - { - if (!theParser.Parse(pp, pcntdn)) - return false; - - if (pf) - pf(pBuf, (arLen - arLenCntdn), me); - } - - nStage = 0; - } - return true; -} +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "parsetools.h" + +bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) { + if (!pBuf) { + Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80); + return false; + } + for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++) + pBuf[valueSize - countDown] = (**pp); + + if (countDown) + return false; + + countDown = valueSize; + return true; +} + +bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) { + switch (nStage) { + case 0: + pBuf->valueSize = lenSize; + theParser.Initialize(pBuf); + nStage = 1; + + case 1: + if (!theParser.Parse(pp, pcntdn)) + return false; + + arLen = 0; + arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue)); + arLenCntdn = arLen; + nStage = 2; + + case 2: + pBuf->valueSize = valSize; + theParser.Initialize(pBuf); + nStage = 3; + + case 3: + for (; arLenCntdn; arLenCntdn--) { + if (!theParser.Parse(pp, pcntdn)) + return false; + + if (pf) + pf(pBuf, (arLen - arLenCntdn), me); + } + + nStage = 0; + } + return true; +} diff --git a/parsetools.h b/parsetools.h index d19b8dac..59402df2 100644 --- a/parsetools.h +++ b/parsetools.h @@ -1,151 +1,149 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__PARSETOOLS_H__) -#define __PARSETOOLS_H__ - -#include -#include -#include "printhex.h" -#include "hexdump.h" -#include "message.h" - -#if defined(ARDUINO) && ARDUINO >=100 -#include "Arduino.h" -#else -#include -#endif - -struct MultiValueBuffer -{ - uint8_t valueSize; - void *pValue; -}; - -class MultiByteValueParser -{ - uint8_t * pBuf; - uint8_t countDown; - uint8_t valueSize; - -public: - MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {}; - - const uint8_t* GetBuffer() { return pBuf; }; - - void Initialize(MultiValueBuffer * const pbuf) - { - pBuf = (uint8_t*)pbuf->pValue; - countDown = valueSize = pbuf->valueSize; - }; - - bool Parse(uint8_t **pp, uint16_t *pcntdn); -}; - -class ByteSkipper -{ - uint8_t *pBuf; - uint8_t nStage; - uint16_t countDown; - -public: - ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {}; - - void Initialize(MultiValueBuffer *pbuf) - { - pBuf = (uint8_t*)pbuf->pValue; - countDown = 0; - }; - - bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) - { - switch (nStage) - { - case 0: - countDown = bytes_to_skip; - nStage ++; - case 1: - for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--); - - if (!countDown) - nStage = 0; - }; - return (!countDown); - }; -}; - -// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser -typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me); - -class PTPListParser -{ -public: - enum ParseMode { modeArray, modeRange/*, modeEnum*/ }; - -private: - uint8_t nStage; - uint8_t enStage; - - uint32_t arLen; - uint32_t arLenCntdn; - - uint8_t lenSize; // size of the array length field in bytes - uint8_t valSize; // size of the array element in bytes - - MultiValueBuffer *pBuf; - - // The only parser for both size and array element parsing - MultiByteValueParser theParser; - - uint8_t /*ParseMode*/ prsMode; - -public: - PTPListParser() : - pBuf(NULL), - nStage(0), - enStage(0), - arLenCntdn(0), - arLen(0), - lenSize(0), - valSize(0), - prsMode(modeArray) - {}; - - void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) - { - pBuf = p; - lenSize = len_size; - valSize = val_size; - prsMode = mode; - - if (prsMode == modeRange) - { - arLenCntdn = arLen = 3; - nStage = 2; - } - else - { - arLenCntdn = arLen = 0; - nStage = 0; - } - enStage = 0; - theParser.Initialize(p); - }; - - bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL); -}; - -#endif // __PARSETOOLS_H__ \ No newline at end of file +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__PARSETOOLS_H__) +#define __PARSETOOLS_H__ + +#include +#include +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif + +struct MultiValueBuffer { + uint8_t valueSize; + void *pValue; +} __attribute__((packed)); + +class MultiByteValueParser { + uint8_t * pBuf; + uint8_t countDown; + uint8_t valueSize; + +public: + + MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) { + }; + + const uint8_t* GetBuffer() { + return pBuf; + }; + + void Initialize(MultiValueBuffer * const pbuf) { + pBuf = (uint8_t*) pbuf->pValue; + countDown = valueSize = pbuf->valueSize; + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn); +}; + +class ByteSkipper { + uint8_t *pBuf; + uint8_t nStage; + uint16_t countDown; + +public: + + ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) { + }; + + void Initialize(MultiValueBuffer *pbuf) { + pBuf = (uint8_t*) pbuf->pValue; + countDown = 0; + }; + + bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) { + switch(nStage) { + case 0: + countDown = bytes_to_skip; + nStage++; + case 1: + for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--); + + if(!countDown) + nStage = 0; + }; + return(!countDown); + }; +}; + +// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser +typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me); + +class PTPListParser { +public: + + enum ParseMode { + modeArray, modeRange/*, modeEnum*/ + }; + +private: + uint8_t nStage; + uint8_t enStage; + + uint32_t arLen; + uint32_t arLenCntdn; + + uint8_t lenSize; // size of the array length field in bytes + uint8_t valSize; // size of the array element in bytes + + MultiValueBuffer *pBuf; + + // The only parser for both size and array element parsing + MultiByteValueParser theParser; + + uint8_t /*ParseMode*/ prsMode; + +public: + + PTPListParser() : + nStage(0), + enStage(0), + arLen(0), + arLenCntdn(0), + lenSize(0), + valSize(0), + pBuf(NULL), + prsMode(modeArray) { + }; + + void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) { + pBuf = p; + lenSize = len_size; + valSize = val_size; + prsMode = mode; + + if(prsMode == modeRange) { + arLenCntdn = arLen = 3; + nStage = 2; + } else { + arLenCntdn = arLen = 0; + nStage = 0; + } + enStage = 0; + theParser.Initialize(p); + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL); +}; + +#endif // __PARSETOOLS_H__ diff --git a/printhex.h b/printhex.h index 7a3b3d9b..4a303884 100644 --- a/printhex.h +++ b/printhex.h @@ -1,66 +1,71 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. 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 -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ -#if !defined(__PRINTHEX_H__) -#define __PRINTHEX_H__ - -#if defined(ARDUINO) && ARDUINO >=100 -#include "Arduino.h" -#else -#include -#endif - -template -void PrintHex(T val) -{ - T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2)); - - while (mask > 1) - { - if (val < mask) - Serial.print("0"); - - mask >>= 4; - } - Serial.print((T)val, HEX); -} - -template -void PrintHex2(Print *prn, T val) -{ - T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2)); - - while (mask > 1) - { - if (val < mask) - prn->print("0"); - - mask >>= 4; - } - prn->print((T)val, HEX); -} - -template -void PrintBin(T val) -{ - for (T mask = (((T)1) << (sizeof(T) << 3)-1); mask; mask>>=1) - if (val & mask) - Serial.print("1"); - else - Serial.print("0"); -} - -#endif // __PRINTHEX_H__ \ No newline at end of file +/* Copyright (C) 2011 Circuits At Home, LTD. 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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(__PRINTHEX_H__) +#define __PRINTHEX_H__ + +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif +void Notifyc(char c, int lvl); + +template +void PrintHex(T val, int lvl) { + int num_nibbles = sizeof(T) * 2; + + do { + char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if(v > 57) v += 7; + Notifyc(v, lvl); + } while(--num_nibbles); +} + +template +void PrintBin(T val, int lvl) { + for(T mask = (((T) 1) << ((sizeof(T) << 3) - 1)); mask; mask >>= 1) + if(val & mask) + Notifyc('1', lvl); + else + Notifyc('0', lvl); +} + +template +void SerialPrintHex(T val) { + int num_nibbles = sizeof(T) * 2; + + do { + char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if(v > 57) v += 7; + Serial.print(v); + } while(--num_nibbles); +} + +template +void PrintHex2(Print *prn, T val) { + T mask = (((T) 1) << (((sizeof(T) << 1) - 1) << 2)); + + while(mask > 1) { + if(val < mask) + prn->print("0"); + + mask >>= 4; + } + prn->print((T) val, HEX); +} + +#endif // __PRINTHEX_H__ diff --git a/usb_ch9.h b/usb_ch9.h index 12501aff..dd854f5c 100644 --- a/usb_ch9.h +++ b/usb_ch9.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* USB chapter 9 structures */ #ifndef _ch9_h_ #define _ch9_h_ @@ -94,77 +94,71 @@ e-mail : support@circuitsathome.com /* Device descriptor structure */ typedef struct { - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). - uint16_t bcdUSB; // USB Spec Release Number (BCD). - uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). - uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. - uint16_t idVendor; // Vendor ID (assigned by the USB-IF). - uint16_t idProduct; // Product ID (assigned by the manufacturer). - uint16_t bcdDevice; // Device release number (BCD). - uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. - uint8_t iProduct; // Index of String Descriptor describing the product. - uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. - uint8_t bNumConfigurations; // Number of possible configurations. -} USB_DEVICE_DESCRIPTOR; + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} __attribute__((packed)) USB_DEVICE_DESCRIPTOR; /* Configuration descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). - uint16_t wTotalLength; // Total length of all descriptors for this configuration. - uint8_t bNumInterfaces; // Number of interfaces in this configuration. - uint8_t bConfigurationValue; // Value of this configuration (1 based). - uint8_t iConfiguration; // Index of String Descriptor describing the configuration. - uint8_t bmAttributes; // Configuration characteristics. - uint8_t bMaxPower; // Maximum power consumed by this configuration. -} USB_CONFIGURATION_DESCRIPTOR; +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR; /* Interface descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). - uint8_t bInterfaceNumber; // Number of this interface (0 based). - uint8_t bAlternateSetting; // Value of this alternate interface setting. - uint8_t bNumEndpoints; // Number of endpoints in this interface. - uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). - uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t iInterface; // Index of String Descriptor describing the interface. -} USB_INTERFACE_DESCRIPTOR; +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR; /* Endpoint descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). - uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). - uint8_t bmAttributes; // Endpoint transfer type. - uint16_t wMaxPacketSize; // Maximum packet size. - uint8_t bInterval; // Polling interval in frames. -} USB_ENDPOINT_DESCRIPTOR; - +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR; /* HID descriptor */ -typedef struct -{ - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdHID; // HID class specification release - uint8_t bCountryCode; - uint8_t bNumDescriptors; // Number of additional class specific descriptors - uint8_t bDescrType; // Type of class descriptor - uint16_t wDescriptorLength; // Total size of the Report descriptor -} USB_HID_DESCRIPTOR; +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; // HID class specification release + uint8_t bCountryCode; + uint8_t bNumDescriptors; // Number of additional class specific descriptors + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) USB_HID_DESCRIPTOR; -typedef struct -{ - uint8_t bDescrType; // Type of class descriptor - uint16_t wDescriptorLength; // Total size of the Report descriptor -} HID_CLASS_DESCRIPTOR_LEN_AND_TYPE; +typedef struct { + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE; #endif // _ch9_h_ diff --git a/usbhost.h b/usbhost.h index 6efe9793..2dd60a06 100644 --- a/usbhost.h +++ b/usbhost.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ /* MAX3421E-based USB Host Library header file */ #ifndef _USBHOST_H_ #define _USBHOST_H_ @@ -22,25 +22,24 @@ e-mail : support@circuitsathome.com #include "max3421e.h" #include "usb_ch9.h" - /* SPI initialization */ -template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi -{ - public: - static void init() { - uint8_t tmp; - CLK::SetDirWrite(); - MOSI::SetDirWrite(); - MISO::SetDirRead(); - SPI_SS::SetDirWrite(); - /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ - SPCR = 0x50; - SPSR = 0x01; - /**/ - tmp = SPSR; - tmp = SPDR; - } -}; +template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi { +public: + + static void init() { + //uint8_t tmp; + CLK::SetDirWrite(); + MOSI::SetDirWrite(); + MISO::SetDirRead(); + SPI_SS::SetDirWrite(); + /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ + SPCR = 0x50; + SPSR = 0x01; + /**/ + //tmp = SPSR; + //tmp = SPDR; + } +}; /* SPI pin definitions. see avrpins.h */ #if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) @@ -53,143 +52,138 @@ typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; #endif -template< typename SS, typename INTR > class MAX3421e /* : public spi */ -{ - static uint8_t vbusState; +template< typename SS, typename INTR > class MAX3421e /* : public spi */ { + static uint8_t vbusState; - public: - MAX3421e(); - void regWr( uint8_t reg, uint8_t data ); - uint8_t* bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); - void gpioWr( uint8_t data ); - uint8_t regRd( uint8_t reg ); - uint8_t* bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); - uint8_t gpioRd(); - uint16_t reset(); - int8_t Init(); - uint8_t getVbusState( void ) { return vbusState; }; - void busprobe(); - uint8_t GpxHandler(); - uint8_t IntHandler(); - uint8_t Task(); +public: + MAX3421e(); + void regWr(uint8_t reg, uint8_t data); + uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p); + void gpioWr(uint8_t data); + uint8_t regRd(uint8_t reg); + uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p); + uint8_t gpioRd(); + uint16_t reset(); + int8_t Init(); + + uint8_t getVbusState(void) { + return vbusState; + }; + void busprobe(); + uint8_t GpxHandler(); + uint8_t IntHandler(); + uint8_t Task(); }; template< typename SS, typename INTR > -uint8_t MAX3421e< SS, INTR >::vbusState = 0; + uint8_t MAX3421e< SS, INTR >::vbusState = 0; /* constructor */ template< typename SS, typename INTR > -MAX3421e< SS, INTR >::MAX3421e() -{ - /* pin and peripheral setup */ - SS::SetDirWrite(); - SS::Set(); - spi::init(); - INTR::SetDirRead(); -#ifdef BOARD_MEGA_ADK - /* For Mega ADK, which has Max3421e on-board, set MAX_RESET to Output mode, and pull Reset to HIGH */ - DDRJ |= _BV(PJ2); - PORTJ &= ~_BV(PJ2); - PORTJ |= _BV(PJ2); -#endif +MAX3421e< SS, INTR >::MAX3421e() { + /* pin and peripheral setup */ + SS::SetDirWrite(); + SS::Set(); + spi::init(); + INTR::SetDirRead(); - /* MAX3421E - full-duplex SPI, level interrupt */ - regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL )); + /* MAX3421E - full-duplex SPI, level interrupt */ + regWr(rPINCTL, (bmFDUPSPI + bmINTLEVEL)); }; + /* write single byte into MAX3421 register */ template< typename SS, typename INTR > -void MAX3421e< SS, INTR >::regWr( uint8_t reg, uint8_t data ) -{ - SS::Clear(); - SPDR = ( reg | 0x02 ); - while(!( SPSR & ( 1 << SPIF ))); - SPDR = data; - while(!( SPSR & ( 1 << SPIF ))); - SS::Set(); - return; +void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) { + SS::Clear(); + SPDR = (reg | 0x02); + while(!(SPSR & (1 << SPIF))); + SPDR = data; + while(!(SPSR & (1 << SPIF))); + SS::Set(); + return; }; /* multiple-byte write */ + /* returns a pointer to memory position after last written */ template< typename SS, typename INTR > -uint8_t* MAX3421e< SS, INTR >::bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) -{ - SS::Clear(); - SPDR = ( reg | 0x02 ); //set WR bit and send register number - while( nbytes-- ) { - while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent - SPDR = ( *data_p ); // send next data byte - data_p++; // advance data pointer - } - while(!( SPSR & ( 1 << SPIF ))); - SS::Set(); - return( data_p ); +uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + SS::Clear(); + SPDR = (reg | 0x02); //set WR bit and send register number + while(nbytes--) { + while(!(SPSR & (1 << SPIF))); //check if previous byte was sent + SPDR = (*data_p); // send next data byte + data_p++; // advance data pointer + } + while(!(SPSR & (1 << SPIF))); + SS::Set(); + return( data_p); } /* GPIO write */ /*GPIO byte is split between 2 registers, so two writes are needed to write one byte */ + /* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */ template< typename SS, typename INTR > -void MAX3421e< SS, INTR >::gpioWr( uint8_t data ) -{ - regWr( rIOPINS1, data ); - data >>= 4; - regWr( rIOPINS2, data ); - return; +void MAX3421e< SS, INTR >::gpioWr(uint8_t data) { + regWr(rIOPINS1, data); + data >>= 4; + regWr(rIOPINS2, data); + return; } + /* single host register read */ template< typename SS, typename INTR > -uint8_t MAX3421e< SS, INTR >::regRd( uint8_t reg ) -{ - SS::Clear(); - SPDR = reg; - while(!( SPSR & ( 1 << SPIF ))); - SPDR = 0; //send empty byte - while(!( SPSR & ( 1 << SPIF ))); - SS::Set(); - return( SPDR ); +uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) { + SS::Clear(); + SPDR = reg; + while(!(SPSR & (1 << SPIF))); + SPDR = 0; //send empty byte + while(!(SPSR & (1 << SPIF))); + SS::Set(); + return( SPDR); } /* multiple-byte register read */ + /* returns a pointer to a memory position after last read */ template< typename SS, typename INTR > -uint8_t* MAX3421e< SS, INTR >::bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) -{ - SS::Clear(); - SPDR = reg; - while(!( SPSR & ( 1 << SPIF ))); //wait - while( nbytes ) { - SPDR = 0; //send empty byte - nbytes--; - while(!( SPSR & ( 1 << SPIF ))); - *data_p = SPDR; - data_p++; - } - SS::Set(); - return( data_p ); +uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + SS::Clear(); + SPDR = reg; + while(!(SPSR & (1 << SPIF))); //wait + while(nbytes) { + SPDR = 0; //send empty byte + nbytes--; + while(!(SPSR & (1 << SPIF))); + *data_p = SPDR; + data_p++; + } + SS::Set(); + return( data_p); } /* GPIO read. See gpioWr for explanation */ + /* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ template< typename SS, typename INTR > -uint8_t MAX3421e< SS, INTR >::gpioRd() -{ - uint8_t gpin = 0; - gpin = regRd( rIOPINS2 ); //pins 4-7 - gpin &= 0xf0; //clean lower nibble - gpin |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. - return( gpin ); +uint8_t MAX3421e< SS, INTR >::gpioRd() { + uint8_t gpin = 0; + gpin = regRd(rIOPINS2); //pins 4-7 + gpin &= 0xf0; //clean lower nibble + gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation. + return( gpin); } + /* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset or zero if PLL haven't stabilized in 65535 cycles */ template< typename SS, typename INTR > -uint16_t MAX3421e< SS, INTR >::reset() -{ - uint16_t i = 0; - regWr( rUSBCTL, bmCHIPRES ); - regWr( rUSBCTL, 0x00 ); - while( ++i ) { - if(( regRd( rUSBIRQ ) & bmOSCOKIRQ )) { - break; - } - } - return( i ); +uint16_t MAX3421e< SS, INTR >::reset() { + uint16_t i = 0; + regWr(rUSBCTL, bmCHIPRES); + regWr(rUSBCTL, 0x00); + while(++i) { + if((regRd(rUSBIRQ) & bmOSCOKIRQ)) { + break; + } + } + return( i); } ///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ //template< typename SS, typename INTR > @@ -199,105 +193,101 @@ uint16_t MAX3421e< SS, INTR >::reset() // return ( -1 ); // } // regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host -// +// // return( 0 ); //} + /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ template< typename SS, typename INTR > -int8_t MAX3421e< SS, INTR >::Init() -{ - if( reset() == 0 ) - { //OSCOKIRQ hasn't asserted in time - return ( -1 ); - } - regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host - - regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection +int8_t MAX3421e< SS, INTR >::Init() { + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time + return( -1); + } + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host - /* check if device is connected */ - regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus - while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish + regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection - busprobe(); //check if anything is connected + /* check if device is connected */ + regWr(rHCTL, bmSAMPLEBUS); // sample USB bus + while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish - regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt - regWr( rCPUCTL, 0x01 ); //enable interrupt pin - return( 0 ); + busprobe(); //check if anything is connected + + regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt + regWr(rCPUCTL, 0x01); //enable interrupt pin + return( 0); } -/* probe bus to determine device presense and speed and switch host to this speed */ +/* probe bus to determine device presence and speed and switch host to this speed */ template< typename SS, typename INTR > -void MAX3421e< SS, INTR >::busprobe() -{ - uint8_t bus_sample; - bus_sample = regRd( rHRSL ); //Get J,K status - bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte - switch( bus_sample ) { //start full-speed or low-speed host - case( bmJSTATUS ): - if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { - regWr( rMODE, MODE_FS_HOST ); //start full-speed host - vbusState = FSHOST; - } - else { - regWr( rMODE, MODE_LS_HOST); //start low-speed host - vbusState = LSHOST; - } - break; - case( bmKSTATUS ): - if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { - regWr( rMODE, MODE_LS_HOST ); //start low-speed host - vbusState = LSHOST; - } - else { - regWr( rMODE, MODE_FS_HOST ); //start full-speed host - vbusState = FSHOST; - } - break; - case( bmSE1 ): //illegal state - vbusState = SE1; - break; - case( bmSE0 ): //disconnected state - regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ); - vbusState = SE0; - break; +void MAX3421e< SS, INTR >::busprobe() { + uint8_t bus_sample; + bus_sample = regRd(rHRSL); //Get J,K status + bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte + switch(bus_sample) { //start full-speed or low-speed host + case( bmJSTATUS): + if((regRd(rMODE) & bmLOWSPEED) == 0) { + regWr(rMODE, MODE_FS_HOST); //start full-speed host + vbusState = FSHOST; + } else { + regWr(rMODE, MODE_LS_HOST); //start low-speed host + vbusState = LSHOST; + } + break; + case( bmKSTATUS): + if((regRd(rMODE) & bmLOWSPEED) == 0) { + regWr(rMODE, MODE_LS_HOST); //start low-speed host + vbusState = LSHOST; + } else { + regWr(rMODE, MODE_FS_HOST); //start full-speed host + vbusState = FSHOST; + } + break; + case( bmSE1): //illegal state + vbusState = SE1; + break; + case( bmSE0): //disconnected state + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ); + vbusState = SE0; + break; }//end switch( bus_sample ) } + /* MAX3421 state change task and interrupt handler */ template< typename SS, typename INTR > -uint8_t MAX3421e< SS, INTR >::Task( void ) -{ - uint8_t rcode = 0; - uint8_t pinvalue; - //Serial.print("Vbus state: "); - //Serial.println( vbusState, HEX ); - pinvalue = INTR::IsSet(); //Read(); - //pinvalue = digitalRead( MAX_INT ); - if( pinvalue == 0 ) { - rcode = IntHandler(); - } -// pinvalue = digitalRead( MAX_GPX ); -// if( pinvalue == LOW ) { -// GpxHandler(); -// } -// usbSM(); //USB state machine - return( rcode ); -} +uint8_t MAX3421e< SS, INTR >::Task(void) { + uint8_t rcode = 0; + uint8_t pinvalue; + //Serial.print("Vbus state: "); + //Serial.println( vbusState, HEX ); + pinvalue = INTR::IsSet(); //Read(); + //pinvalue = digitalRead( MAX_INT ); + if(pinvalue == 0) { + rcode = IntHandler(); + } + // pinvalue = digitalRead( MAX_GPX ); + // if( pinvalue == LOW ) { + // GpxHandler(); + // } + // usbSM(); //USB state machine + return( rcode); +} + template< typename SS, typename INTR > -uint8_t MAX3421e< SS, INTR >::IntHandler() -{ - uint8_t HIRQ; - uint8_t HIRQ_sendback = 0x00; - HIRQ = regRd( rHIRQ ); //determine interrupt source - //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler - // HIRQ_sendback |= bmFRAMEIRQ; - //}//end FRAMEIRQ handling - if( HIRQ & bmCONDETIRQ ) { - busprobe(); - HIRQ_sendback |= bmCONDETIRQ; - } - /* End HIRQ interrupts handling, clear serviced IRQs */ - regWr( rHIRQ, HIRQ_sendback ); - return( HIRQ_sendback ); +uint8_t MAX3421e< SS, INTR >::IntHandler() { + uint8_t HIRQ; + uint8_t HIRQ_sendback = 0x00; + HIRQ = regRd(rHIRQ); //determine interrupt source + //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler + // HIRQ_sendback |= bmFRAMEIRQ; + //}//end FRAMEIRQ handling + if(HIRQ & bmCONDETIRQ) { + busprobe(); + HIRQ_sendback |= bmCONDETIRQ; + } + /* End HIRQ interrupts handling, clear serviced IRQs */ + regWr(rHIRQ, HIRQ_sendback); + return( HIRQ_sendback); } //template< typename SS, typename INTR > //uint8_t MAX3421e< SS, INTR >::GpxHandler() @@ -308,7 +298,7 @@ uint8_t MAX3421e< SS, INTR >::IntHandler() //// delay( 1000 ); //// vbusPwr( ON ); //// regWr( rGPINIRQ, bmGPINIRQ7 ); -//// } +//// } // return( GPINIRQ ); //} diff --git a/usbhub.cpp b/usbhub.cpp index 761b3a37..52e20cfb 100644 --- a/usbhub.cpp +++ b/usbhub.cpp @@ -13,402 +13,382 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ #include "usbhub.h" bool USBHub::bResetInitiated = false; -USBHub::USBHub(USB *p) : - pUsb(p), - bAddress(0), - bNbrPorts(0), - bInitState(0), - qNextPollTime(0), - bPollEnable(false) -{ - epInfo[0].epAddr = 0; - epInfo[0].maxPktSize = 8; - epInfo[0].epAttribs = 0; - epInfo[0].bmNakPower = USB_NAK_MAX_POWER; +USBHub::USBHub(USB *p) : +pUsb(p), +bAddress(0), +bNbrPorts(0), +bInitState(0), +qNextPollTime(0), +bPollEnable(false) { + epInfo[0].epAddr = 0; + epInfo[0].maxPktSize = 8; + epInfo[0].epAttribs = 0; + epInfo[0].bmNakPower = USB_NAK_MAX_POWER; - epInfo[1].epAddr = 1; - epInfo[1].maxPktSize = 8; //kludge - epInfo[1].epAttribs = 0; - epInfo[1].bmNakPower = USB_NAK_NOWAIT; + epInfo[1].epAddr = 1; + epInfo[1].maxPktSize = 8; //kludge + epInfo[1].epAttribs = 0; + epInfo[1].bmNakPower = USB_NAK_NOWAIT; - if (pUsb) - pUsb->RegisterDeviceClass(this); + if (pUsb) + pUsb->RegisterDeviceClass(this); } -uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) -{ - uint8_t buf[32]; - uint8_t rcode; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; - uint8_t len = 0; - uint16_t cd_len = 0; - - //USBTRACE("\r\nHub Init Start"); +uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) { + uint8_t buf[32]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t len = 0; + uint16_t cd_len = 0; - AddressPool &addrPool = pUsb->GetAddressPool(); - - switch (bInitState) - { - case 0: - if (bAddress) - return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + //USBTRACE("\r\nHub Init Start"); - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); + AddressPool &addrPool = pUsb->GetAddressPool(); - if (!p) - return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + switch (bInitState) { + case 0: + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - if (!p->epinfo) - return USB_ERROR_EPINFO_IS_NULL; + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); - // Save old pointer to EP_RECORD of address 0 - oldep_ptr = p->epinfo; + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence - p->epinfo = epInfo; + if (!p->epinfo) + return USB_ERROR_EPINFO_IS_NULL; - p->lowspeed = lowspeed; + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; - // Get device descriptor - rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; - p->lowspeed = false; + p->lowspeed = lowspeed; - if (!rcode) - len = (buf[0] > 32) ? 32 : buf[0]; + // Get device descriptor + rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf); - if( rcode ) - { - // Restore p->epinfo - p->epinfo = oldep_ptr; - return rcode; - } + p->lowspeed = false; - // Extract device class from device descriptor - // If device class is not a hub return - if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09) - return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + if (!rcode) + len = (buf[0] > 32) ? 32 : buf[0]; - // Allocate new address according to device class - bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port); + if (rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + return rcode; + } - if (!bAddress) - return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + // Extract device class from device descriptor + // If device class is not a hub return + if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; - // Extract Max Packet Size from the device descriptor - epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port); - // Assign new address to the device - rcode = pUsb->setAddr( 0, 0, bAddress ); + if (!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; - if (rcode) - { - // Restore p->epinfo - p->epinfo = oldep_ptr; - addrPool.FreeAddress(bAddress); - bAddress = 0; - return rcode; - } - - //USBTRACE2("\r\nHub address: ", bAddress ); - - // Restore p->epinfo - p->epinfo = oldep_ptr; + // Extract Max Packet Size from the device descriptor + epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; - if (len) - rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf ); + // Assign new address to the device + rcode = pUsb->setAddr(0, 0, bAddress); - if(rcode) - goto FailGetDevDescr; + if (rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + addrPool.FreeAddress(bAddress); + bAddress = 0; + return rcode; + } - // Assign epInfo to epinfo pointer - rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); + //USBTRACE2("\r\nHub address: ", bAddress ); - if (rcode) - goto FailSetDevTblEntry; + // Restore p->epinfo + p->epinfo = oldep_ptr; - bInitState = 1; + if (len) + rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf); - case 1: - // Get hub descriptor - rcode = GetHubDescriptor(0, 8, buf); + if (rcode) + goto FailGetDevDescr; - if (rcode) - goto FailGetHubDescr; + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); - // Save number of ports for future use - bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts; + if (rcode) + goto FailSetDevTblEntry; - bInitState = 2; + bInitState = 1; - case 2: - // Read configuration Descriptor in Order To Obtain Proper Configuration Value - rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); + case 1: + // Get hub descriptor + rcode = GetHubDescriptor(0, 8, buf); - if (!rcode) - { - cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; - rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); - } - if (rcode) - goto FailGetConfDescr; + if (rcode) + goto FailGetHubDescr; - // The following code is of no practical use in real life applications. - // It only intended for the usb protocol sniffer to properly parse hub-class requests. - { - uint8_t buf2[24]; + // Save number of ports for future use + bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts; - rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); + bInitState = 2; - if (rcode) - goto FailGetConfDescr; - } + case 2: + // Read configuration Descriptor in Order To Obtain Proper Configuration Value + rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); - // Set Configuration Value - rcode = pUsb->setConf(bAddress, 0, buf[5]); + if (!rcode) { + cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; + rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); + } + if (rcode) + goto FailGetConfDescr; - if (rcode) - goto FailSetConfDescr; + // The following code is of no practical use in real life applications. + // It only intended for the usb protocol sniffer to properly parse hub-class requests. + { + uint8_t buf2[24]; - bInitState = 3; + rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); - case 3: - // Power on all ports - for (uint8_t j=1; j<=bNbrPorts; j++) - SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); + if (rcode) + goto FailGetConfDescr; + } - pUsb->SetHubPreMask(); - bPollEnable = true; - bInitState = 0; - } - bInitState = 0; - return 0; + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, buf[5]); + + if (rcode) + goto FailSetConfDescr; + + bInitState = 3; + + case 3: + // Power on all ports + for (uint8_t j = 1; j <= bNbrPorts; j++) + SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); + + pUsb->SetHubPreMask(); + bPollEnable = true; + bInitState = 0; + } + bInitState = 0; + return 0; FailGetDevDescr: - goto Fail; + goto Fail; FailSetDevTblEntry: - goto Fail; + goto Fail; FailGetHubDescr: - goto Fail; + goto Fail; FailGetConfDescr: - goto Fail; + goto Fail; FailSetConfDescr: - goto Fail; - -FailGetPortStatus: - goto Fail; + goto Fail; Fail: - return rcode; + return rcode; } -uint8_t USBHub::Release() -{ - pUsb->GetAddressPool().FreeAddress(bAddress); +uint8_t USBHub::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); - if (bAddress == 0x41) - pUsb->SetHubPreMask(); + if (bAddress == 0x41) + pUsb->SetHubPreMask(); - bAddress = 0; - bNbrPorts = 0; - qNextPollTime = 0; - bPollEnable = false; - return 0; + bAddress = 0; + bNbrPorts = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; } -uint8_t USBHub::Poll() -{ - uint8_t rcode = 0; +uint8_t USBHub::Poll() { + uint8_t rcode = 0; - if (!bPollEnable) - return 0; + if (!bPollEnable) + return 0; - if (qNextPollTime <= millis()) - { - rcode = CheckHubStatus(); - qNextPollTime = millis() + 100; - } - return rcode; + if (qNextPollTime <= millis()) { + rcode = CheckHubStatus(); + qNextPollTime = millis() + 100; + } + return rcode; } -uint8_t USBHub::CheckHubStatus() -{ - uint8_t rcode; - uint8_t buf[8]; - uint16_t read = 1; +uint8_t USBHub::CheckHubStatus() { + uint8_t rcode; + uint8_t buf[8]; + uint16_t read = 1; - rcode = pUsb->inTransfer(bAddress, 1, &read, buf); + rcode = pUsb->inTransfer(bAddress, 1, &read, buf); - if (rcode) - return rcode; + if (rcode) + return rcode; - if (buf[0] & 0x01) // Hub Status Change - { - //pUsb->PrintHubStatus(addr); - //rcode = GetHubStatus(1, 0, 1, 4, buf); - //if (rcode) - //{ - // Serial.print("GetHubStatus Error"); - // Serial.println(rcode, HEX); - // return rcode; - //} - } - for (uint8_t port=1,mask=0x02; port<8; mask<<=1, port++) - { - if (buf[0] & mask) - { - HubEvent evt; - evt.bmEvent = 0; + if (buf[0] & 0x01) // Hub Status Change + { + //pUsb->PrintHubStatus(addr); + //rcode = GetHubStatus(1, 0, 1, 4, buf); + //if (rcode) + //{ + // Serial.print("GetHubStatus Error"); + // Serial.println(rcode, HEX); + // return rcode; + //} + } + for (uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) { + if (buf[0] & mask) { + HubEvent evt; + evt.bmEvent = 0; - rcode = GetPortStatus(port, 4, evt.evtBuff); + rcode = GetPortStatus(port, 4, evt.evtBuff); - if (rcode) - continue; + if (rcode) + continue; - rcode = PortStatusChange(port, evt); + rcode = PortStatusChange(port, evt); - if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) - return 0; + if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) + return 0; - if (rcode) - return rcode; - } - } // for + if (rcode) + return rcode; + } + } // for - for (uint8_t port=1; port<=bNbrPorts; port++) - { - HubEvent evt; - evt.bmEvent = 0; + for (uint8_t port = 1; port <= bNbrPorts; port++) { + HubEvent evt; + evt.bmEvent = 0; - rcode = GetPortStatus(port, 4, evt.evtBuff); + rcode = GetPortStatus(port, 4, evt.evtBuff); - if (rcode) - continue; + if (rcode) + continue; - if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) - continue; + if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) + continue; - // Emulate connection event for the port - evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; + // Emulate connection event for the port + evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; - rcode = PortStatusChange(port, evt); + rcode = PortStatusChange(port, evt); - if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) - return 0; + if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) + return 0; - if (rcode) - return rcode; - } // for - return 0; + if (rcode) + return rcode; + } // for + return 0; } -uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) -{ - switch (evt.bmEvent) - { - // Device connected event - case bmHUB_PORT_EVENT_CONNECT: - case bmHUB_PORT_EVENT_LS_CONNECT: - if (bResetInitiated) - return 0; +uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) { + switch (evt.bmEvent) { + // Device connected event + case bmHUB_PORT_EVENT_CONNECT: + case bmHUB_PORT_EVENT_LS_CONNECT: + if (bResetInitiated) + return 0; - ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); - ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); - SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); - bResetInitiated = true; - return HUB_ERROR_PORT_HAS_BEEN_RESET; + ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); + bResetInitiated = true; + return HUB_ERROR_PORT_HAS_BEEN_RESET; - // Device disconnected event - case bmHUB_PORT_EVENT_DISCONNECT: - ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); - ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); - bResetInitiated = false; + // Device disconnected event + case bmHUB_PORT_EVENT_DISCONNECT: + ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + bResetInitiated = false; - UsbDeviceAddress a; - a.bmHub = 0; - a.bmParent = bAddress; - a.bmAddress = port; - pUsb->ReleaseDevice(a.devAddress); - return 0; + UsbDeviceAddress a; + a.bmHub = 0; + a.bmParent = bAddress; + a.bmAddress = port; + pUsb->ReleaseDevice(a.devAddress); + return 0; - // Reset complete event - case bmHUB_PORT_EVENT_RESET_COMPLETE: - case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: - ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); - ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + // Reset complete event + case bmHUB_PORT_EVENT_RESET_COMPLETE: + case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: + ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); - delay(20); + delay(20); - a.devAddress = bAddress; + a.devAddress = bAddress; - pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) ); - bResetInitiated = false; - break; + pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED)); + bResetInitiated = false; + break; - } // switch (evt.bmEvent) - return 0; + } // switch (evt.bmEvent) + return 0; } -void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) -{ - uint8_t rcode = 0; - HubEvent evt; +void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) { + uint8_t rcode = 0; + HubEvent evt; - rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); + rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); - if (rcode) - { - Serial.println("ERROR!"); - return; - } - Serial.print("\r\nPort "); - Serial.println(port, DEC); + if (rcode) { + Serial.println("ERROR!"); + return; + } + Serial.print("\r\nPort "); + Serial.println(port, DEC); - Serial.println("Status"); - Serial.print("CONNECTION:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC); - Serial.print("ENABLE:\t\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC); - Serial.print("SUSPEND:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC); - Serial.print("OVER_CURRENT:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC); - Serial.print("RESET:\t\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC); - Serial.print("POWER:\t\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC); - Serial.print("LOW_SPEED:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC); - Serial.print("HIGH_SPEED:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC); - Serial.print("TEST:\t\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC); - Serial.print("INDICATOR:\t"); - Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC); + Serial.println("Status"); + Serial.print("CONNECTION:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC); + Serial.print("ENABLE:\t\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC); + Serial.print("SUSPEND:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC); + Serial.print("OVER_CURRENT:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC); + Serial.print("RESET:\t\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC); + Serial.print("POWER:\t\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC); + Serial.print("LOW_SPEED:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC); + Serial.print("HIGH_SPEED:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC); + Serial.print("TEST:\t\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC); + Serial.print("INDICATOR:\t"); + Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC); - if (!print_changes) - return; + if (!print_changes) + return; - Serial.println("\nChange"); - Serial.print("CONNECTION:\t"); - Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC); - Serial.print("ENABLE:\t\t"); - Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC); - Serial.print("SUSPEND:\t"); - Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC); - Serial.print("OVER_CURRENT:\t"); - Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC); - Serial.print("RESET:\t\t"); - Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC); + Serial.println("\r\nChange"); + Serial.print("CONNECTION:\t"); + Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC); + Serial.print("ENABLE:\t\t"); + Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC); + Serial.print("SUSPEND:\t"); + Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC); + Serial.print("OVER_CURRENT:\t"); + Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC); + Serial.print("RESET:\t\t"); + Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC); } diff --git a/usbhub.h b/usbhub.h index d34afa43..0150c4b3 100644 --- a/usbhub.h +++ b/usbhub.h @@ -13,7 +13,7 @@ Contact information Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com -*/ + */ #if !defined(__USBHUB_H__) #define __USBHUB_H__ @@ -25,6 +25,7 @@ e-mail : support@circuitsathome.com #include "usb_ch9.h" #include "Usb.h" + #if defined(ARDUINO) && ARDUINO >=100 #include "Arduino.h" #else @@ -76,7 +77,7 @@ e-mail : support@circuitsathome.com #define HUB_PORT_TEST_MODE_K 2 #define HUB_PORT_TEST_MODE_SE0_NAK 3 #define HUB_PORT_TEST_MODE_PACKET 4 -#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5 +#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5 // Hub Port Indicator Color #define HUB_PORT_INDICATOR_AUTO 0 @@ -84,7 +85,7 @@ e-mail : support@circuitsathome.com #define HUB_PORT_INDICATOR_GREEN 2 #define HUB_PORT_INDICATOR_OFF 3 -// Hub Port Status Bitmasks +// Hub Port Status Bitmasks #define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001 #define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002 #define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004 @@ -127,7 +128,7 @@ e-mail : support@circuitsathome.com // The bit mask to check for all necessary state bits #define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND) -// Bit mask to check for DISABLED state in HubEvent::bmStatus field +// Bit mask to check for DISABLED state in HubEvent::bmStatus field #define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND) // Hub Port States @@ -142,118 +143,117 @@ e-mail : support@circuitsathome.com #define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) #define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) -struct HubDescriptor -{ - uint8_t bDescLength; // descriptor length - uint8_t bDescriptorType; // descriptor type - uint8_t bNbrPorts; // number of ports a hub equiped with - - struct - { - uint16_t LogPwrSwitchMode : 2; - uint16_t CompoundDevice : 1; - uint16_t OverCurrentProtectMode : 2; - uint16_t TTThinkTime : 2; - uint16_t PortIndicatorsSupported : 1; - uint16_t Reserved : 8; - }; +struct HubDescriptor { + uint8_t bDescLength; // descriptor length + uint8_t bDescriptorType; // descriptor type + uint8_t bNbrPorts; // number of ports a hub equiped with - uint8_t bPwrOn2PwrGood; - uint8_t bHubContrCurrent; -}; + struct { + uint16_t LogPwrSwitchMode : 2; + uint16_t CompoundDevice : 1; + uint16_t OverCurrentProtectMode : 2; + uint16_t TTThinkTime : 2; + uint16_t PortIndicatorsSupported : 1; + uint16_t Reserved : 8; + } __attribute__((packed)); -struct HubEvent -{ - union - { - struct - { - uint16_t bmStatus; // port status bits - uint16_t bmChange; // port status change bits - }; - uint32_t bmEvent; - uint8_t evtBuff[4]; - }; -}; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; +} __attribute__((packed)); -class USBHub : USBDeviceConfig -{ - static bool bResetInitiated; // True when reset is triggered +struct HubEvent { - USB *pUsb; // USB class instance pointer + union { - EpInfo epInfo[2]; // interrupt endpoint info structure + struct { + uint16_t bmStatus; // port status bits + uint16_t bmChange; // port status change bits + } __attribute__((packed)); + uint32_t bmEvent; + uint8_t evtBuff[4]; + }; +} __attribute__((packed)); - uint8_t bAddress; // address - uint8_t bNbrPorts; // number of ports - uint8_t bInitState; // initialization state variable - uint32_t qNextPollTime; // next poll time - bool bPollEnable; // poll enable flag +class USBHub : USBDeviceConfig { + static bool bResetInitiated; // True when reset is triggered - uint8_t CheckHubStatus(); - uint8_t PortStatusChange(uint8_t port, HubEvent &evt); + USB *pUsb; // USB class instance pointer + + EpInfo epInfo[2]; // interrupt endpoint info structure + + uint8_t bAddress; // address + uint8_t bNbrPorts; // number of ports + uint8_t bInitState; // initialization state variable + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + uint8_t CheckHubStatus(); + uint8_t PortStatusChange(uint8_t port, HubEvent &evt); public: - USBHub(USB *p); + USBHub(USB *p); - uint8_t ClearHubFeature( uint8_t fid ); - uint8_t ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 ); - uint8_t GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr ); - uint8_t GetHubStatus( uint16_t nbytes, uint8_t* dataptr ); - uint8_t GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr ); - uint8_t SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr ); - uint8_t SetHubFeature( uint8_t fid ); - uint8_t SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 ); + uint8_t ClearHubFeature(uint8_t fid); + uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0); + uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr); + uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr); + uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr); + uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr); + uint8_t SetHubFeature(uint8_t fid); + uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0); - void PrintHubStatus(); + void PrintHubStatus(); - virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); - virtual uint8_t Release(); - virtual uint8_t Poll(); - virtual uint8_t GetAddress() { return bAddress; }; + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; }; // Clear Hub Feature -inline uint8_t USBHub::ClearHubFeature( uint8_t fid ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL )); + +inline uint8_t USBHub::ClearHubFeature(uint8_t fid) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL)); } // Clear Port Feature -inline uint8_t USBHub::ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, 0, NULL, NULL )); + +inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL)); } // Get Hub Descriptor -inline uint8_t USBHub::GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL )); + +inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL)); } // Get Hub Status -inline uint8_t USBHub::GetHubStatus( uint16_t nbytes, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL )); + +inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL)); } // Get Port Status -inline uint8_t USBHub::GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL )); + +inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL)); } // Set Hub Descriptor -inline uint8_t USBHub::SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL )); + +inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL)); } // Set Hub Feature -inline uint8_t USBHub::SetHubFeature( uint8_t fid ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL )); + +inline uint8_t USBHub::SetHubFeature(uint8_t fid) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL)); } // Set Port Feature -inline uint8_t USBHub::SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel ) -{ - return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, 0, NULL, NULL )); + +inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) { + return( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL)); } void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false); -#endif // __USBHUB_H__ \ No newline at end of file +#endif // __USBHUB_H__ diff --git a/xboxEnums.h b/xboxEnums.h index d66956f0..adf60f9b 100644 --- a/xboxEnums.h +++ b/xboxEnums.h @@ -1,15 +1,15 @@ /* Copyright (C) 2012 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 @@ -22,43 +22,43 @@ /** Enum used to set special LED modes supported by the Xbox controller. */ enum LEDMode { - ROTATING = 0x0A, - FASTBLINK = 0x0B, - SLOWBLINK = 0x0C, - ALTERNATING = 0x0D, + ROTATING = 0x0A, + FASTBLINK = 0x0B, + SLOWBLINK = 0x0C, + ALTERNATING = 0x0D, }; /** Used to set the LEDs on the controllers */ const uint8_t XBOXLEDS[] PROGMEM = { - 0x02, // LED1 - 0x03, // LED2 - 0x04, // LED3 - 0x05, // LED4 - 0x01 // ALL - Used to blink all LEDs - }; -/** Buttons on the controllers */ + 0x02, // LED1 + 0x03, // LED2 + 0x04, // LED3 + 0x05, // LED4 + 0x01 // ALL - Used to blink all LEDs +}; +/** Buttons on the controllers */ const uint16_t XBOXBUTTONS[] PROGMEM = { - 0x0100, // UP - 0x0800, // RIGHT - 0x0200, // DOWN - 0x0400, // LEFT + 0x0100, // UP + 0x0800, // RIGHT + 0x0200, // DOWN + 0x0400, // LEFT - 0x2000, // BACK - 0x1000, // START - 0x4000, // L3 - 0x8000, // R3 + 0x2000, // BACK + 0x1000, // START + 0x4000, // L3 + 0x8000, // R3 - 0,0, // Skip L2 and R2 as these are analog buttons - 0x0001, // L1 - 0x0002, // R1 + 0, 0, // Skip L2 and R2 as these are analog buttons + 0x0001, // L1 + 0x0002, // R1 - 0x0020, // B - 0x0010, // A - 0x0040, // X - 0x0080, // Y + 0x0020, // B + 0x0010, // A + 0x0040, // X + 0x0080, // Y - 0x0004, // XBOX - 0x0008 // SYNC + 0x0004, // XBOX + 0x0008 // SYNC }; #endif \ No newline at end of file