- Fixed issue where temp updates stops updating in status screen.
    - Added feedrate controls.
    - Added tune print menu.
    - Added ability to extrude/retract from touch UI
    - Added support for M300 gcode.
    - Fixed glitches with the sound code.
    - Added USB drive code.
        - Note: This is pending the relicensing of the USB code from "GPL v2" to "GPL v2 and later"
                which the authors have agreed upon.
    - Added ability to browse directory hierarchy.
			
			
				master
			
			
		
							parent
							
								
									6f8605bc63
								
							
						
					
					
						commit
						b110fd01e7
					
				| @ -0,0 +1,85 @@ | ||||
| /**
 | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
 | ||||
|  * | ||||
|  * Based on Sprinter and grbl. | ||||
|  * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm | ||||
|  * | ||||
|  * 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 3 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, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| /**
 | ||||
|  * \file | ||||
|  * \brief Sd2Card class for V2 SD/SDHC cards | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _FAKE_SD2CARD_H_ | ||||
| #define _FAKE_SD2CARD_H_ | ||||
| 
 | ||||
| #include "SdFatConfig.h" | ||||
| #include "SdInfo.h" | ||||
| 
 | ||||
| // SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
 | ||||
| uint8_t const SPI_FULL_SPEED = 0,         // Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate().
 | ||||
|               SPI_HALF_SPEED = 1,         // Set SCK rate to F_CPU/4. See Sd2Card::setSckRate().
 | ||||
|               SPI_QUARTER_SPEED = 2,      // Set SCK rate to F_CPU/8. See Sd2Card::setSckRate().
 | ||||
|               SPI_EIGHTH_SPEED = 3,       // Set SCK rate to F_CPU/16. See Sd2Card::setSckRate().
 | ||||
|               SPI_SIXTEENTH_SPEED = 4;    // Set SCK rate to F_CPU/32. See Sd2Card::setSckRate().
 | ||||
| 
 | ||||
| /**
 | ||||
|  * define SOFTWARE_SPI to use bit-bang SPI | ||||
|  */ | ||||
| #if MEGA_SOFT_SPI | ||||
|   #define SOFTWARE_SPI | ||||
| #elif USE_SOFTWARE_SPI | ||||
|   #define SOFTWARE_SPI | ||||
| #endif | ||||
| 
 | ||||
| // SPI pin definitions - do not edit here - change in SdFatConfig.h
 | ||||
| #if DISABLED(SOFTWARE_SPI) | ||||
|   // hardware pin defs
 | ||||
|   #define SD_CHIP_SELECT_PIN SS_PIN   // The default chip select pin for the SD card is SS.
 | ||||
|   // The following three pins must not be redefined for hardware SPI.
 | ||||
|   #define SPI_MOSI_PIN MOSI_PIN       // SPI Master Out Slave In pin
 | ||||
|   #define SPI_MISO_PIN MISO_PIN       // SPI Master In Slave Out pin
 | ||||
|   #define SPI_SCK_PIN SCK_PIN         // SPI Clock pin
 | ||||
| #else  // SOFTWARE_SPI
 | ||||
|   #define SD_CHIP_SELECT_PIN SOFT_SPI_CS_PIN  // SPI chip select pin
 | ||||
|   #define SPI_MOSI_PIN SOFT_SPI_MOSI_PIN      // SPI Master Out Slave In pin
 | ||||
|   #define SPI_MISO_PIN SOFT_SPI_MISO_PIN      // SPI Master In Slave Out pin
 | ||||
|   #define SPI_SCK_PIN SOFT_SPI_SCK_PIN        // SPI Clock pin
 | ||||
| #endif  // SOFTWARE_SPI
 | ||||
| 
 | ||||
| /**
 | ||||
|  * \class Sd2Card | ||||
|  * \brief Raw access to SD and SDHC flash memory cards. | ||||
|  */ | ||||
| class Sd2Card { | ||||
|   public: | ||||
| 
 | ||||
|   Sd2Card(); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Initialize an SD flash memory card with default clock rate and chip | ||||
|    * select pin.  See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). | ||||
|    * | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool init(uint8_t sckRateID = 0, uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); | ||||
|   bool readBlock(uint32_t block, uint8_t* dst); | ||||
|   bool writeBlock(uint32_t blockNumber, const uint8_t* src); | ||||
| }; | ||||
| 
 | ||||
| #endif  // _FAKE_SD2CARD_H_
 | ||||
| @ -0,0 +1,147 @@ | ||||
| /**
 | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
 | ||||
|  * | ||||
|  * Based on Sprinter and grbl. | ||||
|  * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm | ||||
|  * | ||||
|  * 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 3 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, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| /********************************************************************************************
 | ||||
|  * This program/sketch is used to run a USB Thumb Drive.                                    * | ||||
|  *                                                                                          * | ||||
|  * NOTE - This Arduino Sketch has been modified to initialize a MAX3421E USB Host Interface * | ||||
|  * chip, write 3 test files, print out the directory of the thumb drive and print out the   * | ||||
|  * contents of a short .txt file.                                                           * | ||||
|  *                                                                                          * | ||||
|  * The code is leveraged from the following:                                                * | ||||
|  *                                                                                          * | ||||
|  * 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                                                   * | ||||
|  *                                                                                          * | ||||
|  * SPECIAL NOTE - In order to work with a modified Eisny or RAMBo, the SPI chip select pin  * | ||||
|  * (CS) (D10) has been remapped from PORTB Pin-4 to PORTB Pin-0.  This has been done in the * | ||||
|  * __AVR_ATmega2560__ section of the avrpins.h file.                                        * | ||||
|  *                                                                                          * | ||||
|  ********************************************************************************************/ | ||||
| 
 | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| //#define _usb_h_
 | ||||
| 
 | ||||
| #include "Marlin.h" | ||||
| #include "../watchdog.h" | ||||
| 
 | ||||
| #undef MACROS_H | ||||
| 
 | ||||
| #define USB_HOST_SERIAL customizedSerial | ||||
| 
 | ||||
| #include "lib/masstorage.h" | ||||
| #include "lib/masstorage.cpp" | ||||
| #include "lib/message.cpp" | ||||
| #include "lib/parsetools.cpp" | ||||
| #include "lib/Usb.cpp" | ||||
| 
 | ||||
| 
 | ||||
| #include "Fake_Sd2Card.h" | ||||
| 
 | ||||
| #define MAX_USB_RST 7 | ||||
| 
 | ||||
| // USB host objects.v
 | ||||
| USB usb; | ||||
| BulkOnly bulk(&usb); | ||||
| 
 | ||||
| #define error(msg) {Serial.print("Error: "); Serial.println(msg);} | ||||
| 
 | ||||
| #define TIMEOUT_MILLIS 4000 | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| bool initUSB(USB* usb) { | ||||
|   uint8_t current_state = 0; | ||||
|   uint32_t m = millis(); | ||||
| 
 | ||||
|   for (uint8_t i = 0; usb->Init(1000) == -1; i++) | ||||
|   { | ||||
|     SERIAL_ECHOLNPGM("No USB HOST Shield?"); | ||||
|     watchdog_reset(); | ||||
|     if (i > 10) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   usb->vbusPower(vbus_on); | ||||
| 
 | ||||
|   while ((millis() - m) < TIMEOUT_MILLIS) { | ||||
|     usb->Task(); | ||||
|     current_state = usb->getUsbTaskState(); | ||||
|     if(current_state == USB_STATE_RUNNING) { | ||||
|       return true; | ||||
|     } | ||||
|     watchdog_reset(); | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| Sd2Card::Sd2Card() { | ||||
| }; | ||||
| 
 | ||||
| bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
|   if (!initUSB(&usb)) | ||||
|   { | ||||
|     SERIAL_ECHOLNPGM("initUSB failed"); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     SERIAL_ECHOLNPGM("USB Initialized\n"); | ||||
|   } | ||||
| 
 | ||||
|   if(!bulk.LUNIsGood(0)) { | ||||
|     SERIAL_ECHOLNPGM("LUN zero is not good\n"); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   SERIAL_ECHOLNPAIR("LUN Capacity: ",bulk.GetCapacity(0)); | ||||
| 
 | ||||
|   const uint32_t sectorSize = bulk.GetSectorSize(0); | ||||
|   if(sectorSize != 512) { | ||||
|     SERIAL_ECHOLNPAIR("Expecting sector size of 512, got: ",sectorSize); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) { | ||||
|   return bulk.Read(0, block, 512, 1, dst) == 0; | ||||
| } | ||||
| 
 | ||||
| bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { | ||||
|   return bulk.Write(0, blockNumber, 512, 1, src) == 0; | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,812 @@ | ||||
| /* 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 | ||||
|  */ | ||||
| /* USB functions */ | ||||
| 
 | ||||
| #include "Usb.h" | ||||
| 
 | ||||
| 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(); | ||||
| } | ||||
| 
 | ||||
| /* Initialize data structures */ | ||||
| void USB::init() { | ||||
|         //devConfigIndex = 0;
 | ||||
|         bmHubPre = 0; | ||||
| } | ||||
| 
 | ||||
| uint8_t USB::getUsbTaskState(void) { | ||||
|         return ( usb_task_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); | ||||
| 
 | ||||
|         if(!p || !p->epinfo) | ||||
|                 return NULL; | ||||
| 
 | ||||
|         EpInfo *pep = p->epinfo; | ||||
| 
 | ||||
|         for(uint8_t i = 0; i < p->epcount; i++) { | ||||
|                 if((pep)->epAddr == ep) | ||||
|                         return pep; | ||||
| 
 | ||||
|                 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; | ||||
| 
 | ||||
|         UsbDevice *p = addrPool.GetUsbDevicePtr(addr); | ||||
| 
 | ||||
|         if(!p) | ||||
|                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||||
| 
 | ||||
|         p->address.devAddress = 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); | ||||
| 
 | ||||
|         if(!p) | ||||
|                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||||
| 
 | ||||
|         if(!p->epinfo) | ||||
|                 return USB_ERROR_EPINFO_IS_NULL; | ||||
| 
 | ||||
|         *ppep = getEpInfoEntry(addr, ep); | ||||
| 
 | ||||
|         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
 | ||||
| 
 | ||||
|         uint8_t mode = regRd(rMODE); | ||||
| 
 | ||||
|         //Serial.print("\r\nMode: ");
 | ||||
|         //Serial.println( mode, HEX);
 | ||||
|         //Serial.print("\r\nLS: ");
 | ||||
|         //Serial.println(p->lowspeed, HEX);
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
 | ||||
|         regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); | ||||
| 
 | ||||
|         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) { | ||||
|         bool direction = false; //request direction, IN or OUT
 | ||||
|         uint8_t rcode; | ||||
|         SETUP_PKT setup_pkt; | ||||
| 
 | ||||
|         EpInfo *pep = NULL; | ||||
|         uint16_t nak_limit = 0; | ||||
| 
 | ||||
|         rcode = SetAddress(addr, ep, &pep, nak_limit); | ||||
| 
 | ||||
|         if(rcode) | ||||
|                 return rcode; | ||||
| 
 | ||||
|         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
 | ||||
| 
 | ||||
|         rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
 | ||||
| 
 | ||||
|         if(rcode) //return HRSLT if not zero
 | ||||
|                 return ( rcode); | ||||
| 
 | ||||
|         if(dataptr != NULL) //data stage, if present
 | ||||
|         { | ||||
|                 if(direction) //IN transfer
 | ||||
|                 { | ||||
|                         uint16_t left = total; | ||||
| 
 | ||||
|                         pep->bmRcvToggle = 1; //bmRCVTOG1;
 | ||||
| 
 | ||||
|                         while(left) { | ||||
|                                 // Bytes read into buffer
 | ||||
|                                 uint16_t read = nbytes; | ||||
|                                 //uint16_t read = (left<nbytes) ? left : nbytes;
 | ||||
| 
 | ||||
|                                 rcode = InTransfer(pep, nak_limit, &read, dataptr); | ||||
|                                 if(rcode == hrTOGERR) { | ||||
|                                         // yes, we flip it wrong here so that next time it is actually correct!
 | ||||
|                                         pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; | ||||
|                                         continue; | ||||
|                                 } | ||||
| 
 | ||||
|                                 if(rcode) | ||||
|                                         return rcode; | ||||
| 
 | ||||
|                                 // Invoke callback function if inTransfer completed successfully and callback function pointer is specified
 | ||||
|                                 if(!rcode && p) | ||||
|                                         ((USBReadParser*)p)->Parse(read, dataptr, total - left); | ||||
| 
 | ||||
|                                 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 rcode = SetAddress(addr, ep, &pep, nak_limit); | ||||
| 
 | ||||
|         if(rcode) { | ||||
|                 USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81); | ||||
|                 USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81); | ||||
|                 USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81); | ||||
|                 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; | ||||
| 
 | ||||
|         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
 | ||||
| 
 | ||||
|         // use a 'break' to exit this loop
 | ||||
|         while(1) { | ||||
|                 rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
 | ||||
|                 if(rcode == hrTOGERR) { | ||||
|                         // yes, we flip it wrong here so that next time it is actually correct!
 | ||||
|                         pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; | ||||
|                         regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
 | ||||
|                         continue; | ||||
|                 } | ||||
|                 if(rcode) { | ||||
|                         //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
 | ||||
|                         break; //should be 0, indicating ACK. Else return error code.
 | ||||
|                 } | ||||
|                 /* check for RCVDAVIRQ and generate error if not present */ | ||||
|                 /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */ | ||||
|                 if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) { | ||||
|                         //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
 | ||||
|                         rcode = 0xf0; //receive error
 | ||||
|                         break; | ||||
|                 } | ||||
|                 pktsize = regRd(rRCVBC); //number of received bytes
 | ||||
|                 //printf("Got %i bytes \r\n", pktsize);
 | ||||
|                 // This would be OK, but...
 | ||||
|                 //assert(pktsize <= nbytes);
 | ||||
|                 if(pktsize > nbytes) { | ||||
|                         // This can happen. Use of assert on Arduino locks up the Arduino.
 | ||||
|                         // So I will trim the value, and hope for the best.
 | ||||
|                         //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
 | ||||
|                         pktsize = nbytes; | ||||
|                 } | ||||
| 
 | ||||
|                 int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); | ||||
| 
 | ||||
|                 if(mem_left < 0) | ||||
|                         mem_left = 0; | ||||
| 
 | ||||
|                 data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); | ||||
| 
 | ||||
|                 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 = 0; | ||||
| 
 | ||||
|         uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); | ||||
| 
 | ||||
|         if(rcode) | ||||
|                 return rcode; | ||||
| 
 | ||||
|         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 = 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); | ||||
| 
 | ||||
|                 while(rcode && ((long)(millis() - timeout) < 0L)) { | ||||
|                         switch(rcode) { | ||||
|                                 case hrNAK: | ||||
|                                         nak_count++; | ||||
|                                         if(nak_limit && (nak_count == nak_limit)) | ||||
|                                                 goto breakout; | ||||
|                                         //return ( rcode);
 | ||||
|                                         break; | ||||
|                                 case hrTIMEOUT: | ||||
|                                         retry_count++; | ||||
|                                         if(retry_count == USB_RETRY_LIMIT) | ||||
|                                                 goto breakout; | ||||
|                                         //return ( rcode);
 | ||||
|                                         break; | ||||
|                                 case hrTOGERR: | ||||
|                                         // yes, we flip it wrong here so that next time it is actually correct!
 | ||||
|                                         pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; | ||||
|                                         regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
 | ||||
|                                         break; | ||||
|                                 default: | ||||
|                                         goto breakout; | ||||
|                         }//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...
 | ||||
| breakout: | ||||
| 
 | ||||
|         pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0;  //update toggle
 | ||||
|         return ( rcode); //should be 0 in all cases
 | ||||
| } | ||||
| /* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty       */ | ||||
| /* 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 = hrSUCCESS; | ||||
|         uint8_t retry_count = 0; | ||||
|         uint16_t nak_count = 0; | ||||
| 
 | ||||
|         while((long)(millis() - timeout) < 0L) { | ||||
|                 regWr(rHXFR, (token | ep)); //launch the transfer
 | ||||
|                 rcode = USB_ERROR_TRANSFER_TIMEOUT; | ||||
| 
 | ||||
|                 while((long)(millis() - timeout) < 0L) //wait for transfer completion
 | ||||
|                 { | ||||
|                         tmpdata = regRd(rHIRQ); | ||||
| 
 | ||||
|                         if(tmpdata & bmHXFRDNIRQ) { | ||||
|                                 regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
 | ||||
|                                 rcode = 0x00; | ||||
|                                 break; | ||||
|                         }//if( tmpdata & bmHXFRDNIRQ
 | ||||
| 
 | ||||
|                 }//while ( millis() < timeout
 | ||||
| 
 | ||||
|                 //if (rcode != 0x00) //exit if timeout
 | ||||
|                 //        return ( rcode);
 | ||||
| 
 | ||||
|                 rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
 | ||||
| 
 | ||||
|                 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); | ||||
| } | ||||
| 
 | ||||
| /* USB main task. Performs enumeration/cleanup */ | ||||
| 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; | ||||
| 
 | ||||
|         MAX3421E::Task(); | ||||
| 
 | ||||
|         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; | ||||
|                         //intentional fallthrough
 | ||||
|                 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; i < USB_NUMDEVICES; i++) | ||||
|                 if(devConfig[i]) | ||||
|                         rcode = devConfig[i]->Poll(); | ||||
| 
 | ||||
|         switch(usb_task_state) { | ||||
|                 case USB_DETACHED_SUBSTATE_INITIALIZE: | ||||
|                         init(); | ||||
| 
 | ||||
|                         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: //settle time for just attached device
 | ||||
|                         if((long)(millis() - delay) >= 0L) | ||||
|                                 usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; | ||||
|                         else break; // don't fall through
 | ||||
|                 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 _and_ 20ms has passed we can continue
 | ||||
|                                 /*
 | ||||
|                                 if (delay < millis()) //20ms passed
 | ||||
|                                         usb_task_state = USB_STATE_CONFIGURING; | ||||
|                                  */ | ||||
|                                 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET; | ||||
|                                 delay = millis() + 20; | ||||
|                         } | ||||
|                         break; | ||||
|                 case USB_ATTACHED_SUBSTATE_WAIT_RESET: | ||||
|                         if((long)(millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING; | ||||
|                         else break; // don't fall through
 | ||||
|                 case USB_STATE_CONFIGURING: | ||||
| 
 | ||||
|                         //Serial.print("\r\nConf.LS: ");
 | ||||
|                         //Serial.println(lowspeed, HEX);
 | ||||
| 
 | ||||
|                         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: | ||||
|                         //MAX3421E::Init();
 | ||||
|                         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::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) { | ||||
|         //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
 | ||||
|         uint8_t retries = 0; | ||||
| 
 | ||||
| again: | ||||
|         uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed); | ||||
|         if(rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) { | ||||
|                 if(parent == 0) { | ||||
|                         // Send a bus reset on the root interface.
 | ||||
|                         regWr(rHCTL, bmBUSRST); //issue bus reset
 | ||||
|                         DELAY(102); // delay 102ms, compensate for clock inaccuracy.
 | ||||
|                 } else { | ||||
|                         // reset parent port
 | ||||
|                         devConfig[parent]->ResetHubPort(port); | ||||
|                 } | ||||
|         } else if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
 | ||||
|                 DELAY(100); | ||||
|                 retries++; | ||||
|                 goto again; | ||||
|         } else if(rcode) | ||||
|                 return rcode; | ||||
| 
 | ||||
|         rcode = devConfig[driver]->Init(parent, port, lowspeed); | ||||
|         if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
 | ||||
|                 DELAY(100); | ||||
|                 retries++; | ||||
|                 goto again; | ||||
|         } | ||||
|         if(rcode) { | ||||
|                 // Issue a bus reset, because the device may be in a limbo state
 | ||||
|                 if(parent == 0) { | ||||
|                         // Send a bus reset on the root interface.
 | ||||
|                         regWr(rHCTL, bmBUSRST); //issue bus reset
 | ||||
|                         DELAY(102); // delay 102ms, compensate for clock inaccuracy.
 | ||||
|                 } else { | ||||
|                         // reset parent port
 | ||||
|                         devConfig[parent]->ResetHubPort(port); | ||||
|                 } | ||||
|         } | ||||
|         return rcode; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This is broken. We need to enumerate differently. | ||||
|  * It causes major problems with several devices if detected in an unexpected order. | ||||
|  * | ||||
|  * | ||||
|  * Oleg - I wouldn't do anything before the newly connected device is considered sane. | ||||
|  * i.e.(delays are not indicated for brevity): | ||||
|  * 1. reset | ||||
|  * 2. GetDevDescr(); | ||||
|  * 3a. If ACK, continue with allocating address, addressing, etc. | ||||
|  * 3b. Else reset again, count resets, stop at some number (5?). | ||||
|  * 4. When max.number of resets is reached, toggle power/fail | ||||
|  * If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD() | ||||
|  * it doesn't need to be reset again | ||||
|  * New steps proposal: | ||||
|  * 1: get address pool instance. exit on fail | ||||
|  * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail. | ||||
|  * 3: bus reset, 100ms delay | ||||
|  * 4: set address | ||||
|  * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail | ||||
|  * 6: while (configurations) { | ||||
|  *              for(each configuration) { | ||||
|  *                      for (each driver) { | ||||
|  *                              6a: Ask device if it likes configuration. Returns 0 on OK. | ||||
|  *                                      If successful, the driver configured device. | ||||
|  *                                      The driver now owns the endpoints, and takes over managing them. | ||||
|  *                                      The following will need codes: | ||||
|  *                                          Everything went well, instance consumed, exit with success. | ||||
|  *                                          Instance already in use, ignore it, try next driver. | ||||
|  *                                          Not a supported device, ignore it, try next driver. | ||||
|  *                                          Not a supported configuration for this device, ignore it, try next driver. | ||||
|  *                                          Could not configure device, fatal, exit with fail. | ||||
|  *                      } | ||||
|  *              } | ||||
|  *    } | ||||
|  * 7: for(each driver) { | ||||
|  *      7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID | ||||
|  * 8: if we get here, no driver likes the device plugged in, so exit failure. | ||||
|  * | ||||
|  */ | ||||
| uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { | ||||
|         //uint8_t bAddress = 0;
 | ||||
|         //printf("Configuring: parent = %i, port = %i\r\n", parent, port);
 | ||||
|         uint8_t devConfigIndex; | ||||
|         uint8_t rcode = 0; | ||||
|         uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; | ||||
|         USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf); | ||||
|         UsbDevice *p = NULL; | ||||
|         EpInfo *oldep_ptr = NULL; | ||||
|         EpInfo epInfo; | ||||
| 
 | ||||
|         epInfo.epAddr = 0; | ||||
|         epInfo.maxPktSize = 8; | ||||
|         epInfo.epAttribs = 0; | ||||
|         epInfo.bmNakPower = USB_NAK_MAX_POWER; | ||||
| 
 | ||||
|         //DELAY(2000);
 | ||||
|         AddressPool &addrPool = GetAddressPool(); | ||||
|         // Get pointer to pseudo device with address 0 assigned
 | ||||
|         p = addrPool.GetUsbDevicePtr(0); | ||||
|         if(!p) { | ||||
|                 //printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
 | ||||
|                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||||
|         } | ||||
| 
 | ||||
|         // Save old pointer to EP_RECORD of address 0
 | ||||
|         oldep_ptr = p->epinfo; | ||||
| 
 | ||||
|         // Temporary assign new pointer to epInfo to p->epinfo in order to
 | ||||
|         // avoid toggle inconsistence
 | ||||
| 
 | ||||
|         p->epinfo = &epInfo; | ||||
| 
 | ||||
|         p->lowspeed = lowspeed; | ||||
|         // Get device descriptor
 | ||||
|         rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); | ||||
| 
 | ||||
|         // Restore p->epinfo
 | ||||
|         p->epinfo = oldep_ptr; | ||||
| 
 | ||||
|         if(rcode) { | ||||
|                 //printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
 | ||||
|                 return rcode; | ||||
|         } | ||||
| 
 | ||||
|         // to-do?
 | ||||
|         // Allocate new address according to device class
 | ||||
|         //bAddress = addrPool.AllocAddress(parent, false, port);
 | ||||
| 
 | ||||
|         uint16_t vid = udd->idVendor; | ||||
|         uint16_t pid = udd->idProduct; | ||||
|         uint8_t klass = udd->bDeviceClass; | ||||
|         uint8_t subklass = udd->bDeviceSubClass; | ||||
|         // Attempt to configure if VID/PID or device class matches with a driver
 | ||||
|         // Qualify with subclass too.
 | ||||
|         //
 | ||||
|         // VID/PID & class tests default to false for drivers not yet ported
 | ||||
|         // subclass defaults to true, so you don't have to define it if you don't have to.
 | ||||
|         //
 | ||||
|         for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { | ||||
|                 if(!devConfig[devConfigIndex]) continue; // no driver
 | ||||
|                 if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
 | ||||
|                 if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) { | ||||
|                         rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); | ||||
|                         if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED) | ||||
|                                 break; | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         if(devConfigIndex < USB_NUMDEVICES) { | ||||
|                 return rcode; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         // blindly attempt to configure
 | ||||
|         for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { | ||||
|                 if(!devConfig[devConfigIndex]) continue; | ||||
|                 if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
 | ||||
|                 if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
 | ||||
|                 rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); | ||||
| 
 | ||||
|                 //printf("ERROR ENUMERATING %2.2x\r\n", rcode);
 | ||||
|                 if(!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) { | ||||
|                         // in case of an error dev_index should be reset to 0
 | ||||
|                         //		in order to start from the very beginning the
 | ||||
|                         //		next time the program gets here
 | ||||
|                         //if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
 | ||||
|                         //        devConfigIndex = 0;
 | ||||
|                         return rcode; | ||||
|                 } | ||||
|         } | ||||
|         // if we get here that means that the device class is not supported by any of registered classes
 | ||||
|         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]) continue; | ||||
|                 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)); | ||||
| } | ||||
| //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)); | ||||
| } | ||||
| 
 | ||||
| /* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
 | ||||
|  total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */ | ||||
| uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) { | ||||
|         const uint8_t bufSize = 64; | ||||
|         uint8_t buf[bufSize]; | ||||
|         USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf); | ||||
| 
 | ||||
|         uint8_t ret = getConfDescr(addr, ep, 9, conf, buf); | ||||
| 
 | ||||
|         if(ret) | ||||
|                 return ret; | ||||
| 
 | ||||
|         uint16_t total = ucd->wTotalLength; | ||||
| 
 | ||||
|         //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)); | ||||
| } | ||||
| //set address
 | ||||
| 
 | ||||
| uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) { | ||||
|         uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL); | ||||
|         //DELAY(2); //per USB 2.0 sect.9.2.6.3
 | ||||
|         DELAY(300); // Older spec says you should wait at least 200ms
 | ||||
|         return rcode; | ||||
|         //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)); | ||||
| } | ||||
| 
 | ||||
| #endif // defined(USB_METHODS_INLINE)
 | ||||
| @ -0,0 +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 | ||||
|  */ | ||||
| /* USB functions */ | ||||
| #ifndef _usb_h_ | ||||
| #define _usb_h_ | ||||
| 
 | ||||
| // WARNING: Do not change the order of includes, or stuff will break!
 | ||||
| #include <inttypes.h> | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| // None of these should ever be included by a driver, or a user's sketch.
 | ||||
| #include "settings.h" | ||||
| #include "printhex.h" | ||||
| #include "message.h" | ||||
| #include "max3421e.h" | ||||
| #include "address.h" | ||||
| #include "avrpins.h" | ||||
| #include "usb_ch9.h" | ||||
| #include "usbhost.h" | ||||
| #include "UsbCore.h" | ||||
| #include "parsetools.h" | ||||
| #include "confdescparser.h" | ||||
| 
 | ||||
| #endif //_usb_h_
 | ||||
| @ -0,0 +1,296 @@ | ||||
| /* 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(_usb_h_) || defined(USBCORE_H) | ||||
| #error "Never include UsbCore.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define	USBCORE_H | ||||
| 
 | ||||
| // Not used anymore? If anyone uses this, please let us know so that this may be
 | ||||
| // moved to the proper place, settings.h.
 | ||||
| //#define USB_METHODS_INLINE
 | ||||
| 
 | ||||
| /* shield pins. First parameter - SS pin, second parameter - INT pin */ | ||||
| #ifdef BOARD_BLACK_WIDDOW | ||||
| typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
 | ||||
| #elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) | ||||
| #if EXT_RAM | ||||
| typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
 | ||||
| #else | ||||
| typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
 | ||||
| #endif | ||||
| #elif defined(BOARD_MEGA_ADK) | ||||
| typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
 | ||||
| #elif defined(ARDUINO_AVR_BALANDUINO) | ||||
| typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
 | ||||
| #else | ||||
| typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.) or Teensy 2.0 and 3.0
 | ||||
| #endif | ||||
| 
 | ||||
| /* Common setup data constant combinations  */ | ||||
| #define bmREQ_GET_DESCR     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //get descriptor request type
 | ||||
| #define bmREQ_SET           USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //set request type for all but 'set feature' and 'set interface'
 | ||||
| #define bmREQ_CL_GET_INTF   USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE     //get interface request type
 | ||||
| 
 | ||||
| // D7		data transfer direction (0 - host-to-device, 1 - device-to-host)
 | ||||
| // D6-5		Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
 | ||||
| // D4-0		Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
 | ||||
| 
 | ||||
| // USB Device Classes
 | ||||
| #define USB_CLASS_USE_CLASS_INFO	0x00	// Use Class Info in the Interface Descriptors
 | ||||
| #define USB_CLASS_AUDIO			0x01	// Audio
 | ||||
| #define USB_CLASS_COM_AND_CDC_CTRL	0x02	// Communications and CDC Control
 | ||||
| #define USB_CLASS_HID			0x03	// HID
 | ||||
| #define USB_CLASS_PHYSICAL		0x05	// Physical
 | ||||
| #define USB_CLASS_IMAGE			0x06	// Image
 | ||||
| #define USB_CLASS_PRINTER		0x07	// Printer
 | ||||
| #define USB_CLASS_MASS_STORAGE		0x08	// Mass Storage
 | ||||
| #define USB_CLASS_HUB			0x09	// Hub
 | ||||
| #define USB_CLASS_CDC_DATA		0x0a	// CDC-Data
 | ||||
| #define USB_CLASS_SMART_CARD		0x0b	// Smart-Card
 | ||||
| #define USB_CLASS_CONTENT_SECURITY	0x0d	// Content Security
 | ||||
| #define USB_CLASS_VIDEO			0x0e	// Video
 | ||||
| #define USB_CLASS_PERSONAL_HEALTH	0x0f	// Personal Healthcare
 | ||||
| #define USB_CLASS_DIAGNOSTIC_DEVICE	0xdc	// Diagnostic Device
 | ||||
| #define USB_CLASS_WIRELESS_CTRL		0xe0	// Wireless Controller
 | ||||
| #define USB_CLASS_MISC			0xef	// Miscellaneous
 | ||||
| #define USB_CLASS_APP_SPECIFIC		0xfe	// Application Specific
 | ||||
| #define USB_CLASS_VENDOR_SPECIFIC	0xff	// Vendor Specific
 | ||||
| 
 | ||||
| // Additional Error Codes
 | ||||
| #define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED	0xD1 | ||||
| #define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE	0xD2 | ||||
| #define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS	0xD3 | ||||
| #define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL		0xD4 | ||||
| #define USB_ERROR_HUB_ADDRESS_OVERFLOW			0xD5 | ||||
| #define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL		0xD6 | ||||
| #define USB_ERROR_EPINFO_IS_NULL			0xD7 | ||||
| #define USB_ERROR_INVALID_ARGUMENT			0xD8 | ||||
| #define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE		0xD9 | ||||
| #define USB_ERROR_INVALID_MAX_PKT_SIZE			0xDA | ||||
| #define USB_ERROR_EP_NOT_FOUND_IN_TBL			0xDB | ||||
| #define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET      0xE0 | ||||
| #define USB_ERROR_FailGetDevDescr                       0xE1 | ||||
| #define USB_ERROR_FailSetDevTblEntry                    0xE2 | ||||
| #define USB_ERROR_FailGetConfDescr                      0xE3 | ||||
| #define USB_ERROR_TRANSFER_TIMEOUT			0xFF | ||||
| 
 | ||||
| #define USB_XFER_TIMEOUT        10000 //30000    // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
 | ||||
| //#define USB_NAK_LIMIT		32000   //NAK limit for a transfer. 0 means NAKs are not counted
 | ||||
| #define USB_RETRY_LIMIT		3       // 3 retry limit for a transfer
 | ||||
| #define USB_SETTLE_DELAY	200     //settle delay in milliseconds
 | ||||
| 
 | ||||
| #define USB_NUMDEVICES		16	//number of USB devices
 | ||||
| //#define HUB_MAX_HUBS		7	// maximum number of hubs that can be attached to the host controller
 | ||||
| #define HUB_PORT_RESET_DELAY	20	// hub port reset delay 10 ms recomended, can be up to 20 ms
 | ||||
| 
 | ||||
| /* USB state machine states */ | ||||
| #define USB_STATE_MASK                                      0xf0 | ||||
| 
 | ||||
| #define USB_STATE_DETACHED                                  0x10 | ||||
| #define USB_DETACHED_SUBSTATE_INITIALIZE                    0x11 | ||||
| #define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE               0x12 | ||||
| #define USB_DETACHED_SUBSTATE_ILLEGAL                       0x13 | ||||
| #define USB_ATTACHED_SUBSTATE_SETTLE                        0x20 | ||||
| #define USB_ATTACHED_SUBSTATE_RESET_DEVICE                  0x30 | ||||
| #define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE           0x40 | ||||
| #define USB_ATTACHED_SUBSTATE_WAIT_SOF                      0x50 | ||||
| #define USB_ATTACHED_SUBSTATE_WAIT_RESET                    0x51 | ||||
| #define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE    0x60 | ||||
| #define USB_STATE_ADDRESSING                                0x70 | ||||
| #define USB_STATE_CONFIGURING                               0x80 | ||||
| #define USB_STATE_RUNNING                                   0x90 | ||||
| #define USB_STATE_ERROR                                     0xa0 | ||||
| 
 | ||||
| class USBDeviceConfig { | ||||
| public: | ||||
| 
 | ||||
|         virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         virtual uint8_t Release() { | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         virtual uint8_t Poll() { | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         virtual uint8_t GetAddress() { | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         virtual void ResetHubPort(uint8_t port) { | ||||
|                 return; | ||||
|         } // Note used for hubs only!
 | ||||
| 
 | ||||
|         virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { | ||||
|                 return false; | ||||
|         } | ||||
| 
 | ||||
|         virtual boolean DEVCLASSOK(uint8_t klass) { | ||||
|                 return false; | ||||
|         } | ||||
| 
 | ||||
|         virtual boolean DEVSUBCLASSOK(uint8_t subklass) { | ||||
|                 return true; | ||||
|         } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| /* USB Setup Packet Structure   */ | ||||
| typedef struct { | ||||
| 
 | ||||
|         union { // offset   description
 | ||||
|                 uint8_t bmRequestType; //   0      Bit-map of request type
 | ||||
| 
 | ||||
|                 struct { | ||||
|                         uint8_t recipient : 5; //          Recipient of the request
 | ||||
|                         uint8_t type : 2; //          Type of request
 | ||||
|                         uint8_t direction : 1; //          Direction of data X-fer
 | ||||
|                 } __attribute__((packed)); | ||||
|         } ReqType_u; | ||||
|         uint8_t bRequest; //   1      Request
 | ||||
| 
 | ||||
|         union { | ||||
|                 uint16_t wValue; //   2      Depends on bRequest
 | ||||
| 
 | ||||
|                 struct { | ||||
|                         uint8_t wValueLo; | ||||
|                         uint8_t wValueHi; | ||||
|                 } __attribute__((packed)); | ||||
|         } wVal_u; | ||||
|         uint16_t wIndex; //   4      Depends on bRequest
 | ||||
|         uint16_t wLength; //   6      Depends on bRequest
 | ||||
| } __attribute__((packed)) SETUP_PKT, *PSETUP_PKT; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Base class for incoming data parser
 | ||||
| 
 | ||||
| class USBReadParser { | ||||
| public: | ||||
|         virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; | ||||
| }; | ||||
| 
 | ||||
| class USB : public MAX3421E { | ||||
|         AddressPoolImpl<USB_NUMDEVICES> addrPool; | ||||
|         USBDeviceConfig* devConfig[USB_NUMDEVICES]; | ||||
|         uint8_t bmHubPre; | ||||
| 
 | ||||
| public: | ||||
|         USB(void); | ||||
| 
 | ||||
|         void SetHubPreMask() { | ||||
|                 bmHubPre |= bmHUBPRE; | ||||
|         }; | ||||
| 
 | ||||
|         void ResetHubPreMask() { | ||||
|                 bmHubPre &= (~bmHUBPRE); | ||||
|         }; | ||||
| 
 | ||||
|         AddressPool& GetAddressPool() { | ||||
|                 return (AddressPool&)addrPool; | ||||
|         }; | ||||
| 
 | ||||
|         uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) { | ||||
|                 for(uint8_t i = 0; i < USB_NUMDEVICES; i++) { | ||||
|                         if(!devConfig[i]) { | ||||
|                                 devConfig[i] = pdev; | ||||
|                                 return 0; | ||||
|                         } | ||||
|                 } | ||||
|                 return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS; | ||||
|         }; | ||||
| 
 | ||||
|         void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { | ||||
|                 addrPool.ForEachUsbDevice(pfunc); | ||||
|         }; | ||||
|         uint8_t getUsbTaskState(void); | ||||
|         void setUsbTaskState(uint8_t state); | ||||
| 
 | ||||
|         EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep); | ||||
|         uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr); | ||||
| 
 | ||||
|         /* Control requests */ | ||||
|         uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr); | ||||
|         uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr); | ||||
| 
 | ||||
|         uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p); | ||||
| 
 | ||||
|         uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr); | ||||
|         uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr); | ||||
|         uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value); | ||||
|         /**/ | ||||
|         uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction); | ||||
|         uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit); | ||||
|         uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data); | ||||
|         uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data); | ||||
|         uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit); | ||||
| 
 | ||||
|         void Task(void); | ||||
| 
 | ||||
|         uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed); | ||||
|         uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed); | ||||
|         uint8_t ReleaseDevice(uint8_t addr); | ||||
| 
 | ||||
|         uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, | ||||
|                 uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p); | ||||
| 
 | ||||
| private: | ||||
|         void init(); | ||||
|         uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit); | ||||
|         uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data); | ||||
|         uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data); | ||||
|         uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed); | ||||
| }; | ||||
| 
 | ||||
| #if 0 //defined(USB_METHODS_INLINE)
 | ||||
| //get device descriptor
 | ||||
| 
 | ||||
| inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) { | ||||
|         return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr)); | ||||
| } | ||||
| //get configuration descriptor
 | ||||
| 
 | ||||
| inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) { | ||||
|         return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr)); | ||||
| } | ||||
| //get string descriptor
 | ||||
| 
 | ||||
| inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) { | ||||
|         return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr)); | ||||
| } | ||||
| //set address
 | ||||
| 
 | ||||
| inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) { | ||||
|         return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL)); | ||||
| } | ||||
| //set configuration
 | ||||
| 
 | ||||
| inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) { | ||||
|         return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL)); | ||||
| } | ||||
| 
 | ||||
| #endif // defined(USB_METHODS_INLINE)
 | ||||
| 
 | ||||
| #endif	/* USBCORE_H */ | ||||
| @ -0,0 +1,147 @@ | ||||
| /********************************************************************************************
 | ||||
|  * This program/sketch is used to run a USB Thumb Drive.                                    * | ||||
|  *                                                                                          * | ||||
|  * NOTE - This Arduino Sketch has been modified to initialize a MAX3421E USB Host Interface * | ||||
|  * chip, write 3 test files, print out the directory of the thumb drive and print out the   * | ||||
|  * contents of a short .txt file.                                                           * | ||||
|  *                                                                                          * | ||||
|  * The code is leveraged from the following:                                                * | ||||
|  *                                                                                          * | ||||
|  * 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                                                   * | ||||
|  *                                                                                          * | ||||
|  * SPECIAL NOTE - In order to work with a modified Eisny or RAMBo, the SPI chip select pin  * | ||||
|  * (CS) (D10) has been remapped from PORTB Pin-4 to PORTB Pin-0.  This has been done in the * | ||||
|  * __AVR_ATmega2560__ section of the avrpins.h file.                                        * | ||||
|  *                                                                                          * | ||||
|  ********************************************************************************************/ | ||||
| 
 | ||||
| #include <SPI.h> | ||||
| #include "masstorage.h" | ||||
| 
 | ||||
| #define MAX_USB_RST 7 | ||||
| 
 | ||||
| // USB host objects.v
 | ||||
| USB usb; | ||||
| BulkOnly bulk(&usb); | ||||
| 
 | ||||
| #define error(msg) {Serial.print("Error: "); Serial.println(msg);} | ||||
| 
 | ||||
| #define TIMEOUT_MILLIS 4000 | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| bool initUSB(USB* usb) { | ||||
|  uint8_t last_state = 0; | ||||
|  uint8_t current_state = 0; | ||||
|   uint32_t m = millis(); | ||||
|    | ||||
|   for (uint8_t i = 0; usb->Init(1000) == -1; i++) | ||||
|   { | ||||
|     //if (USB_FAT_DBG_MODE) {
 | ||||
|       Serial.println(F("No USB HOST Shield?")); | ||||
|     //}
 | ||||
|     if (i > 10) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| #if USB_FAT_DBG_MODE | ||||
|   Serial.print(F("Host initialized, ms: ")); | ||||
|   Serial.println(millis() - m); | ||||
| #endif  // USB_FAT_DBG_MODE
 | ||||
| 
 | ||||
|   usb->vbusPower(vbus_on); | ||||
| #if USB_FAT_DBG_MODE   | ||||
|   Serial.print(F("USB powered, ms: ")); | ||||
|   Serial.println(millis() - m); | ||||
| #endif  // USB_FAT_DBG_MODE
 | ||||
|    | ||||
|   while ((millis() - m) < TIMEOUT_MILLIS) { | ||||
|     usb->Task();   | ||||
|     current_state = usb->getUsbTaskState(); | ||||
| #if USB_FAT_DBG_MODE     | ||||
|     if (last_state != current_state) { | ||||
|       Serial.print(F("USB state: ")); | ||||
|       Serial.print(current_state, HEX); | ||||
|       Serial.print(F(", ms: ")); | ||||
|       Serial.println(millis() - m); | ||||
|     } | ||||
|     last_state = current_state; | ||||
| #endif  // USB_FAT_DBG_MODE    
 | ||||
|     if(current_state == USB_STATE_RUNNING) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| void setup() | ||||
| { | ||||
|   pinMode(MAX_USB_RST, OUTPUT); | ||||
|   digitalWrite(MAX_USB_RST, HIGH); | ||||
|    | ||||
|   Serial.begin(9600); | ||||
| 
 | ||||
|   Serial.print("USB THUMB DRIVE FILE TEST\n\n"); | ||||
| 
 | ||||
|   Serial.print("Initializing The USB Bus\n"); | ||||
| 
 | ||||
|   // Initialize the USB bus.
 | ||||
|    | ||||
|   if (!initUSB(&usb)) | ||||
|   { | ||||
|     error("initUSB failed");    | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Serial.print("USB Initialized\n"); | ||||
|   } | ||||
| 
 | ||||
|   if(bulk.LUNIsGood(0)) { | ||||
|     Serial.print("LUN Capacity: "); | ||||
|     Serial.println(bulk.GetCapacity(0)); | ||||
| 
 | ||||
|     const uint32_t sectorSize = bulk.GetSectorSize(0); | ||||
|      | ||||
|     Serial.print("Sector Size: "); | ||||
|     Serial.println(sectorSize); | ||||
| 
 | ||||
|     uint8_t buf[512]; | ||||
|      | ||||
|      | ||||
|     const uint8_t  lun = 0; | ||||
|     const uint32_t addr = 0; | ||||
|     if(bulk.Read(lun, addr, sectorSize, 1, buf) == 0) { | ||||
|       Serial.print("Read a block: \n"); | ||||
|       Serial.println((char*)buf); | ||||
|     } else { | ||||
|       Serial.print("Failed to a read block\n"); | ||||
|     } | ||||
| 
 | ||||
|     const char *message = PSTR("This is a test of writing raw data!"); | ||||
|     strcpy_P(buf, message); | ||||
| 
 | ||||
|     if(bulk.Write(lun, addr, sectorSize, 1, buf) == 0) { | ||||
|       Serial.print("Wrote a block\n"); | ||||
|     } else { | ||||
|       Serial.print("Failed to write a block\n"); | ||||
|     } | ||||
|   } else { | ||||
|     Serial.print("LUN zero is not good\n"); | ||||
|   } | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
| void loop () {} | ||||
| @ -0,0 +1,282 @@ | ||||
| /* 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(_usb_h_) || defined(__ADDRESS_H__) | ||||
| #error "Never include address.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define __ADDRESS_H__ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* 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		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
 | ||||
| 
 | ||||
|         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
 | ||||
|                 } __attribute__((packed)); | ||||
|         }; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| //	  7   6   5   4   3   2   1   0
 | ||||
| //  ---------------------------------
 | ||||
| //  |   | H | P | P | P | A | A | A |
 | ||||
| //  ---------------------------------
 | ||||
| //
 | ||||
| // H - if 1 the address is a hub address
 | ||||
| // 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 zero
 | ||||
|                 } __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
 | ||||
|         UsbDeviceAddress 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 { | ||||
| 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; | ||||
| }; | ||||
| 
 | ||||
| typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); | ||||
| 
 | ||||
| #define ADDR_ERROR_INVALID_INDEX		0xFF | ||||
| #define ADDR_ERROR_INVALID_ADDRESS		0xFF | ||||
| 
 | ||||
| template <const uint8_t MAX_DEVICES_ALLOWED> | ||||
| 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
 | ||||
| 
 | ||||
|         UsbDevice thePool[MAX_DEVICES_ALLOWED]; | ||||
| 
 | ||||
|         // Initializes address pool entry
 | ||||
| 
 | ||||
|         void InitEntry(uint8_t index) { | ||||
|                 thePool[index].address.devAddress = 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; i++) { | ||||
|                         if(thePool[i].address.devAddress == address) | ||||
|                                 return i; | ||||
|                 } | ||||
|                 return 0; | ||||
|         }; | ||||
| 
 | ||||
|         // Returns thePool child index for a given parent
 | ||||
| 
 | ||||
|         uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) { | ||||
|                 for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) { | ||||
|                         if(thePool[i].address.bmParent == addr.bmAddress) | ||||
|                                 return i; | ||||
|                 } | ||||
|                 return 0; | ||||
|         }; | ||||
| 
 | ||||
|         // Frees address entry specified by index parameter
 | ||||
| 
 | ||||
|         void FreeAddressByIndex(uint8_t index) { | ||||
|                 // Zero field is reserved and should not be affected
 | ||||
|                 if(index == 0) | ||||
|                         return; | ||||
| 
 | ||||
|                 UsbDeviceAddress uda = thePool[index].address; | ||||
|                 // If a hub was switched off all port addresses should be freed
 | ||||
|                 if(uda.bmHub == 1) { | ||||
|                         for(uint8_t i = 1; (i = FindChildIndex(uda, i));) | ||||
|                                 FreeAddressByIndex(i); | ||||
| 
 | ||||
|                         // If the hub had the last allocated address, hubCounter should be decremented
 | ||||
|                         if(hubCounter == uda.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; | ||||
|         }; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|         AddressPoolImpl() : hubCounter(0) { | ||||
|                 // Zero address is reserved
 | ||||
|                 InitEntry(0); | ||||
| 
 | ||||
|                 thePool[0].address.devAddress = 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; | ||||
| 
 | ||||
|                 InitAllAddresses(); | ||||
|         }; | ||||
| 
 | ||||
|         // Returns a pointer to a specified address entry
 | ||||
| 
 | ||||
|         virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) { | ||||
|                 if(!addr) | ||||
|                         return thePool; | ||||
| 
 | ||||
|                 uint8_t index = FindAddressIndex(addr); | ||||
| 
 | ||||
|                 return (!index) ? NULL : thePool + index; | ||||
|         }; | ||||
| 
 | ||||
|         // Performs an operation specified by pfunc for each addressed device
 | ||||
| 
 | ||||
|         void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { | ||||
|                 if(!pfunc) | ||||
|                         return; | ||||
| 
 | ||||
|                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) | ||||
|                         if(thePool[i].address.devAddress) | ||||
|                                 pfunc(thePool + i); | ||||
|         }; | ||||
| 
 | ||||
|         // Allocates new address
 | ||||
| 
 | ||||
|         virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) { | ||||
|                 /* if (parent != 0 && port == 0)
 | ||||
|                         USB_HOST_SERIAL.println("PRT:0"); */ | ||||
|                 UsbDeviceAddress _parent; | ||||
|                 _parent.devAddress = parent; | ||||
|                 if(_parent.bmReserved || port > 7) | ||||
|                         //if(parent > 127 || port > 7)
 | ||||
|                         return 0; | ||||
| 
 | ||||
|                 if(is_hub && hubCounter == 7) | ||||
|                         return 0; | ||||
| 
 | ||||
|                 // finds first empty address entry starting from one
 | ||||
|                 uint8_t index = FindAddressIndex(0); | ||||
| 
 | ||||
|                 if(!index) // if empty entry is not found
 | ||||
|                         return 0; | ||||
| 
 | ||||
|                 if(_parent.devAddress == 0) { | ||||
|                         if(is_hub) { | ||||
|                                 thePool[index].address.devAddress = 0x41; | ||||
|                                 hubCounter++; | ||||
|                         } else | ||||
|                                 thePool[index].address.devAddress = 1; | ||||
| 
 | ||||
|                         return thePool[index].address.devAddress; | ||||
|                 } | ||||
| 
 | ||||
|                 UsbDeviceAddress addr; | ||||
|                 addr.devAddress = 0; // Ensure all bits are zero
 | ||||
|                 addr.bmParent = _parent.bmAddress; | ||||
|                 if(is_hub) { | ||||
|                         addr.bmHub = 1; | ||||
|                         addr.bmAddress = ++hubCounter; | ||||
|                 } else { | ||||
|                         addr.bmHub = 0; | ||||
|                         addr.bmAddress = port; | ||||
|                 } | ||||
|                 thePool[index].address = addr; | ||||
|                 /*
 | ||||
|                                 USB_HOST_SERIAL.print("Addr:"); | ||||
|                                 USB_HOST_SERIAL.print(addr.bmHub, HEX); | ||||
|                                 USB_HOST_SERIAL.print("."); | ||||
|                                 USB_HOST_SERIAL.print(addr.bmParent, HEX); | ||||
|                                 USB_HOST_SERIAL.print("."); | ||||
|                                 USB_HOST_SERIAL.println(addr.bmAddress, HEX); | ||||
|                  */ | ||||
|                 return thePool[index].address.devAddress; | ||||
|         }; | ||||
| 
 | ||||
|         // 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; i<MAX_DEVICES_ALLOWED; i++)
 | ||||
|         //		if (thePool[i].address != 0);
 | ||||
|         //			counter ++;
 | ||||
| 
 | ||||
|         //	return counter;
 | ||||
|         //};
 | ||||
| }; | ||||
| 
 | ||||
| #endif // __ADDRESS_H__
 | ||||
| @ -0,0 +1,1024 @@ | ||||
| /* 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 | ||||
|  */ | ||||
| 
 | ||||
| /* derived from Konstantin Chizhov's AVR port templates */ | ||||
| 
 | ||||
| #if !defined(_usb_h_) || defined(_avrpins_h_) | ||||
| #error "Never include avrpins.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define _avrpins_h_ | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
| 
 | ||||
| // pointers are 16 bits on AVR
 | ||||
| #define pgm_read_pointer(p) pgm_read_word(p) | ||||
| 
 | ||||
| // Support for these boards needs to be manually activated in settings.h or in a makefile
 | ||||
| #if !defined(BOARD_MEGA_ADK) && defined(__AVR_ATmega2560__) && (USE_UHS_MEGA_ADK || defined(ARDUINO_AVR_ADK)) | ||||
| #define BOARD_MEGA_ADK | ||||
| #elif !defined(BOARD_BLACK_WIDDOW) && USE_UHS_BLACK_WIDDOW | ||||
| #define BOARD_BLACK_WIDDOW | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PORTA | ||||
| #define USE_PORTA | ||||
| #endif | ||||
| #ifdef PORTB | ||||
| #define USE_PORTB | ||||
| #endif | ||||
| #ifdef PORTC | ||||
| #define USE_PORTC | ||||
| #endif | ||||
| #ifdef PORTD | ||||
| #define USE_PORTD | ||||
| #endif | ||||
| #ifdef PORTE | ||||
| #define USE_PORTE | ||||
| #endif | ||||
| #ifdef PORTF | ||||
| #define USE_PORTF | ||||
| #endif | ||||
| #ifdef PORTG | ||||
| #define USE_PORTG | ||||
| #endif | ||||
| #ifdef PORTH | ||||
| #define USE_PORTH | ||||
| #endif | ||||
| #ifdef PORTJ | ||||
| #define USE_PORTJ | ||||
| #endif | ||||
| #ifdef PORTK | ||||
| #define USE_PORTK | ||||
| #endif | ||||
| #ifdef PORTL | ||||
| #define USE_PORTL | ||||
| #endif | ||||
| #ifdef PORTQ | ||||
| #define USE_PORTQ | ||||
| #endif | ||||
| #ifdef PORTR | ||||
| #define USE_PORTR | ||||
| #endif | ||||
| 
 | ||||
| #ifdef TCCR0A | ||||
| #define USE_TCCR0A | ||||
| #endif | ||||
| #ifdef TCCR1A | ||||
| #define USE_TCCR1A | ||||
| #endif | ||||
| #ifdef TCCR2A | ||||
| #define USE_TCCR2A | ||||
| #endif | ||||
| 
 | ||||
| //Port definitions for AtTiny, AtMega families.
 | ||||
| 
 | ||||
| #define MAKE_PORT(portName, ddrName, pinName, className, ID) \ | ||||
|     class className{\ | ||||
|     public:\ | ||||
|       typedef uint8_t DataT;\ | ||||
|     public:\ | ||||
|       static void Write(DataT value){portName = value;}\ | ||||
|       static void ClearAndSet(DataT clearMask, DataT value){portName = (portName & ~clearMask) | value;}\ | ||||
|       static DataT Read(){return portName;}\ | ||||
|       static void DirWrite(DataT value){ddrName = value;}\ | ||||
|       static DataT DirRead(){return ddrName;}\ | ||||
|       static void Set(DataT value){portName |= value;}\ | ||||
|       static void Clear(DataT value){portName &= ~value;}\ | ||||
|       static void Toggle(DataT value){portName ^= value;}\ | ||||
|       static void DirSet(DataT value){ddrName |= value;}\ | ||||
|       static void DirClear(DataT value){ddrName &= ~value;}\ | ||||
|       static void DirToggle(DataT value){ddrName ^= value;}\ | ||||
|       static DataT PinRead(){return pinName;}\ | ||||
|       enum{Id = ID};\ | ||||
|       enum{Width=sizeof(DataT)*8};\ | ||||
|     }; | ||||
| 
 | ||||
| // TCCR registers to set/clear Arduino PWM
 | ||||
| #define MAKE_TCCR(TccrName, className) \ | ||||
|     class className{\ | ||||
|     public:\ | ||||
|       typedef uint8_t DataT;\ | ||||
|     public:\ | ||||
|       static void Write(DataT value){TccrName = value;}\ | ||||
|       static void ClearAndSet(DataT clearMask, DataT value){TccrName = (TccrName & ~clearMask) | value;}\ | ||||
|       static DataT Read(){return TccrName;}\ | ||||
|       static void Set(DataT value){TccrName |= value;}\ | ||||
|       static void Clear(DataT value){TccrName &= ~value;}\ | ||||
|       static void Toggle(DataT value){TccrName ^= value;}\ | ||||
|       enum{Width=sizeof(DataT)*8};\ | ||||
|     }; | ||||
| 
 | ||||
| #ifdef USE_PORTA | ||||
| 
 | ||||
| MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A') | ||||
| #endif | ||||
| #ifdef USE_PORTB | ||||
| MAKE_PORT(PORTB, DDRB, PINB, Portb, 'B') | ||||
| #endif | ||||
| #ifdef USE_PORTC | ||||
| MAKE_PORT(PORTC, DDRC, PINC, Portc, 'C') | ||||
| #endif | ||||
| #ifdef USE_PORTD | ||||
| MAKE_PORT(PORTD, DDRD, PIND, Portd, 'D') | ||||
| #endif | ||||
| #ifdef USE_PORTE | ||||
| MAKE_PORT(PORTE, DDRE, PINE, Porte, 'E') | ||||
| #endif | ||||
| #ifdef USE_PORTF | ||||
| MAKE_PORT(PORTF, DDRF, PINF, Portf, 'F') | ||||
| #endif | ||||
| #ifdef USE_PORTG | ||||
| MAKE_PORT(PORTG, DDRG, PING, Portg, 'G') | ||||
| #endif | ||||
| #ifdef USE_PORTH | ||||
| MAKE_PORT(PORTH, DDRH, PINH, Porth, 'H') | ||||
| #endif | ||||
| #ifdef USE_PORTJ | ||||
| MAKE_PORT(PORTJ, DDRJ, PINJ, Portj, 'J') | ||||
| #endif | ||||
| #ifdef USE_PORTK | ||||
| MAKE_PORT(PORTK, DDRK, PINK, Portk, 'K') | ||||
| #endif | ||||
| #ifdef USE_PORTL | ||||
| MAKE_PORT(PORTL, DDRL, PINL, Portl, 'L') | ||||
| #endif | ||||
| #ifdef USE_PORTQ | ||||
| MAKE_PORT(PORTQ, DDRQ, PINQ, Portq, 'Q') | ||||
| #endif | ||||
| #ifdef USE_PORTR | ||||
| MAKE_PORT(PORTR, DDRR, PINR, Portr, 'R') | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_TCCR0A | ||||
| MAKE_TCCR(TCCR0A, Tccr0a) | ||||
| #endif | ||||
| #ifdef USE_TCCR1A | ||||
| MAKE_TCCR(TCCR1A, Tccr1a) | ||||
| #endif | ||||
| #ifdef USE_TCCR2A | ||||
| MAKE_TCCR(TCCR2A, Tccr2a) | ||||
| #endif | ||||
| 
 | ||||
| // this class represents one pin in a IO port.
 | ||||
| // It is fully static.
 | ||||
| template<typename PORT, uint8_t PIN> | ||||
| class TPin { | ||||
|         //    BOOST_STATIC_ASSERT(PIN < PORT::Width);
 | ||||
| public: | ||||
|         typedef PORT Port; | ||||
| 
 | ||||
|         enum { | ||||
|                 Number = PIN | ||||
|         }; | ||||
| 
 | ||||
|         static void Set() { | ||||
|                 PORT::Set(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static void Set(uint8_t val) { | ||||
|                 if(val) | ||||
|                         Set(); | ||||
|                 else Clear(); | ||||
|         } | ||||
| 
 | ||||
|         static void SetDir(uint8_t val) { | ||||
|                 if(val) | ||||
|                         SetDirWrite(); | ||||
|                 else SetDirRead(); | ||||
|         } | ||||
| 
 | ||||
|         static void Clear() { | ||||
|                 PORT::Clear(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static void Toggle() { | ||||
|                 PORT::Toggle(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static void SetDirRead() { | ||||
|                 PORT::DirClear(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static void SetDirWrite() { | ||||
|                 PORT::DirSet(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static uint8_t IsSet() { | ||||
|                 return PORT::PinRead() & (uint8_t)(1 << PIN); | ||||
|         } | ||||
| 
 | ||||
|         static void WaiteForSet() { | ||||
|                 while(IsSet() == 0) { | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         static void WaiteForClear() { | ||||
|                 while(IsSet()) { | ||||
|                 } | ||||
|         } | ||||
| }; //class TPin...
 | ||||
| 
 | ||||
| // this class represents one bit in TCCR port.
 | ||||
| // used to set/clear TCCRx bits
 | ||||
| // It is fully static.
 | ||||
| 
 | ||||
| template<typename TCCR, uint8_t COM> | ||||
| class TCom { | ||||
|         //    BOOST_STATIC_ASSERT(PIN < PORT::Width);
 | ||||
| public: | ||||
|         typedef TCCR Tccr; | ||||
| 
 | ||||
|         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<Porta, 0 > Pa0; | ||||
| typedef TPin<Porta, 1 > Pa1; | ||||
| typedef TPin<Porta, 2 > Pa2; | ||||
| typedef TPin<Porta, 3 > Pa3; | ||||
| typedef TPin<Porta, 4 > Pa4; | ||||
| typedef TPin<Porta, 5 > Pa5; | ||||
| typedef TPin<Porta, 6 > Pa6; | ||||
| typedef TPin<Porta, 7 > Pa7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTB | ||||
| typedef TPin<Portb, 0 > Pb0; | ||||
| typedef TPin<Portb, 1 > Pb1; | ||||
| typedef TPin<Portb, 2 > Pb2; | ||||
| typedef TPin<Portb, 3 > Pb3; | ||||
| typedef TPin<Portb, 4 > Pb4; | ||||
| typedef TPin<Portb, 5 > Pb5; | ||||
| typedef TPin<Portb, 6 > Pb6; | ||||
| typedef TPin<Portb, 7 > Pb7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTC | ||||
| typedef TPin<Portc, 0 > Pc0; | ||||
| typedef TPin<Portc, 1 > Pc1; | ||||
| typedef TPin<Portc, 2 > Pc2; | ||||
| typedef TPin<Portc, 3 > Pc3; | ||||
| typedef TPin<Portc, 4 > Pc4; | ||||
| typedef TPin<Portc, 5 > Pc5; | ||||
| typedef TPin<Portc, 6 > Pc6; | ||||
| typedef TPin<Portc, 7 > Pc7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTD | ||||
| typedef TPin<Portd, 0 > Pd0; | ||||
| typedef TPin<Portd, 1 > Pd1; | ||||
| typedef TPin<Portd, 2 > Pd2; | ||||
| typedef TPin<Portd, 3 > Pd3; | ||||
| typedef TPin<Portd, 4 > Pd4; | ||||
| typedef TPin<Portd, 5 > Pd5; | ||||
| typedef TPin<Portd, 6 > Pd6; | ||||
| typedef TPin<Portd, 7 > Pd7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTE | ||||
| typedef TPin<Porte, 0 > Pe0; | ||||
| typedef TPin<Porte, 1 > Pe1; | ||||
| typedef TPin<Porte, 2 > Pe2; | ||||
| typedef TPin<Porte, 3 > Pe3; | ||||
| typedef TPin<Porte, 4 > Pe4; | ||||
| typedef TPin<Porte, 5 > Pe5; | ||||
| typedef TPin<Porte, 6 > Pe6; | ||||
| typedef TPin<Porte, 7 > Pe7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTF | ||||
| typedef TPin<Portf, 0 > Pf0; | ||||
| typedef TPin<Portf, 1 > Pf1; | ||||
| typedef TPin<Portf, 2 > Pf2; | ||||
| typedef TPin<Portf, 3 > Pf3; | ||||
| typedef TPin<Portf, 4 > Pf4; | ||||
| typedef TPin<Portf, 5 > Pf5; | ||||
| typedef TPin<Portf, 6 > Pf6; | ||||
| typedef TPin<Portf, 7 > Pf7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTG | ||||
| typedef TPin<Portg, 0 > Pg0; | ||||
| typedef TPin<Portg, 1 > Pg1; | ||||
| typedef TPin<Portg, 2 > Pg2; | ||||
| typedef TPin<Portg, 3 > Pg3; | ||||
| typedef TPin<Portg, 4 > Pg4; | ||||
| typedef TPin<Portg, 5 > Pg5; | ||||
| typedef TPin<Portg, 6 > Pg6; | ||||
| typedef TPin<Portg, 7 > Pg7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTH | ||||
| typedef TPin<Porth, 0 > Ph0; | ||||
| typedef TPin<Porth, 1 > Ph1; | ||||
| typedef TPin<Porth, 2 > Ph2; | ||||
| typedef TPin<Porth, 3 > Ph3; | ||||
| typedef TPin<Porth, 4 > Ph4; | ||||
| typedef TPin<Porth, 5 > Ph5; | ||||
| typedef TPin<Porth, 6 > Ph6; | ||||
| typedef TPin<Porth, 7 > Ph7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTJ | ||||
| typedef TPin<Portj, 0 > Pj0; | ||||
| typedef TPin<Portj, 1 > Pj1; | ||||
| typedef TPin<Portj, 2 > Pj2; | ||||
| typedef TPin<Portj, 3 > Pj3; | ||||
| typedef TPin<Portj, 4 > Pj4; | ||||
| typedef TPin<Portj, 5 > Pj5; | ||||
| typedef TPin<Portj, 6 > Pj6; | ||||
| typedef TPin<Portj, 7 > Pj7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTK | ||||
| typedef TPin<Portk, 0 > Pk0; | ||||
| typedef TPin<Portk, 1 > Pk1; | ||||
| typedef TPin<Portk, 2 > Pk2; | ||||
| typedef TPin<Portk, 3 > Pk3; | ||||
| typedef TPin<Portk, 4 > Pk4; | ||||
| typedef TPin<Portk, 5 > Pk5; | ||||
| typedef TPin<Portk, 6 > Pk6; | ||||
| typedef TPin<Portk, 7 > Pk7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTL | ||||
| typedef TPin<Portl, 0 > Pl0; | ||||
| typedef TPin<Portl, 1 > Pl1; | ||||
| typedef TPin<Portl, 2 > Pl2; | ||||
| typedef TPin<Portl, 3 > Pl3; | ||||
| typedef TPin<Portl, 4 > Pl4; | ||||
| typedef TPin<Portl, 5 > Pl5; | ||||
| typedef TPin<Portl, 6 > Pl6; | ||||
| typedef TPin<Portl, 7 > Pl7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTQ | ||||
| typedef TPin<Portq, 0 > Pq0; | ||||
| typedef TPin<Portq, 1 > Pq1; | ||||
| typedef TPin<Portq, 2 > Pq2; | ||||
| typedef TPin<Portq, 3 > Pq3; | ||||
| typedef TPin<Portq, 4 > Pq4; | ||||
| typedef TPin<Portq, 5 > Pq5; | ||||
| typedef TPin<Portq, 6 > Pq6; | ||||
| typedef TPin<Portq, 7 > Pq7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_PORTR | ||||
| typedef TPin<Portr, 0 > Pr0; | ||||
| typedef TPin<Portr, 1 > Pr1; | ||||
| typedef TPin<Portr, 2 > Pr2; | ||||
| typedef TPin<Portr, 3 > Pr3; | ||||
| typedef TPin<Portr, 4 > Pr4; | ||||
| typedef TPin<Portr, 5 > Pr5; | ||||
| typedef TPin<Portr, 6 > Pr6; | ||||
| typedef TPin<Portr, 7 > Pr7; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_TCCR0A | ||||
| typedef TCom<Tccr0a, COM0A1> Tc0a; //P6
 | ||||
| typedef TCom<Tccr0a, COM0B1> Tc0b; //P5
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_TCCR1A | ||||
| typedef TCom<Tccr1a, COM1A1> Tc1a; //P9
 | ||||
| typedef TCom<Tccr1a, COM1B1> Tc1b; //P10
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_TCCR2A | ||||
| typedef TCom<Tccr2a, COM2A1> Tc2a; //P11
 | ||||
| typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
 | ||||
| #endif | ||||
| 
 | ||||
| template<typename Tp_pin, typename Tc_bit> | ||||
| 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 */ | ||||
| 
 | ||||
| //typedef Tp_Tc<Pd3, Tc2b> P3;  //Arduino pin 3
 | ||||
| //typedef Tp_Tc<Pd5, Tc0b> P5;  //Arduino pin 5
 | ||||
| //typedef Tp_Tc<Pd6, Tc0a> P6;  //Arduino pin 6
 | ||||
| //typedef Tp_Tc<Pb1, Tc1a> P9;  //Arduino pin 9
 | ||||
| //typedef Tp_Tc<Pb2, Tc1b> P10;  //Arduino pin 10
 | ||||
| //typedef Tp_Tc<Pb3, Tc2a> P11;  //Arduino pin 11
 | ||||
| 
 | ||||
| /* Arduino pin definitions  */ | ||||
| #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||
| // "Mega" Arduino pin numbers
 | ||||
| 
 | ||||
| #define P0  Pe0 | ||||
| #define P1  Pe1 | ||||
| #define P2  Pe4 | ||||
| #define P3  Pe5 | ||||
| #define P4  Pg5 | ||||
| #define P5  Pe3 | ||||
| #define P6  Ph3 | ||||
| #define P7  Ph4 | ||||
| 
 | ||||
| #define P8  Ph5 | ||||
| #define P9  Ph6 | ||||
| //#define P10  Pb4    //Pb4 - Regular Arduino
 | ||||
| #define P10  Pb0    //Pb0 - Einsy Board
 | ||||
| #define P11  Pb5 | ||||
| #define P12  Pb6 | ||||
| #define P13  Pb7 | ||||
| 
 | ||||
| #define P14  Pj1 | ||||
| #define P15  Pj0 | ||||
| #define P16  Ph1 | ||||
| #define P17  Ph0 | ||||
| #define P18  Pd3 | ||||
| #define P19  Pd2 | ||||
| #define P20  Pd1 | ||||
| #define P21  Pd0 | ||||
| 
 | ||||
| #define P22 Pa0 | ||||
| #define P23 Pa1 | ||||
| #define P24 Pa2 | ||||
| #define P25 Pa3 | ||||
| #define P26 Pa4 | ||||
| #define P27 Pa5 | ||||
| #define P28 Pa6 | ||||
| #define P29 Pa7 | ||||
| #define P30 Pc7 | ||||
| #define P31 Pc6 | ||||
| #define P32 Pc5 | ||||
| #define P33 Pc4 | ||||
| #define P34 Pc3 | ||||
| #define P35 Pc2 | ||||
| #define P36 Pc1 | ||||
| #define P37 Pc0 | ||||
| 
 | ||||
| #define P38 Pd7 | ||||
| #define P39 Pg2 | ||||
| #define P40 Pg1 | ||||
| #define P41 Pg0 | ||||
| #define P42 Pl7 | ||||
| #define P43 Pl6 | ||||
| #define P44 Pl5 | ||||
| #define P45 Pl4 | ||||
| #define P46 Pl3 | ||||
| #define P47 Pl2 | ||||
| #define P48 Pl1 | ||||
| #define P49 Pl0 | ||||
| #define P50 Pb3 | ||||
| #define P51 Pb2 | ||||
| #define P52 Pb1 | ||||
| // #define P53 Pb0
 | ||||
| 
 | ||||
| #ifdef BOARD_MEGA_ADK // These pins are not broken out on the Arduino ADK
 | ||||
| #define P54 Pe6 // INT on Arduino ADK
 | ||||
| #define P55 Pj2 // MAX_RESET on Arduino ADK
 | ||||
| #endif | ||||
| 
 | ||||
| // "Mega" pin numbers
 | ||||
| 
 | ||||
| #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | ||||
| // "Classic" Arduino pin numbers
 | ||||
| 
 | ||||
| #define P0  Pd0 | ||||
| #define P1  Pd1 | ||||
| #define P2  Pd2 | ||||
| #define P3  Pd3 | ||||
| #define P4  Pd4 | ||||
| #define P5  Pd5 | ||||
| #define P6  Pd6 | ||||
| #define P7  Pd7 | ||||
| 
 | ||||
| #define P8  Pb0 | ||||
| #define P9  Pb1 | ||||
| #define P10  Pb2 | ||||
| #define P11  Pb3 | ||||
| #define P12  Pb4 | ||||
| #define P13  Pb5 | ||||
| 
 | ||||
| #define P14  Pc0 | ||||
| #define P15  Pc1 | ||||
| #define P16  Pc2 | ||||
| #define P17  Pc3 | ||||
| #define P18  Pc4 | ||||
| #define P19  Pc5 | ||||
| 
 | ||||
| // "Classic" Arduino pin numbers
 | ||||
| 
 | ||||
| #elif defined(CORE_TEENSY) && defined(__AVR_ATmega32U4__) | ||||
| // Teensy 2.0 pin numbers
 | ||||
| // http://www.pjrc.com/teensy/pinout.html
 | ||||
| #define P0  Pb0 | ||||
| #define P1  Pb1 | ||||
| #define P2  Pb2 | ||||
| #define P3  Pb3 | ||||
| #define P4  Pb7 | ||||
| #define P5  Pd0 | ||||
| #define P6  Pd1 | ||||
| #define P7  Pd2 | ||||
| #define P8  Pd3 | ||||
| #define P9  Pc6 | ||||
| #define P10 Pc7 | ||||
| #define P11 Pd6 | ||||
| #define P12 Pd7 | ||||
| #define P13 Pb4 | ||||
| #define P14 Pb5 | ||||
| #define P15 Pb6 | ||||
| #define P16 Pf7 | ||||
| #define P17 Pf6 | ||||
| #define P18 Pf5 | ||||
| #define P19 Pf4 | ||||
| #define P20 Pf1 | ||||
| #define P21 Pf0 | ||||
| #define P22 Pd4 | ||||
| #define P23 Pd5 | ||||
| #define P24 Pe6 | ||||
| // Teensy 2.0
 | ||||
| 
 | ||||
| #elif defined(__AVR_ATmega32U4__) | ||||
| // Arduino Leonardo pin numbers
 | ||||
| 
 | ||||
| #define P0  Pd2 // D0 - PD2
 | ||||
| #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
 | ||||
| 
 | ||||
| // Arduino Leonardo pin numbers
 | ||||
| 
 | ||||
| #elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) | ||||
| // Teensy++ 1.0 and 2.0 pin numbers
 | ||||
| // http://www.pjrc.com/teensy/pinout.html
 | ||||
| #define P0  Pd0 | ||||
| #define P1  Pd1 | ||||
| #define P2  Pd2 | ||||
| #define P3  Pd3 | ||||
| #define P4  Pd4 | ||||
| #define P5  Pd5 | ||||
| #define P6  Pd6 | ||||
| #define P7  Pd7 | ||||
| #define P8  Pe0 | ||||
| #define P9  Pe1 | ||||
| #define P10 Pc0 | ||||
| #define P11 Pc1 | ||||
| #define P12 Pc2 | ||||
| #define P13 Pc3 | ||||
| #define P14 Pc4 | ||||
| #define P15 Pc5 | ||||
| #define P16 Pc6 | ||||
| #define P17 Pc7 | ||||
| #define P18 Pe6 | ||||
| #define P19 Pe7 | ||||
| #define P20 Pb0 | ||||
| #define P21 Pb1 | ||||
| #define P22 Pb2 | ||||
| #define P23 Pb3 | ||||
| #define P24 Pb4 | ||||
| #define P25 Pb5 | ||||
| #define P26 Pb6 | ||||
| #define P27 Pb7 | ||||
| #define P28 Pa0 | ||||
| #define P29 Pa1 | ||||
| #define P30 Pa2 | ||||
| #define P31 Pa3 | ||||
| #define P32 Pa4 | ||||
| #define P33 Pa5 | ||||
| #define P34 Pa6 | ||||
| #define P35 Pa7 | ||||
| #define P36 Pe4 | ||||
| #define P37 Pe5 | ||||
| #define P38 Pf0 | ||||
| #define P39 Pf1 | ||||
| #define P40 Pf2 | ||||
| #define P41 Pf3 | ||||
| #define P42 Pf4 | ||||
| #define P43 Pf5 | ||||
| #define P44 Pf6 | ||||
| #define P45 Pf7 | ||||
| // Teensy++ 1.0 and 2.0
 | ||||
| 
 | ||||
| #elif defined(ARDUINO_AVR_BALANDUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__)) | ||||
| // Balanduino pin numbers
 | ||||
| // http://balanduino.net/
 | ||||
| #define P0  Pd0 /* 0  - PD0 */ | ||||
| #define P1  Pd1 /* 1  - PD1 */ | ||||
| 
 | ||||
| #if BALANDUINO_REVISION < 13 | ||||
|   #define P2  Pb2 /* 2  - PB2 */ | ||||
|   #define P3  Pd6 /* 3  - PD6 */ | ||||
|   #define P4  Pd7 /* 4  - PD7 */ | ||||
|   #define P5  Pb3 /* 5  - PB3 */ | ||||
| #else | ||||
|   #define P2  Pd2 /* 2  - PD2 */ | ||||
|   #define P3  Pd3 /* 3  - PD3 */ | ||||
|   #define P4  Pd6 /* 4  - PD6 */ | ||||
|   #define P5  Pd7 /* 5  - PD7 */ | ||||
| #endif | ||||
| 
 | ||||
| #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 Pc1 /* 13 - PC1 */ | ||||
| #define P14 Pc0 /* 14 - PC0 */ | ||||
| 
 | ||||
| #if BALANDUINO_REVISION < 13 | ||||
|   #define P15 Pd2 /* 15 - PD2 */ | ||||
|   #define P16 Pd3 /* 16 - PD3 */ | ||||
| #else | ||||
|   #define P15 Pb2 /* 15 - PB2 */ | ||||
|   #define P16 Pb3 /* 16 - PB2 */ | ||||
| #endif | ||||
| 
 | ||||
| #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 */ | ||||
| // Balanduino
 | ||||
| 
 | ||||
| #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | ||||
| // Sanguino pin numbers
 | ||||
| // Homepage: http://sanguino.cc/hardware
 | ||||
| // Hardware add-on: https://github.com/Lauszus/Sanguino
 | ||||
| #define P0  Pb0 | ||||
| #define P1  Pb1 | ||||
| #define P2  Pb2 | ||||
| #define P3  Pb3 | ||||
| #define P4  Pb4 | ||||
| #define P5  Pb5 | ||||
| #define P6  Pb6 | ||||
| #define P7  Pb7 | ||||
| #define P8  Pd0 | ||||
| #define P9  Pd1 | ||||
| #define P10 Pd2 | ||||
| #define P11 Pd3 | ||||
| #define P12 Pd4 | ||||
| #define P13 Pd5 | ||||
| #define P14 Pd6 | ||||
| #define P15 Pd7 | ||||
| #define P16 Pc0 | ||||
| #define P17 Pc1 | ||||
| #define P18 Pc2 | ||||
| #define P19 Pc3 | ||||
| #define P20 Pc4 | ||||
| #define P21 Pc5 | ||||
| #define P22 Pc6 | ||||
| #define P23 Pc7 | ||||
| #define P24 Pa0 | ||||
| #define P25 Pa1 | ||||
| #define P26 Pa2 | ||||
| #define P27 Pa3 | ||||
| #define P28 Pa4 | ||||
| #define P29 Pa5 | ||||
| #define P30 Pa6 | ||||
| #define P31 Pa7 | ||||
| // Sanguino
 | ||||
| 
 | ||||
| #else | ||||
| #error "Please define board in avrpins.h" | ||||
| 
 | ||||
| #endif // Arduino pin definitions
 | ||||
| 
 | ||||
| #endif // __AVR__
 | ||||
| 
 | ||||
| #if defined(__arm__) | ||||
| 
 | ||||
| // pointers are 32 bits on ARM
 | ||||
| #define pgm_read_pointer(p) pgm_read_dword(p) | ||||
| 
 | ||||
| #if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) | ||||
| 
 | ||||
| #include "core_pins.h" | ||||
| #include "avr_emulation.h" | ||||
| 
 | ||||
| #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) | ||||
| #define GPIO_BITBAND_PTR(reg, bit) ((uint8_t *)GPIO_BITBAND_ADDR((reg), (bit))) | ||||
| 
 | ||||
| #define MAKE_PIN(className, baseReg, pinNum, configReg) \ | ||||
| class className { \ | ||||
| public: \ | ||||
|   static void Set() { \ | ||||
|     *GPIO_BITBAND_PTR(baseReg, pinNum) = 1; \ | ||||
|   } \ | ||||
|   static void Clear() { \ | ||||
|     *GPIO_BITBAND_PTR(baseReg, pinNum) = 0; \ | ||||
|   } \ | ||||
|   static void SetDirRead() { \ | ||||
|     configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ | ||||
|     *(GPIO_BITBAND_PTR(baseReg, pinNum) + 640) = 0; \ | ||||
|   } \ | ||||
|   static void SetDirWrite() { \ | ||||
|     configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ | ||||
|     *(GPIO_BITBAND_PTR(baseReg, pinNum) + 640) = 1; \ | ||||
|   } \ | ||||
|   static uint8_t IsSet() { \ | ||||
|     return *(GPIO_BITBAND_PTR(baseReg, pinNum) + 512); \ | ||||
|   } \ | ||||
| }; | ||||
| 
 | ||||
| MAKE_PIN(P0, CORE_PIN0_PORTREG, CORE_PIN0_BIT, CORE_PIN0_CONFIG); | ||||
| MAKE_PIN(P1, CORE_PIN1_PORTREG, CORE_PIN1_BIT, CORE_PIN1_CONFIG); | ||||
| MAKE_PIN(P2, CORE_PIN2_PORTREG, CORE_PIN2_BIT, CORE_PIN2_CONFIG); | ||||
| MAKE_PIN(P3, CORE_PIN3_PORTREG, CORE_PIN3_BIT, CORE_PIN3_CONFIG); | ||||
| MAKE_PIN(P4, CORE_PIN4_PORTREG, CORE_PIN4_BIT, CORE_PIN4_CONFIG); | ||||
| MAKE_PIN(P5, CORE_PIN5_PORTREG, CORE_PIN5_BIT, CORE_PIN5_CONFIG); | ||||
| MAKE_PIN(P6, CORE_PIN6_PORTREG, CORE_PIN6_BIT, CORE_PIN6_CONFIG); | ||||
| MAKE_PIN(P7, CORE_PIN7_PORTREG, CORE_PIN7_BIT, CORE_PIN7_CONFIG); | ||||
| MAKE_PIN(P8, CORE_PIN8_PORTREG, CORE_PIN8_BIT, CORE_PIN8_CONFIG); | ||||
| MAKE_PIN(P9, CORE_PIN9_PORTREG, CORE_PIN9_BIT, CORE_PIN9_CONFIG); | ||||
| MAKE_PIN(P10, CORE_PIN10_PORTREG, CORE_PIN10_BIT, CORE_PIN10_CONFIG); | ||||
| MAKE_PIN(P11, CORE_PIN11_PORTREG, CORE_PIN11_BIT, CORE_PIN11_CONFIG); | ||||
| MAKE_PIN(P12, CORE_PIN12_PORTREG, CORE_PIN12_BIT, CORE_PIN12_CONFIG); | ||||
| MAKE_PIN(P13, CORE_PIN13_PORTREG, CORE_PIN13_BIT, CORE_PIN13_CONFIG); | ||||
| MAKE_PIN(P14, CORE_PIN14_PORTREG, CORE_PIN14_BIT, CORE_PIN14_CONFIG); | ||||
| MAKE_PIN(P15, CORE_PIN15_PORTREG, CORE_PIN15_BIT, CORE_PIN15_CONFIG); | ||||
| MAKE_PIN(P16, CORE_PIN16_PORTREG, CORE_PIN16_BIT, CORE_PIN16_CONFIG); | ||||
| MAKE_PIN(P17, CORE_PIN17_PORTREG, CORE_PIN17_BIT, CORE_PIN17_CONFIG); | ||||
| MAKE_PIN(P18, CORE_PIN18_PORTREG, CORE_PIN18_BIT, CORE_PIN18_CONFIG); | ||||
| MAKE_PIN(P19, CORE_PIN19_PORTREG, CORE_PIN19_BIT, CORE_PIN19_CONFIG); | ||||
| MAKE_PIN(P20, CORE_PIN20_PORTREG, CORE_PIN20_BIT, CORE_PIN20_CONFIG); | ||||
| MAKE_PIN(P21, CORE_PIN21_PORTREG, CORE_PIN21_BIT, CORE_PIN21_CONFIG); | ||||
| MAKE_PIN(P22, CORE_PIN22_PORTREG, CORE_PIN22_BIT, CORE_PIN22_CONFIG); | ||||
| MAKE_PIN(P23, CORE_PIN23_PORTREG, CORE_PIN23_BIT, CORE_PIN23_CONFIG); | ||||
| MAKE_PIN(P24, CORE_PIN24_PORTREG, CORE_PIN24_BIT, CORE_PIN24_CONFIG); | ||||
| MAKE_PIN(P25, CORE_PIN25_PORTREG, CORE_PIN25_BIT, CORE_PIN25_CONFIG); | ||||
| MAKE_PIN(P26, CORE_PIN26_PORTREG, CORE_PIN26_BIT, CORE_PIN26_CONFIG); | ||||
| MAKE_PIN(P27, CORE_PIN27_PORTREG, CORE_PIN27_BIT, CORE_PIN27_CONFIG); | ||||
| MAKE_PIN(P28, CORE_PIN28_PORTREG, CORE_PIN28_BIT, CORE_PIN28_CONFIG); | ||||
| MAKE_PIN(P29, CORE_PIN29_PORTREG, CORE_PIN29_BIT, CORE_PIN29_CONFIG); | ||||
| MAKE_PIN(P30, CORE_PIN30_PORTREG, CORE_PIN30_BIT, CORE_PIN30_CONFIG); | ||||
| MAKE_PIN(P31, CORE_PIN31_PORTREG, CORE_PIN31_BIT, CORE_PIN31_CONFIG); | ||||
| MAKE_PIN(P32, CORE_PIN32_PORTREG, CORE_PIN32_BIT, CORE_PIN32_CONFIG); | ||||
| MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); | ||||
| 
 | ||||
| #undef MAKE_PIN | ||||
| 
 | ||||
| #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) | ||||
| 
 | ||||
| // SetDirRead:
 | ||||
| //   Disable interrupts
 | ||||
| //   Disable the pull up resistor
 | ||||
| //   Set to INPUT
 | ||||
| //   Enable PIO
 | ||||
| 
 | ||||
| // SetDirWrite:
 | ||||
| //   Disable interrupts
 | ||||
| //   Disable the pull up resistor
 | ||||
| //   Set to OUTPUT
 | ||||
| //   Enable PIO
 | ||||
| 
 | ||||
| #define MAKE_PIN(className, pio, pinMask) \ | ||||
| class className { \ | ||||
| public: \ | ||||
|   static void Set() { \ | ||||
|     pio->PIO_SODR = pinMask; \ | ||||
|   } \ | ||||
|   static void Clear() { \ | ||||
|     pio->PIO_CODR = pinMask; \ | ||||
|   } \ | ||||
|   static void SetDirRead() { \ | ||||
|     pio->PIO_IDR = pinMask ; \ | ||||
|     pio->PIO_PUDR = pinMask; \ | ||||
|     pio->PIO_ODR = pinMask; \ | ||||
|     pio->PIO_PER = pinMask; \ | ||||
|   } \ | ||||
|   static void SetDirWrite() { \ | ||||
|     pio->PIO_IDR = pinMask ; \ | ||||
|     pio->PIO_PUDR = pinMask; \ | ||||
|     pio->PIO_OER = pinMask; \ | ||||
|     pio->PIO_PER = pinMask; \ | ||||
|   } \ | ||||
|   static uint8_t IsSet() { \ | ||||
|     return pio->PIO_PDSR & pinMask; \ | ||||
|   } \ | ||||
| }; | ||||
| 
 | ||||
| // See: http://arduino.cc/en/Hacking/PinMappingSAM3X and variant.cpp
 | ||||
| 
 | ||||
| MAKE_PIN(P0, PIOA, PIO_PA8); | ||||
| MAKE_PIN(P1, PIOA, PIO_PA9); | ||||
| MAKE_PIN(P2, PIOB, PIO_PB25); | ||||
| MAKE_PIN(P3, PIOC, PIO_PC28); | ||||
| MAKE_PIN(P4, PIOC, PIO_PC26); | ||||
| MAKE_PIN(P5, PIOC, PIO_PC25); | ||||
| MAKE_PIN(P6, PIOC, PIO_PC24); | ||||
| MAKE_PIN(P7, PIOC, PIO_PC23); | ||||
| MAKE_PIN(P8, PIOC, PIO_PC22); | ||||
| MAKE_PIN(P9, PIOC, PIO_PC21); | ||||
| MAKE_PIN(P10, PIOC, PIO_PC29); | ||||
| MAKE_PIN(P11, PIOD, PIO_PD7); | ||||
| MAKE_PIN(P12, PIOD, PIO_PD8); | ||||
| MAKE_PIN(P13, PIOB, PIO_PB27); | ||||
| MAKE_PIN(P14, PIOD, PIO_PD4); | ||||
| MAKE_PIN(P15, PIOD, PIO_PD5); | ||||
| MAKE_PIN(P16, PIOA, PIO_PA13); | ||||
| MAKE_PIN(P17, PIOA, PIO_PA12); | ||||
| MAKE_PIN(P18, PIOA, PIO_PA11); | ||||
| MAKE_PIN(P19, PIOA, PIO_PA10); | ||||
| MAKE_PIN(P20, PIOB, PIO_PB12); | ||||
| MAKE_PIN(P21, PIOB, PIO_PB13); | ||||
| MAKE_PIN(P22, PIOB, PIO_PB26); | ||||
| MAKE_PIN(P23, PIOA, PIO_PA14); | ||||
| MAKE_PIN(P24, PIOA, PIO_PA15); | ||||
| MAKE_PIN(P25, PIOD, PIO_PD0); | ||||
| MAKE_PIN(P26, PIOD, PIO_PD1); | ||||
| MAKE_PIN(P27, PIOD, PIO_PD2); | ||||
| MAKE_PIN(P28, PIOD, PIO_PD3); | ||||
| MAKE_PIN(P29, PIOD, PIO_PD6); | ||||
| MAKE_PIN(P30, PIOD, PIO_PD9); | ||||
| MAKE_PIN(P31, PIOA, PIO_PA7); | ||||
| MAKE_PIN(P32, PIOD, PIO_PD10); | ||||
| MAKE_PIN(P33, PIOC, PIO_PC1); | ||||
| MAKE_PIN(P34, PIOC, PIO_PC2); | ||||
| MAKE_PIN(P35, PIOC, PIO_PC3); | ||||
| MAKE_PIN(P36, PIOC, PIO_PC4); | ||||
| MAKE_PIN(P37, PIOC, PIO_PC5); | ||||
| MAKE_PIN(P38, PIOC, PIO_PC6); | ||||
| MAKE_PIN(P39, PIOC, PIO_PC7); | ||||
| MAKE_PIN(P40, PIOC, PIO_PC8); | ||||
| MAKE_PIN(P41, PIOC, PIO_PC9); | ||||
| MAKE_PIN(P42, PIOA, PIO_PA19); | ||||
| MAKE_PIN(P43, PIOA, PIO_PA20); | ||||
| MAKE_PIN(P44, PIOC, PIO_PC19); | ||||
| MAKE_PIN(P45, PIOC, PIO_PC18); | ||||
| MAKE_PIN(P46, PIOC, PIO_PC17); | ||||
| MAKE_PIN(P47, PIOC, PIO_PC16); | ||||
| MAKE_PIN(P48, PIOC, PIO_PC15); | ||||
| MAKE_PIN(P49, PIOC, PIO_PC14); | ||||
| MAKE_PIN(P50, PIOC, PIO_PC13); | ||||
| MAKE_PIN(P51, PIOC, PIO_PC12); | ||||
| MAKE_PIN(P52, PIOB, PIO_PB21); | ||||
| MAKE_PIN(P53, PIOB, PIO_PB14); | ||||
| MAKE_PIN(P54, PIOA, PIO_PA16); | ||||
| MAKE_PIN(P55, PIOA, PIO_PA24); | ||||
| MAKE_PIN(P56, PIOA, PIO_PA23); | ||||
| MAKE_PIN(P57, PIOA, PIO_PA22); | ||||
| MAKE_PIN(P58, PIOA, PIO_PA6); | ||||
| MAKE_PIN(P59, PIOA, PIO_PA4); | ||||
| MAKE_PIN(P60, PIOA, PIO_PA3); | ||||
| MAKE_PIN(P61, PIOA, PIO_PA2); | ||||
| MAKE_PIN(P62, PIOB, PIO_PB17); | ||||
| MAKE_PIN(P63, PIOB, PIO_PB18); | ||||
| MAKE_PIN(P64, PIOB, PIO_PB19); | ||||
| MAKE_PIN(P65, PIOB, PIO_PB20); | ||||
| MAKE_PIN(P66, PIOB, PIO_PB15); | ||||
| MAKE_PIN(P67, PIOB, PIO_PB16); | ||||
| MAKE_PIN(P68, PIOA, PIO_PA1); | ||||
| MAKE_PIN(P69, PIOA, PIO_PA0); | ||||
| MAKE_PIN(P70, PIOA, PIO_PA17); | ||||
| MAKE_PIN(P71, PIOA, PIO_PA18); | ||||
| MAKE_PIN(P72, PIOC, PIO_PC30); | ||||
| MAKE_PIN(P73, PIOA, PIO_PA21); | ||||
| MAKE_PIN(P74, PIOA, PIO_PA25); // MISO
 | ||||
| MAKE_PIN(P75, PIOA, PIO_PA26); // MOSI
 | ||||
| MAKE_PIN(P76, PIOA, PIO_PA27); // CLK
 | ||||
| MAKE_PIN(P77, PIOA, PIO_PA28); | ||||
| MAKE_PIN(P78, PIOB, PIO_PB23); // Unconnected
 | ||||
| 
 | ||||
| #undef MAKE_PIN | ||||
| 
 | ||||
| #elif defined(RBL_NRF51822) | ||||
| 
 | ||||
| #define MAKE_PIN(className, pin) \ | ||||
| class className { \ | ||||
| public: \ | ||||
|     static void Set() { \ | ||||
|         nrf_gpio_pin_set(pin); \ | ||||
|     } \ | ||||
|     static void Clear() { \ | ||||
|         nrf_gpio_pin_clear(pin); \ | ||||
|     } \ | ||||
|     static void SetDirRead() { \ | ||||
|         nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL); \ | ||||
|     } \ | ||||
|     static void SetDirWrite() { \ | ||||
|         nrf_gpio_cfg_output(pin); \ | ||||
|     } \ | ||||
|     static uint8_t IsSet() { \ | ||||
|         return (uint8_t)nrf_gpio_pin_read(pin); \ | ||||
|     } \ | ||||
| }; | ||||
| 
 | ||||
| // See: pin_transform.c in RBL nRF51822 SDK
 | ||||
| MAKE_PIN(P0, Pin_nRF51822_to_Arduino(D0)); | ||||
| MAKE_PIN(P1, Pin_nRF51822_to_Arduino(D1)); | ||||
| MAKE_PIN(P2, Pin_nRF51822_to_Arduino(D2)); | ||||
| MAKE_PIN(P3, Pin_nRF51822_to_Arduino(D3)); | ||||
| MAKE_PIN(P4, Pin_nRF51822_to_Arduino(D4)); | ||||
| MAKE_PIN(P5, Pin_nRF51822_to_Arduino(D5)); | ||||
| MAKE_PIN(P6, Pin_nRF51822_to_Arduino(D6)); | ||||
| MAKE_PIN(P7, Pin_nRF51822_to_Arduino(D7)); | ||||
| MAKE_PIN(P8, Pin_nRF51822_to_Arduino(D8)); | ||||
| MAKE_PIN(P9, Pin_nRF51822_to_Arduino(D9)); // INT
 | ||||
| MAKE_PIN(P10, Pin_nRF51822_to_Arduino(D10)); // SS
 | ||||
| MAKE_PIN(P11, Pin_nRF51822_to_Arduino(D11)); | ||||
| MAKE_PIN(P12, Pin_nRF51822_to_Arduino(D12)); | ||||
| MAKE_PIN(P13, Pin_nRF51822_to_Arduino(D13)); | ||||
| MAKE_PIN(P14, Pin_nRF51822_to_Arduino(D14)); | ||||
| MAKE_PIN(P15, Pin_nRF51822_to_Arduino(D15)); | ||||
| MAKE_PIN(P17, Pin_nRF51822_to_Arduino(D17)); // MISO
 | ||||
| MAKE_PIN(P18, Pin_nRF51822_to_Arduino(D18)); // MOSI
 | ||||
| MAKE_PIN(P16, Pin_nRF51822_to_Arduino(D16)); // CLK
 | ||||
| MAKE_PIN(P19, Pin_nRF51822_to_Arduino(D19)); | ||||
| MAKE_PIN(P20, Pin_nRF51822_to_Arduino(D20)); | ||||
| MAKE_PIN(P21, Pin_nRF51822_to_Arduino(D21)); | ||||
| MAKE_PIN(P22, Pin_nRF51822_to_Arduino(D22)); | ||||
| MAKE_PIN(P23, Pin_nRF51822_to_Arduino(D23)); | ||||
| MAKE_PIN(P24, Pin_nRF51822_to_Arduino(D24)); | ||||
| 
 | ||||
| #undef MAKE_PIN | ||||
| 
 | ||||
| 
 | ||||
| #else | ||||
| #error "Please define board in avrpins.h" | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #endif // __arm__
 | ||||
| 
 | ||||
| #endif //_avrpins_h_
 | ||||
| @ -0,0 +1,217 @@ | ||||
| /* 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(_usb_h_) || defined(__CONFDESCPARSER_H__) | ||||
| #error "Never include confdescparser.h directly; include Usb.h instead" | ||||
| #else | ||||
| 
 | ||||
| #define __CONFDESCPARSER_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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> | ||||
| 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 UseOr; | ||||
|         bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn); | ||||
|         void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|         void SetOR(void) { | ||||
|                 UseOr = true; | ||||
|         } | ||||
|         ConfigDescParser(UsbConfigXtracter *xtractor); | ||||
|         virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); | ||||
| }; | ||||
| 
 | ||||
| template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> | ||||
| ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) : | ||||
| theXtractor(xtractor), | ||||
| stateParseDescr(0), | ||||
| dscrLen(0), | ||||
| dscrType(0), | ||||
| UseOr(false) { | ||||
|         theBuffer.pValue = varBuffer; | ||||
|         valParser.Initialize(&theBuffer); | ||||
|         theSkipper.Initialize(&theBuffer); | ||||
| }; | ||||
| 
 | ||||
| template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> | ||||
| void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> | ||||
| bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) { | ||||
|         USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer); | ||||
|         USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer); | ||||
|         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 all ready in the buffer
 | ||||
|                         //	the pointer is positioned two bytes ahead in order for the rest of descriptor
 | ||||
|                         //	to be read right after the size and the type fields.
 | ||||
|                         // This should be used carefully. 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 = ucd->bConfigurationValue; | ||||
|                                         break; | ||||
|                                 case USB_DESCRIPTOR_INTERFACE: | ||||
|                                         if(!valParser.Parse(pp, pcntdn)) | ||||
|                                                 return false; | ||||
|                                         if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID) | ||||
|                                                 break; | ||||
|                                         if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID) | ||||
|                                                 break; | ||||
|                                         if(UseOr) { | ||||
|                                                 if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol))) | ||||
|                                                         break; | ||||
|                                         } else { | ||||
|                                                 if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID) | ||||
|                                                         break; | ||||
|                                         } | ||||
|                                         isGoodInterface = true; | ||||
|                                         ifaceNumber = uid->bInterfaceNumber; | ||||
|                                         ifaceAltSet = uid->bAlternateSetting; | ||||
|                                         protoValue = uid->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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> | ||||
| void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { | ||||
|         Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80); | ||||
|         Notify(PSTR("bDescLength:\t\t"), 0x80); | ||||
|         PrintHex<uint8_t > (pDesc->bLength, 0x80); | ||||
| 
 | ||||
|         Notify(PSTR("\r\nbDescriptorType:\t"), 0x80); | ||||
|         PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80); | ||||
| 
 | ||||
|         Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80); | ||||
|         PrintHex<uint16_t > (pDesc->bcdHID, 0x80); | ||||
| 
 | ||||
|         Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80); | ||||
|         PrintHex<uint8_t > (pDesc->bCountryCode, 0x80); | ||||
| 
 | ||||
|         Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80); | ||||
|         PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80); | ||||
| 
 | ||||
|         //Notify(PSTR("\r\nbDescrType:\t\t"));
 | ||||
|         //PrintHex<uint8_t>(pDesc->bDescrType);
 | ||||
|         //
 | ||||
|         //Notify(PSTR("\r\nwDescriptorLength:\t"));
 | ||||
|         //PrintHex<uint16_t>(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<uint8_t > (pLT[i].bDescrType, 0x80); | ||||
| 
 | ||||
|                 Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80); | ||||
|                 PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80); | ||||
|         } | ||||
|         Notify(PSTR("\r\n"), 0x80); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #endif // __CONFDESCPARSER_H__
 | ||||
| @ -0,0 +1,361 @@ | ||||
| #################################################### | ||||
| # Syntax Coloring Map For USB Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| USB	KEYWORD1 | ||||
| USBHub	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For BTD (Bluetooth) Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| BTD	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| Task	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For PS3/PS4 Bluetooth/USB Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| PS3BT	KEYWORD1 | ||||
| PS3USB	KEYWORD1 | ||||
| PS4BT	KEYWORD1 | ||||
| PS4USB	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| setBdaddr	KEYWORD2 | ||||
| getBdaddr	KEYWORD2 | ||||
| setMoveBdaddr	KEYWORD2 | ||||
| getMoveBdaddr	KEYWORD2 | ||||
| getMoveCalibration	KEYWORD2 | ||||
| 
 | ||||
| getButtonPress	KEYWORD2 | ||||
| getButtonClick	KEYWORD2 | ||||
| getAnalogButton	KEYWORD2 | ||||
| getAnalogHat	KEYWORD2 | ||||
| getSensor	KEYWORD2 | ||||
| getAngle	KEYWORD2 | ||||
| get9DOFValues	KEYWORD2 | ||||
| getStatus	KEYWORD2 | ||||
| printStatusString	KEYWORD2 | ||||
| getTemperature	KEYWORD2 | ||||
| disconnect	KEYWORD2 | ||||
| 
 | ||||
| setAllOff	KEYWORD2 | ||||
| setRumbleOff	KEYWORD2 | ||||
| setRumbleOn	KEYWORD2 | ||||
| setLedOff	KEYWORD2 | ||||
| setLedOn	KEYWORD2 | ||||
| setLedToggle	KEYWORD2 | ||||
| setLedFlash	KEYWORD2 | ||||
| moveSetBulb	KEYWORD2 | ||||
| moveSetRumble	KEYWORD2 | ||||
| 
 | ||||
| attachOnInit	KEYWORD2 | ||||
| 
 | ||||
| PS3Connected	KEYWORD2 | ||||
| PS3MoveConnected	KEYWORD2 | ||||
| PS3NavigationConnected	KEYWORD2 | ||||
| 
 | ||||
| isReady	KEYWORD2 | ||||
| watingForConnection	KEYWORD2 | ||||
| 
 | ||||
| isTouching	KEYWORD2 | ||||
| getX	KEYWORD2 | ||||
| getY	KEYWORD2 | ||||
| getTouchCounter	KEYWORD2 | ||||
| 
 | ||||
| getUsbStatus    KEYWORD2 | ||||
| getAudioStatus  KEYWORD2 | ||||
| getMicStatus    KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Constants and enums (LITERAL1) | ||||
| #################################################### | ||||
| OFF	LITERAL1 | ||||
| LED1	LITERAL1 | ||||
| LED2	LITERAL1 | ||||
| LED3	LITERAL1 | ||||
| LED4	LITERAL1 | ||||
| LED5	LITERAL1 | ||||
| LED6	LITERAL1 | ||||
| LED7	LITERAL1 | ||||
| LED8	LITERAL1 | ||||
| LED9	LITERAL1 | ||||
| LED10	LITERAL1 | ||||
| 
 | ||||
| Red	LITERAL1 | ||||
| Green	LITERAL1 | ||||
| Blue	LITERAL1 | ||||
| Yellow	LITERAL1 | ||||
| Lightblue	LITERAL1 | ||||
| Purble	LITERAL1 | ||||
| White	LITERAL1 | ||||
| Off	LITERAL1 | ||||
| 
 | ||||
| SELECT	LITERAL1 | ||||
| L3	LITERAL1 | ||||
| R3	LITERAL1 | ||||
| START	LITERAL1 | ||||
| UP	LITERAL1 | ||||
| RIGHT	LITERAL1 | ||||
| DOWN	LITERAL1 | ||||
| LEFT	LITERAL1 | ||||
| L2	LITERAL1 | ||||
| R2	LITERAL1 | ||||
| L1	LITERAL1 | ||||
| R1	LITERAL1 | ||||
| TRIANGLE	LITERAL1 | ||||
| CIRCLE	LITERAL1 | ||||
| CROSS	LITERAL1 | ||||
| SQUARE	LITERAL1 | ||||
| PS	LITERAL1 | ||||
| MOVE	LITERAL1 | ||||
| T	LITERAL1 | ||||
| 
 | ||||
| SHARE	LITERAL1 | ||||
| OPTIONS	LITERAL1 | ||||
| TOUCHPAD	LITERAL1 | ||||
| 
 | ||||
| LeftHatX	LITERAL1 | ||||
| LeftHatY	LITERAL1 | ||||
| RightHatX	LITERAL1 | ||||
| RightHatY	LITERAL1 | ||||
| 
 | ||||
| aX	LITERAL1 | ||||
| aY	LITERAL1 | ||||
| aZ	LITERAL1 | ||||
| gX	LITERAL1 | ||||
| gY	LITERAL1 | ||||
| gZ	LITERAL1 | ||||
| aXmove	LITERAL1 | ||||
| aYmove	LITERAL1 | ||||
| aZmove	LITERAL1 | ||||
| gXmove	LITERAL1 | ||||
| gYmove	LITERAL1 | ||||
| gZmove	LITERAL1 | ||||
| tempMove	LITERAL1 | ||||
| mXmove	LITERAL1 | ||||
| mZmove	LITERAL1 | ||||
| mYmove	LITERAL1 | ||||
| 
 | ||||
| Pitch	LITERAL1 | ||||
| Roll	LITERAL1 | ||||
| 
 | ||||
| Plugged	LITERAL1 | ||||
| Unplugged	LITERAL1 | ||||
| Charging	LITERAL1 | ||||
| NotCharging	LITERAL1 | ||||
| Shutdown	LITERAL1 | ||||
| Dying	LITERAL1 | ||||
| Low	LITERAL1 | ||||
| High	LITERAL1 | ||||
| Full	LITERAL1 | ||||
| MoveCharging	LITERAL1 | ||||
| MoveNotCharging	LITERAL1 | ||||
| MoveShutdown	LITERAL1 | ||||
| MoveDying	LITERAL1 | ||||
| MoveLow	LITERAL1 | ||||
| MoveHigh	LITERAL1 | ||||
| MoveFull	LITERAL1 | ||||
| CableRumble	LITERAL1 | ||||
| Cable	LITERAL1 | ||||
| BluetoothRumble	LITERAL1 | ||||
| Bluetooth	LITERAL1 | ||||
| 
 | ||||
| RumbleHigh	LITERAL1 | ||||
| RumbleLow	LITERAL1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For Xbox 360 Libraries | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| XBOXUSB	KEYWORD1 | ||||
| XBOXOLD	KEYWORD1 | ||||
| XBOXRECV	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| 
 | ||||
| setLedRaw	KEYWORD2 | ||||
| setLedBlink	KEYWORD2 | ||||
| setLedMode	KEYWORD2 | ||||
| getBatteryLevel	KEYWORD2 | ||||
| buttonChanged	KEYWORD2 | ||||
| 
 | ||||
| XboxReceiverConnected	KEYWORD2 | ||||
| Xbox360Connected	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Constants and enums (LITERAL1) | ||||
| #################################################### | ||||
| 
 | ||||
| ALL	LITERAL1 | ||||
| 
 | ||||
| ROTATING	LITERAL1 | ||||
| FASTBLINK	LITERAL1 | ||||
| SLOWBLINK	LITERAL1 | ||||
| ALTERNATING	LITERAL1 | ||||
| 
 | ||||
| BACK	LITERAL1 | ||||
| 
 | ||||
| XBOX	LITERAL1 | ||||
| SYNC	LITERAL1 | ||||
| 
 | ||||
| BLACK	LITERAL1 | ||||
| WHITE	LITERAL1 | ||||
| 
 | ||||
| A	LITERAL1 | ||||
| B	LITERAL1 | ||||
| X	LITERAL1 | ||||
| Y	LITERAL1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For RFCOMM/SPP Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| SPP	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| 
 | ||||
| connected	KEYWORD2 | ||||
| discard	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For Wiimote Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| WII	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| 
 | ||||
| wiimoteConnected	KEYWORD2 | ||||
| nunchuckConnected	KEYWORD2 | ||||
| motionPlusConnected	KEYWORD2 | ||||
| wiiUProControllerConnected	KEYWORD2 | ||||
| setRumbleToggle	KEYWORD2 | ||||
| getPitch	KEYWORD2 | ||||
| getRoll	KEYWORD2 | ||||
| getYaw	KEYWORD2 | ||||
| getWiimotePitch	KEYWORD2 | ||||
| getWiimoteRoll	KEYWORD2 | ||||
| getNunchuckPitch	KEYWORD2 | ||||
| getNunchuckRoll	KEYWORD2 | ||||
| PAIR	KEYWORD2 | ||||
| statusRequest	KEYWORD2 | ||||
| getBatteryLevel	KEYWORD2 | ||||
| getWiiState	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Constants and enums (LITERAL1) | ||||
| #################################################### | ||||
| 
 | ||||
| PLUS	LITERAL1 | ||||
| MINUS	LITERAL1 | ||||
| ONE	LITERAL1 | ||||
| TWO	LITERAL1 | ||||
| HOME	LITERAL1 | ||||
| Z	LITERAL1 | ||||
| C	LITERAL1 | ||||
| L	LITERAL1 | ||||
| R	LITERAL1 | ||||
| ZL	LITERAL1 | ||||
| ZR	LITERAL1 | ||||
| HatX	LITERAL1 | ||||
| HatY	LITERAL1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions for the IR Camera | ||||
| #################################################### | ||||
| 
 | ||||
| IRinitialize	KEYWORD2 | ||||
| isIRCameraEnabled	KEYWORD2 | ||||
| getIRx1	KEYWORD2 | ||||
| getIRy1	KEYWORD2 | ||||
| getIRs1	KEYWORD2 | ||||
| getIRx2	KEYWORD2 | ||||
| getIRy2	KEYWORD2 | ||||
| getIRs2	KEYWORD2 | ||||
| getIRx3	KEYWORD2 | ||||
| getIRy3	KEYWORD2 | ||||
| getIRs3	KEYWORD2 | ||||
| getIRx4	KEYWORD2 | ||||
| getIRy4	KEYWORD2 | ||||
| getIRs4	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For BTHID Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| BTHID	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| SetReportParser	KEYWORD2 | ||||
| setProtocolMode	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Syntax Coloring Map For PS Buzz Library | ||||
| #################################################### | ||||
| 
 | ||||
| #################################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| #################################################### | ||||
| 
 | ||||
| PSBuzz	KEYWORD1 | ||||
| 
 | ||||
| #################################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| #################################################### | ||||
| 
 | ||||
| setLedOnAll	KEYWORD2 | ||||
| setLedOffAll	KEYWORD2 | ||||
| 
 | ||||
| #################################################### | ||||
| # Constants and enums (LITERAL1) | ||||
| #################################################### | ||||
| 
 | ||||
| RED	LITERAL1 | ||||
| YELLOW	LITERAL1 | ||||
| GREEN	LITERAL1 | ||||
| ORANGE	LITERAL1 | ||||
| BLUE	LITERAL1 | ||||
| @ -0,0 +1,46 @@ | ||||
| { | ||||
|   "name": "USB-Host-Shield-20", | ||||
|   "keywords": "usb, host, ftdi, adk, acm, pl2303, hid, bluetooth, spp, ps3, ps4, buzz, xbox, wii, mass storage", | ||||
|   "description": "Revision 2.0 of MAX3421E-based USB Host Shield Library", | ||||
|   "authors": | ||||
|   [ | ||||
|     { | ||||
|       "name": "Oleg Mazurov", | ||||
|       "email": "mazurov@circuitsathome.com", | ||||
|       "url": "http://www.circuitsathome.com", | ||||
|       "maintainer": true | ||||
|     }, | ||||
|     { | ||||
|       "name": "Alexei Glushchenko", | ||||
|       "email": "alex-gl@mail.ru" | ||||
|     }, | ||||
|     { | ||||
|       "name": "Kristian Lauszus", | ||||
|       "email": "kristianl@tkjelectronics.com", | ||||
|       "url": "http://tkjelectronics.com", | ||||
|       "maintainer": true | ||||
|     }, | ||||
|     { | ||||
|       "name": "Andrew Kroll", | ||||
|       "email": "xxxajk@gmail.com", | ||||
|       "maintainer": true | ||||
|     } | ||||
|   ], | ||||
|   "repository": | ||||
|   { | ||||
|     "type": "git", | ||||
|     "url": "https://github.com/felis/USB_Host_Shield_2.0.git" | ||||
|   }, | ||||
|   "examples": | ||||
|   [ | ||||
|   	"examples/*/*.ino", | ||||
|   	"examples/*/*/*.ino" | ||||
|   ], | ||||
|   "frameworks": "arduino", | ||||
|   "platforms": | ||||
|   [ | ||||
|     "atmelavr", | ||||
|     "teensy", | ||||
|     "atmelsam" | ||||
|   ] | ||||
| } | ||||
| @ -0,0 +1,82 @@ | ||||
| /* 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(_usb_h_) || defined(MACROS_H) | ||||
| #error "Never include macros.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define	MACROS_H | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // HANDY MACROS
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h))) | ||||
| #define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h))) | ||||
| #define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el) | ||||
| #define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el); | ||||
| 
 | ||||
| #define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) | ||||
| #ifndef __BYTE_GRABBING_DEFINED__ | ||||
| #define __BYTE_GRABBING_DEFINED__ 1 | ||||
| #ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN | ||||
| // Note: Use this if your compiler generates horrible assembler!
 | ||||
| #define BGRAB0(__usi__)  (((uint8_t *)&(__usi__))[0]) | ||||
| #define BGRAB1(__usi__)  (((uint8_t *)&(__usi__))[1]) | ||||
| #define BGRAB2(__usi__)  (((uint8_t *)&(__usi__))[2]) | ||||
| #define BGRAB3(__usi__)  (((uint8_t *)&(__usi__))[3]) | ||||
| #define BGRAB4(__usi__)  (((uint8_t *)&(__usi__))[4]) | ||||
| #define BGRAB5(__usi__)  (((uint8_t *)&(__usi__))[5]) | ||||
| #define BGRAB6(__usi__)  (((uint8_t *)&(__usi__))[6]) | ||||
| #define BGRAB7(__usi__)  (((uint8_t *)&(__usi__))[7]) | ||||
| #else | ||||
| // Note: The cast alone to uint8_t is actually enough.
 | ||||
| // GCC throws out the "& 0xff", and the size is no different.
 | ||||
| // Some compilers need it.
 | ||||
| #define BGRAB0(__usi__)  ((uint8_t)((__usi__) & 0xff )) | ||||
| #define BGRAB1(__usi__)  ((uint8_t)(((__usi__) >> 8) & 0xff)) | ||||
| #define BGRAB2(__usi__)  ((uint8_t)(((__usi__) >> 16) & 0xff)) | ||||
| #define BGRAB3(__usi__)  ((uint8_t)(((__usi__) >> 24) & 0xff)) | ||||
| #define BGRAB4(__usi__)  ((uint8_t)(((__usi__) >> 32) & 0xff)) | ||||
| #define BGRAB5(__usi__)  ((uint8_t)(((__usi__) >> 40) & 0xff)) | ||||
| #define BGRAB6(__usi__)  ((uint8_t)(((__usi__) >> 48) & 0xff)) | ||||
| #define BGRAB7(__usi__)  ((uint8_t)(((__usi__) >> 56) & 0xff)) | ||||
| #endif | ||||
| #define BOVER1(__usi__)  ((uint16_t)(__usi__) << 8) | ||||
| #define BOVER2(__usi__)  ((uint32_t)(__usi__) << 16) | ||||
| #define BOVER3(__usi__)  ((uint32_t)(__usi__) << 24) | ||||
| #define BOVER4(__usi__)  ((uint64_t)(__usi__) << 32) | ||||
| #define BOVER5(__usi__)  ((uint64_t)(__usi__) << 40) | ||||
| #define BOVER6(__usi__)  ((uint64_t)(__usi__) << 48) | ||||
| #define BOVER7(__usi__)  ((uint64_t)(__usi__) << 56) | ||||
| 
 | ||||
| // These are the smallest and fastest ways I have found so far in pure C/C++.
 | ||||
| #define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__))) | ||||
| #define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__))) | ||||
| #define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__))) | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Debug macros: Strings are stored in progmem (flash) instead of RAM. | ||||
|  */ | ||||
| #define USBTRACE(s) (Notify(PSTR(s), 0x80)) | ||||
| #define USBTRACE1(s,l) (Notify(PSTR(s), l)) | ||||
| #define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80)) | ||||
| #define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l)) | ||||
| 
 | ||||
| 
 | ||||
| #endif	/* MACROS_H */ | ||||
| 
 | ||||
| @ -0,0 +1,1270 @@ | ||||
| /* 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 "masstorage.h" | ||||
| 
 | ||||
| const uint8_t BulkOnly::epDataInIndex = 1; | ||||
| const uint8_t BulkOnly::epDataOutIndex = 2; | ||||
| const uint8_t BulkOnly::epInterruptInIndex = 3; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| // Interface code
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Get the capacity of the media | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return media capacity | ||||
|  */ | ||||
| uint32_t BulkOnly::GetCapacity(uint8_t lun) { | ||||
|         if(LUNOk[lun]) | ||||
|                 return CurrentCapacity[lun]; | ||||
|         return 0LU; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get the sector (block) size used on the media | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return media sector size | ||||
|  */ | ||||
| uint16_t BulkOnly::GetSectorSize(uint8_t lun) { | ||||
|         if(LUNOk[lun]) | ||||
|                 return CurrentSectorSize[lun]; | ||||
|         return 0U; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Test if LUN is ready for use | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return true if LUN is ready for use | ||||
|  */ | ||||
| bool BulkOnly::LUNIsGood(uint8_t lun) { | ||||
|         return LUNOk[lun]; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Test if LUN is write protected | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return cached status of write protect switch | ||||
|  */ | ||||
| boolean BulkOnly::WriteProtected(uint8_t lun) { | ||||
|         return WriteOk[lun]; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Wrap and execute a SCSI CDB with length of 6 | ||||
|  * | ||||
|  * @param cdb CDB to execute | ||||
|  * @param buf_size Size of expected transaction | ||||
|  * @param buf Buffer | ||||
|  * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { | ||||
|         // promote buf_size to 32bits.
 | ||||
|         CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); | ||||
|         //SetCurLUN(cdb->LUN);
 | ||||
|         return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Wrap and execute a SCSI CDB with length of 10 | ||||
|  * | ||||
|  * @param cdb CDB to execute | ||||
|  * @param buf_size Size of expected transaction | ||||
|  * @param buf Buffer | ||||
|  * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { | ||||
|         // promote buf_size to 32bits.
 | ||||
|         CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); | ||||
|         //SetCurLUN(cdb->LUN);
 | ||||
|         return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Lock or Unlock the tray or door on device. | ||||
|  * Caution: Some devices with buggy firmware will lock up. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param lock 1 to lock, 0 to unlock | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) { | ||||
|         Notify(PSTR("\r\nLockMedia\r\n"), 0x80); | ||||
|         Notify(PSTR("---------\r\n"), 0x80); | ||||
| 
 | ||||
|         CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock); | ||||
|         return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Media control, for spindle motor and media tray or door. | ||||
|  * This includes CDROM, TAPE and anything with a media loader. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media | ||||
|  * @return 0 on success | ||||
|  */ | ||||
| uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { | ||||
|         Notify(PSTR("\r\nMediaCTL\r\n"), 0x80); | ||||
|         Notify(PSTR("-----------------\r\n"), 0x80); | ||||
| 
 | ||||
|         uint8_t rcode = MASS_ERR_UNIT_NOT_READY; | ||||
|         if(bAddress) { | ||||
|                 CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0); | ||||
|                 rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT); | ||||
|         } else { | ||||
|                 SetCurLUN(lun); | ||||
|         } | ||||
|         return rcode; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Read data from media | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param addr LBA address on media to read | ||||
|  * @param bsize size of a block (we should probably use the cached size) | ||||
|  * @param blocks how many blocks to read | ||||
|  * @param buf memory that is able to hold the requested data | ||||
|  * @return 0 on success | ||||
|  */ | ||||
| uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) { | ||||
|         if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||||
|         Notify(PSTR("\r\nRead LUN:\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (lun, 0x90); | ||||
|         Notify(PSTR("\r\nLBA:\t\t"), 0x90); | ||||
|         D_PrintHex<uint32_t > (addr, 0x90); | ||||
|         Notify(PSTR("\r\nblocks:\t\t"), 0x90); | ||||
|         D_PrintHex<uint8_t > (blocks, 0x90); | ||||
|         Notify(PSTR("\r\nblock size:\t"), 0x90); | ||||
|         D_PrintHex<uint16_t > (bsize, 0x90); | ||||
|         Notify(PSTR("\r\n---------\r\n"), 0x80); | ||||
|         CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr); | ||||
| 
 | ||||
| again: | ||||
|         uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN); | ||||
| 
 | ||||
|         if(er == MASS_ERR_STALL) { | ||||
|                 MediaCTL(lun, 1); | ||||
|                 DELAY(150); | ||||
|                 if(!TestUnitReady(lun)) goto again; | ||||
|         } | ||||
|         return er; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Write data to media | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param addr LBA address on media to write | ||||
|  * @param bsize size of a block (we should probably use the cached size) | ||||
|  * @param blocks how many blocks to write | ||||
|  * @param buf memory that contains the data to write | ||||
|  * @return 0 on success | ||||
|  */ | ||||
| uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) { | ||||
|         if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||||
|         if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED; | ||||
|         Notify(PSTR("\r\nWrite LUN:\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (lun, 0x90); | ||||
|         Notify(PSTR("\r\nLBA:\t\t"), 0x90); | ||||
|         D_PrintHex<uint32_t > (addr, 0x90); | ||||
|         Notify(PSTR("\r\nblocks:\t\t"), 0x90); | ||||
|         D_PrintHex<uint8_t > (blocks, 0x90); | ||||
|         Notify(PSTR("\r\nblock size:\t"), 0x90); | ||||
|         D_PrintHex<uint16_t > (bsize, 0x90); | ||||
|         Notify(PSTR("\r\n---------\r\n"), 0x80); | ||||
|         CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr); | ||||
| 
 | ||||
| again: | ||||
|         uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT); | ||||
| 
 | ||||
|         if(er == MASS_ERR_WRITE_STALL) { | ||||
|                 MediaCTL(lun, 1); | ||||
|                 DELAY(150); | ||||
|                 if(!TestUnitReady(lun)) goto again; | ||||
|         } | ||||
|         return er; | ||||
| } | ||||
| 
 | ||||
| // End of user functions, the remaining code below is driver internals.
 | ||||
| // Only developer serviceable parts below!
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| // Main driver code
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| BulkOnly::BulkOnly(USB *p) : | ||||
| pUsb(p), | ||||
| bAddress(0), | ||||
| bIface(0), | ||||
| bNumEP(1), | ||||
| qNextPollTime(0), | ||||
| bPollEnable(false), | ||||
| //dCBWTag(0),
 | ||||
| bLastUsbError(0) { | ||||
|         ClearAllEP(); | ||||
|         dCBWTag = 0; | ||||
|         if(pUsb) | ||||
|                 pUsb->RegisterDeviceClass(this); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success | ||||
|  * We need to standardize either the rcode, or change the API to return values | ||||
|  * so a signal that additional actions are required can be produced. | ||||
|  * Some of these codes do exist already. | ||||
|  * | ||||
|  * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance. | ||||
|  * Doing so would save some program memory when using multiple drivers. | ||||
|  * | ||||
|  * @param parent USB address of parent | ||||
|  * @param port address of port on parent | ||||
|  * @param lowspeed true if device is low speed | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { | ||||
| 
 | ||||
|         const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); | ||||
| 
 | ||||
|         uint8_t buf[constBufSize]; | ||||
|         USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||||
|         uint8_t rcode; | ||||
|         UsbDevice *p = NULL; | ||||
|         EpInfo *oldep_ptr = NULL; | ||||
|         USBTRACE("MS ConfigureDevice\r\n"); | ||||
|         ClearAllEP(); | ||||
|         AddressPool &addrPool = pUsb->GetAddressPool(); | ||||
| 
 | ||||
| 
 | ||||
|         if(bAddress) | ||||
|                 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||||
| 
 | ||||
|         // <TECHNICAL>
 | ||||
|         // 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 = udd->bMaxPacketSize0; | ||||
|         // Steal and abuse from epInfo structure to save on memory.
 | ||||
|         epInfo[1].epAddr = udd->bNumConfigurations; | ||||
|         // </TECHNICAL>
 | ||||
|         return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; | ||||
| 
 | ||||
| FailGetDevDescr: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         NotifyFailGetDevDescr(rcode); | ||||
| #endif | ||||
|         rcode = USB_ERROR_FailGetDevDescr; | ||||
| 
 | ||||
|         Release(); | ||||
|         return rcode; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * | ||||
|  * @param parent (not used) | ||||
|  * @param port (not used) | ||||
|  * @param lowspeed true if device is low speed | ||||
|  * @return 0 for success | ||||
|  */ | ||||
| uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||||
|         uint8_t rcode; | ||||
|         uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
 | ||||
|         epInfo[1].epAddr = 0; | ||||
|         USBTRACE("MS Init\r\n"); | ||||
| 
 | ||||
|         AddressPool &addrPool = pUsb->GetAddressPool(); | ||||
|         UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); | ||||
| 
 | ||||
|         if(!p) | ||||
|                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||||
| 
 | ||||
|         // Assign new address to the device
 | ||||
|         DELAY(2000); | ||||
|         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; | ||||
| 
 | ||||
|         // 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; | ||||
|         } | ||||
| 
 | ||||
|         if(bNumEP < 3) | ||||
|                 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||||
| 
 | ||||
|         // Assign epInfo to epinfo pointer
 | ||||
|         pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); | ||||
| 
 | ||||
|         USBTRACE2("Conf:", bConfNum); | ||||
| 
 | ||||
|         // Set Configuration Value
 | ||||
|         rcode = pUsb->setConf(bAddress, 0, bConfNum); | ||||
| 
 | ||||
|         if(rcode) | ||||
|                 goto FailSetConfDescr; | ||||
| 
 | ||||
|         //Linux does a 1sec delay after this.
 | ||||
|         DELAY(1000); | ||||
| 
 | ||||
|         rcode = GetMaxLUN(&bMaxLUN); | ||||
|         if(rcode) | ||||
|                 goto FailGetMaxLUN; | ||||
| 
 | ||||
|         if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1; | ||||
|         ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN); | ||||
| 
 | ||||
|         DELAY(1000); // Delay a bit for slow firmware.
 | ||||
| 
 | ||||
|         for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||||
|                 InquiryResponse response; | ||||
|                 rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); | ||||
|                 if(rcode) { | ||||
|                         ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode); | ||||
|                 } else { | ||||
| #if 0 | ||||
|                         printf("LUN %i `", lun); | ||||
|                         uint8_t *buf = response.VendorID; | ||||
|                         for(int i = 0; i < 28; i++) printf("%c", buf[i]); | ||||
|                         printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier); | ||||
|                         printf("Device type %2.2X ", response.DeviceType); | ||||
|                         printf("RMB %1.1X ", response.Removable); | ||||
|                         printf("SSCS %1.1X ", response.SCCS); | ||||
|                         uint8_t sv = response.Version; | ||||
|                         printf("SCSI version %2.2X\r\nDevice conforms to ", sv); | ||||
|                         switch(sv) { | ||||
|                                 case 0: | ||||
|                                         printf("No specific"); | ||||
|                                         break; | ||||
|                                 case 1: | ||||
|                                         printf("ANSI X3.131-1986 (ANSI 1)"); | ||||
|                                         break; | ||||
|                                 case 2: | ||||
|                                         printf("ANSI X3.131-1994 (ANSI 2)"); | ||||
|                                         break; | ||||
|                                 case 3: | ||||
|                                         printf("ANSI INCITS 301-1997 (SPC)"); | ||||
|                                         break; | ||||
|                                 case 4: | ||||
|                                         printf("ANSI INCITS 351-2001 (SPC-2)"); | ||||
|                                         break; | ||||
|                                 case 5: | ||||
|                                         printf("ANSI INCITS 408-2005 (SPC-4)"); | ||||
|                                         break; | ||||
|                                 case 6: | ||||
|                                         printf("T10/1731-D (SPC-4)"); | ||||
|                                         break; | ||||
|                                 default: | ||||
|                                         printf("unknown"); | ||||
|                         } | ||||
|                         printf(" standards.\r\n"); | ||||
| #endif | ||||
|                         uint8_t tries = 0xf0; | ||||
|                         while((rcode = TestUnitReady(lun))) { | ||||
|                                 if(rcode == 0x08) break; // break on no media, this is OK to do.
 | ||||
|                                 // try to lock media and spin up
 | ||||
|                                 if(tries < 14) { | ||||
|                                         LockMedia(lun, 1); | ||||
|                                         MediaCTL(lun, 1); // I actually have a USB stick that needs this!
 | ||||
|                                 } else DELAY(2 * (tries + 1)); | ||||
|                                 tries++; | ||||
|                                 if(!tries) break; | ||||
|                         } | ||||
|                         if(!rcode) { | ||||
|                                 DELAY(1000); | ||||
|                                 LUNOk[lun] = CheckLUN(lun); | ||||
|                                 if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun); | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         CheckMedia(); | ||||
| 
 | ||||
|         rcode = OnInit(); | ||||
| 
 | ||||
|         if(rcode) | ||||
|                 goto FailOnInit; | ||||
| 
 | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         USBTRACE("MS configured\r\n\r\n"); | ||||
| #endif | ||||
| 
 | ||||
|         bPollEnable = true; | ||||
| 
 | ||||
|         //USBTRACE("Poll enabled\r\n");
 | ||||
|         return 0; | ||||
| 
 | ||||
| FailSetConfDescr: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         NotifyFailSetConfDescr(); | ||||
|         goto Fail; | ||||
| #endif | ||||
| 
 | ||||
| FailOnInit: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         USBTRACE("OnInit:"); | ||||
|         goto Fail; | ||||
| #endif | ||||
| 
 | ||||
| FailGetMaxLUN: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         USBTRACE("GetMaxLUN:"); | ||||
|         goto Fail; | ||||
| #endif | ||||
| 
 | ||||
|         //#ifdef DEBUG_USB_HOST
 | ||||
|         //FailInvalidSectorSize:
 | ||||
|         //        USBTRACE("Sector Size is NOT VALID: ");
 | ||||
|         //        goto Fail;
 | ||||
|         //#endif
 | ||||
| 
 | ||||
| FailSetDevTblEntry: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         NotifyFailSetDevTblEntry(); | ||||
|         goto Fail; | ||||
| #endif | ||||
| 
 | ||||
| FailGetConfDescr: | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         NotifyFailGetConfDescr(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef DEBUG_USB_HOST | ||||
| Fail: | ||||
|         NotifyFail(rcode); | ||||
| #endif | ||||
|         Release(); | ||||
|         return rcode; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param conf | ||||
|  * @param iface | ||||
|  * @param alt | ||||
|  * @param proto | ||||
|  * @param pep | ||||
|  */ | ||||
| void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR * pep) { | ||||
|         ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf); | ||||
|         ErrorMessage<uint8_t > (PSTR("Iface Num"), iface); | ||||
|         ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt); | ||||
| 
 | ||||
|         bConfNum = conf; | ||||
| 
 | ||||
|         uint8_t index; | ||||
| 
 | ||||
| #if 1 | ||||
|         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; | ||||
|                 epInfo[index].epAttribs = 0; | ||||
| 
 | ||||
|                 bNumEP++; | ||||
| 
 | ||||
|                 PrintEndpointDescriptor(pep); | ||||
| 
 | ||||
|         } | ||||
| #else | ||||
|         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); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::Release() { | ||||
|         ClearAllEP(); | ||||
|         pUsb->GetAddressPool().FreeAddress(bAddress); | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return true if LUN is ready for use. | ||||
|  */ | ||||
| boolean BulkOnly::CheckLUN(uint8_t lun) { | ||||
|         uint8_t rcode; | ||||
|         Capacity capacity; | ||||
|         for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0; | ||||
| 
 | ||||
|         rcode = ReadCapacity10(lun, (uint8_t*)capacity.data); | ||||
|         if(rcode) { | ||||
|                 //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
 | ||||
|                 return false; | ||||
|         } | ||||
|         ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun); | ||||
|         for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++) | ||||
|                 D_PrintHex<uint8_t > (capacity.data[i], 0x80); | ||||
|         Notify(PSTR("\r\n\r\n"), 0x80); | ||||
|         // Only 512/1024/2048/4096 are valid values!
 | ||||
|         uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]); | ||||
|         if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) { | ||||
|                 return false; | ||||
|         } | ||||
|         // Store capacity information.
 | ||||
|         CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
 | ||||
| 
 | ||||
|         CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1; | ||||
|         if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) { | ||||
|                 // Buggy firmware will report 0xffffffff or 0 for no media
 | ||||
|                 if(CurrentCapacity[lun]) | ||||
|                         ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun); | ||||
|                 return false; | ||||
|         } | ||||
|         DELAY(20); | ||||
|         Page3F(lun); | ||||
|         if(!TestUnitReady(lun)) return true; | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * Scan for media change on all LUNs | ||||
|  */ | ||||
| void BulkOnly::CheckMedia() { | ||||
|         for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||||
|                 if(TestUnitReady(lun)) { | ||||
|                         LUNOk[lun] = false; | ||||
|                         continue; | ||||
|                 } | ||||
|                 if(!LUNOk[lun]) | ||||
|                         LUNOk[lun] = CheckLUN(lun); | ||||
|         } | ||||
| #if 0 | ||||
|         printf("}}}}}}}}}}}}}}}}STATUS "); | ||||
|         for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||||
|                 if(LUNOk[lun]) | ||||
|                         printf("#"); | ||||
|                 else printf("."); | ||||
|         } | ||||
|         printf("\r\n"); | ||||
| #endif | ||||
|         qNextPollTime = millis() + 2000; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::Poll() { | ||||
|         //uint8_t rcode = 0;
 | ||||
| 
 | ||||
|         if(!bPollEnable) | ||||
|                 return 0; | ||||
| 
 | ||||
|         if((long)(millis() - qNextPollTime) >= 0L) { | ||||
|                 CheckMedia(); | ||||
|         } | ||||
|         //rcode = 0;
 | ||||
| 
 | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| // SCSI code
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param plun | ||||
|  * @return | ||||
|  */ | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. Used during Driver Init | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param bsize | ||||
|  * @param buf | ||||
|  * @return | ||||
|  */ | ||||
| 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); | ||||
| 
 | ||||
|         CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0); | ||||
|         uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN); | ||||
| 
 | ||||
|         return rc; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::TestUnitReady(uint8_t lun) { | ||||
|         //SetCurLUN(lun);
 | ||||
|         if(!bAddress) | ||||
|                 return MASS_ERR_UNIT_NOT_READY; | ||||
| 
 | ||||
|         Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80); | ||||
|         Notify(PSTR("-----------------\r\n"), 0x80); | ||||
| 
 | ||||
|         CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0); | ||||
|         return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param pc | ||||
|  * @param page | ||||
|  * @param subpage | ||||
|  * @param len | ||||
|  * @param pbuf | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::ModeSense6(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); | ||||
| 
 | ||||
|         CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0); | ||||
|         return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param bsize | ||||
|  * @param buf | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) { | ||||
|         Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); | ||||
|         Notify(PSTR("---------------\r\n"), 0x80); | ||||
| 
 | ||||
|         CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun); | ||||
|         return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * Page 3F contains write protect status. | ||||
|  * | ||||
|  * @param lun Logical Unit Number to test. | ||||
|  * @return Write protect switch status. | ||||
|  */ | ||||
| uint8_t BulkOnly::Page3F(uint8_t lun) { | ||||
|         uint8_t buf[192]; | ||||
|         for(int i = 0; i < 192; i++) { | ||||
|                 buf[i] = 0x00; | ||||
|         } | ||||
|         WriteOk[lun] = true; | ||||
| #if SKIP_WRITE_PROTECT | ||||
|         return 0; | ||||
| #else  // SKIP_WRITE_PROTECT
 | ||||
|         uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf); | ||||
|         if(!rc) { | ||||
|                 WriteOk[lun] = ((buf[2] & 0x80) == 0); | ||||
|                 Notify(PSTR("Mode Sense: "), 0x80); | ||||
|                 for(int i = 0; i < 4; i++) { | ||||
|                         D_PrintHex<uint8_t > (buf[i], 0x80); | ||||
|                         Notify(PSTR(" "), 0x80); | ||||
|                 } | ||||
|                 Notify(PSTR("\r\n"), 0x80); | ||||
|         } | ||||
|         return rc; | ||||
| #endif  // SKIP_WRITE_PROTECT
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @param size | ||||
|  * @param buf | ||||
|  * @return | ||||
|  */ | ||||
| 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); | ||||
| 
 | ||||
|         CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0); | ||||
|         CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN); | ||||
|         //SetCurLUN(lun);
 | ||||
|         return Transaction(&cbw, size, buf); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| // USB code
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param index | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::ClearEpHalt(uint8_t index) { | ||||
|         if(index == 0) | ||||
|                 return 0; | ||||
| 
 | ||||
|         uint8_t ret = 0; | ||||
| 
 | ||||
|         while((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)) == 0x01)) | ||||
|                 DELAY(6); | ||||
| 
 | ||||
|         if(ret) { | ||||
|                 ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret); | ||||
|                 ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr)); | ||||
|                 return ret; | ||||
|         } | ||||
|         epInfo[index].bmSndToggle = 0; | ||||
|         epInfo[index].bmRcvToggle = 0; | ||||
|         // epAttribs = 0;
 | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  */ | ||||
| void BulkOnly::Reset() { | ||||
|         while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) DELAY(6); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @return 0 if successful | ||||
|  */ | ||||
| uint8_t BulkOnly::ResetRecovery() { | ||||
|         Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); | ||||
|         Notify(PSTR("-----------------\r\n"), 0x80); | ||||
| 
 | ||||
|         DELAY(6); | ||||
|         Reset(); | ||||
|         DELAY(6); | ||||
|         ClearEpHalt(epDataInIndex); | ||||
|         DELAY(6); | ||||
|         bLastUsbError = ClearEpHalt(epDataOutIndex); | ||||
|         DELAY(6); | ||||
|         return bLastUsbError; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * Clear all EP data and clear all LUN status | ||||
|  */ | ||||
| void BulkOnly::ClearAllEP() { | ||||
|         for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { | ||||
|                 epInfo[i].epAddr = 0; | ||||
|                 epInfo[i].maxPktSize = (i) ? 0 : 8; | ||||
|                 epInfo[i].epAttribs = 0; | ||||
| 
 | ||||
|                 epInfo[i].bmNakPower = USB_NAK_DEFAULT; | ||||
|         } | ||||
| 
 | ||||
|         for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) { | ||||
|                 LUNOk[i] = false; | ||||
|                 WriteOk[i] = false; | ||||
|                 CurrentCapacity[i] = 0lu; | ||||
|                 CurrentSectorSize[i] = 0; | ||||
|         } | ||||
| 
 | ||||
|         bIface = 0; | ||||
|         bNumEP = 1; | ||||
|         bAddress = 0; | ||||
|         qNextPollTime = 0; | ||||
|         bPollEnable = false; | ||||
|         bLastUsbError = 0; | ||||
|         bMaxLUN = 0; | ||||
|         bTheLUN = 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param pcsw | ||||
|  * @param pcbw | ||||
|  * @return | ||||
|  */ | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param error | ||||
|  * @param index | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { | ||||
|         uint8_t count = 3; | ||||
| 
 | ||||
|         bLastUsbError = error; | ||||
|         //if (error)
 | ||||
|         //ClearEpHalt(index);
 | ||||
|         while(error && count) { | ||||
|                 if(error != hrSUCCESS) { | ||||
|                         ErrorMessage<uint8_t > (PSTR("USB Error"), error); | ||||
|                         ErrorMessage<uint8_t > (PSTR("Index"), index); | ||||
|                 } | ||||
|                 switch(error) { | ||||
|                                 // case hrWRONGPID:
 | ||||
|                         case hrSUCCESS: | ||||
|                                 return MASS_ERR_SUCCESS; | ||||
|                         case hrBUSY: | ||||
|                                 // SIE is busy, just hang out and try again.
 | ||||
|                                 return MASS_ERR_UNIT_BUSY; | ||||
|                         case hrTIMEOUT: | ||||
|                         case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; | ||||
|                         case hrSTALL: | ||||
|                                 if(index == 0) | ||||
|                                         return MASS_ERR_STALL; | ||||
|                                 ClearEpHalt(index); | ||||
|                                 if(index != epDataInIndex) | ||||
|                                         return MASS_ERR_WRITE_STALL; | ||||
|                                 return MASS_ERR_STALL; | ||||
| 
 | ||||
|                         case hrNAK: | ||||
|                                 if(index == 0) | ||||
|                                         return MASS_ERR_UNIT_BUSY; | ||||
|                                 return MASS_ERR_UNIT_BUSY; | ||||
| 
 | ||||
|                         case hrTOGERR: | ||||
|                                 // Handle a very super rare corner case, where toggles become de-synched.
 | ||||
|                                 // I have only ran into one device that has this firmware bug, and this is
 | ||||
|                                 // the only clean way to get back into sync with the buggy device firmware.
 | ||||
|                                 //   --AJK
 | ||||
|                                 if(bAddress && bConfNum) { | ||||
|                                         error = pUsb->setConf(bAddress, 0, bConfNum); | ||||
| 
 | ||||
|                                         if(error) | ||||
|                                                 break; | ||||
|                                 } | ||||
|                                 return MASS_ERR_SUCCESS; | ||||
|                         default: | ||||
|                                 ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error); | ||||
|                                 return MASS_ERR_GENERAL_USB_ERROR; | ||||
|                 } | ||||
|                 count--; | ||||
|         } // while
 | ||||
| 
 | ||||
|         return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); | ||||
| } | ||||
| 
 | ||||
| #if MS_WANT_PARSER | ||||
| 
 | ||||
| uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) { | ||||
|         return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param pcbw | ||||
|  * @param buf_size | ||||
|  * @param buf | ||||
|  * @param flags | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf | ||||
| #if MS_WANT_PARSER | ||||
|         , uint8_t flags | ||||
| #endif | ||||
|         ) { | ||||
| 
 | ||||
| #if MS_WANT_PARSER | ||||
|         uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; | ||||
|         printf("Transfersize %i\r\n", bytes); | ||||
|         DELAY(1000); | ||||
| 
 | ||||
|         boolean callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; | ||||
| #else | ||||
|         uint16_t bytes = buf_size; | ||||
| #endif | ||||
|         boolean write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; | ||||
|         uint8_t ret = 0; | ||||
|         uint8_t usberr; | ||||
|         CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
 | ||||
|         SetCurLUN(pcbw->bmCBWLUN); | ||||
|         ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); | ||||
| 
 | ||||
|         while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) DELAY(1); | ||||
| 
 | ||||
|         ret = HandleUsbError(usberr, epDataOutIndex); | ||||
|         //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
 | ||||
|         if(ret) { | ||||
|                 ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret); | ||||
|         } else { | ||||
|                 if(bytes) { | ||||
|                         if(!write) { | ||||
| #if MS_WANT_PARSER | ||||
|                                 if(callback) { | ||||
|                                         uint8_t rbuf[bytes]; | ||||
|                                         while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) DELAY(1); | ||||
|                                         if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); | ||||
|                                 } else { | ||||
| #endif | ||||
|                                         while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) DELAY(1); | ||||
| #if MS_WANT_PARSER | ||||
| 
 | ||||
|                                 } | ||||
| #endif | ||||
|                                 ret = HandleUsbError(usberr, epDataInIndex); | ||||
|                         } else { | ||||
|                                 while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) DELAY(1); | ||||
|                                 ret = HandleUsbError(usberr, epDataOutIndex); | ||||
|                         } | ||||
|                         if(ret) { | ||||
|                                 ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret); | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|                 bytes = sizeof (CommandStatusWrapper); | ||||
|                 int tries = 2; | ||||
|                 while(tries--) { | ||||
|                         while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) DELAY(1); | ||||
|                         if(!usberr) break; | ||||
|                         ClearEpHalt(epDataInIndex); | ||||
|                         if(tries) ResetRecovery(); | ||||
|                 } | ||||
|                 if(!ret) { | ||||
|                         Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); | ||||
|                         Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); | ||||
|                 } else { | ||||
|                         // Throw away csw, IT IS NOT OF ANY USE.
 | ||||
|                         ResetRecovery(); | ||||
|                         return ret; | ||||
|                 } | ||||
|                 ret = HandleUsbError(usberr, epDataInIndex); | ||||
|                 if(ret) { | ||||
|                         ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret); | ||||
|                 } | ||||
|                 if(usberr == hrSUCCESS) { | ||||
|                         if(IsValidCSW(&csw, pcbw)) { | ||||
|                                 //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
 | ||||
|                                 //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
 | ||||
|                                 //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
 | ||||
|                                 Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); | ||||
|                                 return csw.bCSWStatus; | ||||
|                         } else { | ||||
|                                 // NOTE! Sometimes this is caused by the reported residue being wrong.
 | ||||
|                                 // Get a different device. It isn't compliant, and should have never passed Q&A.
 | ||||
|                                 // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
 | ||||
|                                 // Other devices that exhibit this behavior exist in the wild too.
 | ||||
|                                 // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
 | ||||
|                                 Notify(PSTR("Invalid CSW\r\n"), 0x80); | ||||
|                                 ResetRecovery(); | ||||
|                                 //return MASS_ERR_SUCCESS;
 | ||||
|                                 return MASS_ERR_INVALID_CSW; | ||||
|                         } | ||||
|                 } | ||||
|         } | ||||
|         return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param lun Logical Unit Number | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::SetCurLUN(uint8_t lun) { | ||||
|         if(lun > bMaxLUN) | ||||
|                 return MASS_ERR_INVALID_LUN; | ||||
|         bTheLUN = lun; | ||||
|         return MASS_ERR_SUCCESS; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * For driver use only. | ||||
|  * | ||||
|  * @param status | ||||
|  * @return | ||||
|  */ | ||||
| uint8_t BulkOnly::HandleSCSIError(uint8_t status) { | ||||
|         uint8_t ret = 0; | ||||
| 
 | ||||
|         switch(status) { | ||||
|                 case 0: return MASS_ERR_SUCCESS; | ||||
| 
 | ||||
|                 case 2: | ||||
|                         ErrorMessage<uint8_t > (PSTR("Phase Error"), status); | ||||
|                         ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||||
|                         ResetRecovery(); | ||||
|                         return MASS_ERR_GENERAL_SCSI_ERROR; | ||||
| 
 | ||||
|                 case 1: | ||||
|                         ErrorMessage<uint8_t > (PSTR("SCSI Error"), status); | ||||
|                         ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||||
|                         RequestSenseResponce rsp; | ||||
| 
 | ||||
|                         ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); | ||||
| 
 | ||||
|                         if(ret) { | ||||
|                                 return MASS_ERR_GENERAL_SCSI_ERROR; | ||||
|                         } | ||||
|                         ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode); | ||||
|                         if(rsp.bResponseCode & 0x80) { | ||||
|                                 Notify(PSTR("Information field: "), 0x80); | ||||
|                                 for(int i = 0; i < 4; i++) { | ||||
|                                         D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80); | ||||
|                                         Notify(PSTR(" "), 0x80); | ||||
|                                 } | ||||
|                                 Notify(PSTR("\r\n"), 0x80); | ||||
|                         } | ||||
|                         ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey); | ||||
|                         ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); | ||||
|                         ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); | ||||
|                         // warning, this is not testing ASQ, only SK and ASC.
 | ||||
|                         switch(rsp.bmSenseKey) { | ||||
|                                 case SCSI_S_UNIT_ATTENTION: | ||||
|                                         switch(rsp.bAdditionalSenseCode) { | ||||
|                                                 case SCSI_ASC_MEDIA_CHANGED: | ||||
|                                                         return MASS_ERR_MEDIA_CHANGED; | ||||
|                                                 default: | ||||
|                                                         return MASS_ERR_UNIT_NOT_READY; | ||||
|                                         } | ||||
|                                 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; | ||||
|                         } | ||||
| 
 | ||||
|                         // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
 | ||||
|                         //    case 0x05/0x14: we stalled out
 | ||||
|                         //    case 0x15/0x16: we naked out.
 | ||||
|                 default: | ||||
|                         ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status); | ||||
|                         ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||||
|                         return status; | ||||
|         } // switch
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| // Debugging code
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /**
 | ||||
|  * | ||||
|  * @param ep_ptr | ||||
|  */ | ||||
| void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) { | ||||
|         Notify(PSTR("Endpoint descriptor:"), 0x80); | ||||
|         Notify(PSTR("\r\nLength:\t\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); | ||||
|         Notify(PSTR("\r\nType:\t\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); | ||||
|         Notify(PSTR("\r\nAddress:\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); | ||||
|         Notify(PSTR("\r\nAttributes:\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); | ||||
|         Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); | ||||
|         D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); | ||||
|         Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); | ||||
|         D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); | ||||
|         Notify(PSTR("\r\n"), 0x80); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| // misc/to kill/to-do
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /* 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 MS_WANT_PARSER | ||||
|         if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||||
|         Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); | ||||
|         Notify(PSTR("---------\r\n"), 0x80); | ||||
| 
 | ||||
|         CommandBlockWrapper cbw = CommandBlockWrapper(); | ||||
| 
 | ||||
|         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; | ||||
| 
 | ||||
|         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)); | ||||
| #else | ||||
|         return MASS_ERR_NOT_IMPLEMENTED; | ||||
| #endif | ||||
| } | ||||
| @ -0,0 +1,571 @@ | ||||
| /* 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(__MASSTORAGE_H__) | ||||
| #define __MASSTORAGE_H__ | ||||
| 
 | ||||
| // Cruft removal, makes driver smaller, faster.
 | ||||
| #ifndef MS_WANT_PARSER | ||||
| #define MS_WANT_PARSER 0 | ||||
| #endif | ||||
| 
 | ||||
| #include "Usb.h" | ||||
| 
 | ||||
| #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 // (0 << 7)
 | ||||
| #define MASS_CMD_DIR_IN			0x80 //(1 << 7)
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Reference documents from T10 (http://www.t10.org)
 | ||||
|  * SCSI Primary Commands - 3 (SPC-3) | ||||
|  * SCSI Block Commands - 2 (SBC-2) | ||||
|  * Multi-Media Commands - 5 (MMC-5) | ||||
|  */ | ||||
| 
 | ||||
| /* Group 1 commands (CDB's here are should all be 6-bytes) */ | ||||
| #define SCSI_CMD_TEST_UNIT_READY	0x00 | ||||
| #define SCSI_CMD_REQUEST_SENSE		0x03 | ||||
| #define SCSI_CMD_FORMAT_UNIT		0x04 | ||||
| #define SCSI_CMD_READ_6			0x08 | ||||
| #define SCSI_CMD_WRITE_6		0x0A | ||||
| #define SCSI_CMD_INQUIRY		0x12 | ||||
| #define SCSI_CMD_MODE_SELECT_6          0x15 | ||||
| #define SCSI_CMD_MODE_SENSE_6		0x1A | ||||
| #define SCSI_CMD_START_STOP_UNIT	0x1B | ||||
| #define SCSI_CMD_PREVENT_REMOVAL        0x1E | ||||
| /* Group 2 Commands (CDB's here are 10-bytes) */ | ||||
| #define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 | ||||
| #define SCSI_CMD_READ_CAPACITY_10	0x25 | ||||
| #define SCSI_CMD_READ_10		0x28 | ||||
| #define SCSI_CMD_WRITE_10		0x2A | ||||
| #define SCSI_CMD_SEEK_10                0x2B | ||||
| #define SCSI_CMD_ERASE_10               0x2C | ||||
| #define SCSI_CMD_WRITE_AND_VERIFY_10    0x2E | ||||
| #define SCSI_CMD_VERIFY_10              0x2F | ||||
| #define SCSI_CMD_SYNCHRONIZE_CACHE      0x35 | ||||
| #define SCSI_CMD_WRITE_BUFFER           0x3B | ||||
| #define SCSI_CMD_READ_BUFFER            0x3C | ||||
| #define SCSI_CMD_READ_SUBCHANNEL        0x42 | ||||
| #define SCSI_CMD_READ_TOC               0x43 | ||||
| #define SCSI_CMD_READ_HEADER            0x44 | ||||
| #define SCSI_CMD_PLAY_AUDIO_10          0x45 | ||||
| #define SCSI_CMD_GET_CONFIGURATION      0x46 | ||||
| #define SCSI_CMD_PLAY_AUDIO_MSF         0x47 | ||||
| #define SCSI_CMD_PLAY_AUDIO_TI          0x48 | ||||
| #define SCSI_CMD_PLAY_TRACK_REL_10      0x49 | ||||
| #define SCSI_CMD_GET_EVENT_STATUS       0x4A | ||||
| #define SCSI_CMD_PAUSE_RESUME           0x4B | ||||
| #define SCSI_CMD_READ_DISC_INFORMATION  0x51 | ||||
| #define SCSI_CMD_READ_TRACK_INFORMATION 0x52 | ||||
| #define SCSI_CMD_RESERVE_TRACK          0x53 | ||||
| #define SCSI_CMD_SEND_OPC_INFORMATION   0x54 | ||||
| #define SCSI_CMD_MODE_SELECT_10         0x55 | ||||
| #define SCSI_CMD_REPAIR_TRACK           0x58 | ||||
| #define SCSI_CMD_MODE_SENSE_10          0x5A | ||||
| #define SCSI_CMD_CLOSE_TRACK_SESSION    0x5B | ||||
| #define SCSI_CMD_READ_BUFFER_CAPACITY   0x5C | ||||
| #define SCSI_CMD_SEND_CUE_SHEET         0x5D | ||||
| /* Group 5 Commands (CDB's here are 12-bytes) */ | ||||
| #define SCSI_CMD_REPORT_LUNS            0xA0 | ||||
| #define SCSI_CMD_BLANK                  0xA1 | ||||
| #define SCSI_CMD_SECURITY_PROTOCOL_IN   0xA2 | ||||
| #define SCSI_CMD_SEND_KEY               0xA3 | ||||
| #define SCSI_CMD_REPORT_KEY             0xA4 | ||||
| #define SCSI_CMD_PLAY_AUDIO_12          0xA5 | ||||
| #define SCSI_CMD_LOAD_UNLOAD            0xA6 | ||||
| #define SCSI_CMD_SET_READ_AHEAD         0xA7 | ||||
| #define SCSI_CMD_READ_12                0xA8 | ||||
| #define SCSI_CMD_PLAY_TRACK_REL_12      0xA9 | ||||
| #define SCSI_CMD_WRITE_12               0xAA | ||||
| #define SCSI_CMD_READ_MEDIA_SERIAL_12   0xAB | ||||
| #define SCSI_CMD_GET_PERFORMANCE        0xAC | ||||
| #define SCSI_CMD_READ_DVD_STRUCTURE     0xAD | ||||
| #define SCSI_CMD_SECURITY_PROTOCOL_OUT  0xB5 | ||||
| #define SCSI_CMD_SET_STREAMING          0xB6 | ||||
| #define SCSI_CMD_READ_MSF               0xB9 | ||||
| #define SCSI_CMD_SET_SPEED              0xBB | ||||
| #define SCSI_CMD_MECHANISM_STATUS       0xBD | ||||
| #define SCSI_CMD_READ_CD                0xBE | ||||
| #define SCSI_CMD_SEND_DISC_STRUCTURE    0xBF | ||||
| /* Vendor-unique Commands, included for completeness */ | ||||
| #define SCSI_CMD_CD_PLAYBACK_STATUS     0xC4 /* SONY unique */ | ||||
| #define SCSI_CMD_PLAYBACK_CONTROL       0xC9 /* SONY unique */ | ||||
| #define SCSI_CMD_READ_CDDA              0xD8 /* Vendor unique */ | ||||
| #define SCSI_CMD_READ_CDXA              0xDB /* Vendor unique */ | ||||
| #define SCSI_CMD_READ_ALL_SUBCODES      0xDF /* Vendor unique */ | ||||
| 
 | ||||
| /* SCSI error codes */ | ||||
| #define SCSI_S_NOT_READY		0x02 | ||||
| #define SCSI_S_MEDIUM_ERROR		0x03 | ||||
| #define SCSI_S_ILLEGAL_REQUEST		0x05 | ||||
| #define SCSI_S_UNIT_ATTENTION		0x06 | ||||
| #define SCSI_ASC_LBA_OUT_OF_RANGE       0x21 | ||||
| #define SCSI_ASC_MEDIA_CHANGED          0x28 | ||||
| #define SCSI_ASC_MEDIUM_NOT_PRESENT     0x3A | ||||
| 
 | ||||
| /* USB error codes */ | ||||
| #define MASS_ERR_SUCCESS		0x00 | ||||
| #define MASS_ERR_PHASE_ERROR		0x02 | ||||
| #define MASS_ERR_UNIT_NOT_READY		0x03 | ||||
| #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_MEDIA_CHANGED          0x0A | ||||
| #define MASS_ERR_DEVICE_DISCONNECTED    0x11 | ||||
| #define MASS_ERR_UNABLE_TO_RECOVER	0x12	// Reset recovery error
 | ||||
| #define MASS_ERR_INVALID_LUN		0x13 | ||||
| #define MASS_ERR_WRITE_STALL    	0x14 | ||||
| #define MASS_ERR_READ_NAKS              0x15 | ||||
| #define MASS_ERR_WRITE_NAKS             0x16 | ||||
| #define MASS_ERR_WRITE_PROTECTED        0x17 | ||||
| #define MASS_ERR_NOT_IMPLEMENTED        0xFD | ||||
| #define MASS_ERR_GENERAL_SCSI_ERROR	0xFE | ||||
| #define MASS_ERR_GENERAL_USB_ERROR	0xFF | ||||
| #define MASS_ERR_USER			0xA0	// For subclasses to define their own error codes
 | ||||
| 
 | ||||
| #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
 | ||||
| 
 | ||||
| #define MASS_MAX_ENDPOINTS		3 | ||||
| 
 | ||||
| struct Capacity { | ||||
|         uint8_t data[8]; | ||||
|         //uint32_t dwBlockAddress;
 | ||||
|         //uint32_t dwBlockLength;
 | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct BASICCDB { | ||||
|         uint8_t Opcode; | ||||
| 
 | ||||
|         unsigned unused : 5; | ||||
|         unsigned LUN : 3; | ||||
| 
 | ||||
|         uint8_t info[12]; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| typedef BASICCDB BASICCDB_t; | ||||
| 
 | ||||
| struct CDB6 { | ||||
|         uint8_t Opcode; | ||||
| 
 | ||||
|         unsigned LBAMSB : 5; | ||||
|         unsigned LUN : 3; | ||||
| 
 | ||||
|         uint8_t LBAHB; | ||||
|         uint8_t LBALB; | ||||
|         uint8_t AllocationLength; | ||||
|         uint8_t Control; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|         CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) : | ||||
|         Opcode(_Opcode), LBAMSB(BGRAB2(LBA) & 0x1f), LUN(_LUN), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)), | ||||
|         AllocationLength(_AllocationLength), Control(_Control) { | ||||
|         } | ||||
| 
 | ||||
|         CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) : | ||||
|         Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0), | ||||
|         AllocationLength(_AllocationLength), Control(_Control) { | ||||
|         } | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| typedef CDB6 CDB6_t; | ||||
| 
 | ||||
| struct CDB10 { | ||||
|         uint8_t Opcode; | ||||
| 
 | ||||
|         unsigned Service_Action : 5; | ||||
|         unsigned LUN : 3; | ||||
| 
 | ||||
|         uint8_t LBA_L_M_MB; | ||||
|         uint8_t LBA_L_M_LB; | ||||
|         uint8_t LBA_L_L_MB; | ||||
|         uint8_t LBA_L_L_LB; | ||||
| 
 | ||||
|         uint8_t Misc2; | ||||
| 
 | ||||
|         uint8_t ALC_MB; | ||||
|         uint8_t ALC_LB; | ||||
| 
 | ||||
|         uint8_t Control; | ||||
| public: | ||||
| 
 | ||||
|         CDB10(uint8_t _Opcode, uint8_t _LUN) : | ||||
|         Opcode(_Opcode), Service_Action(0), LUN(_LUN), | ||||
|         LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0), | ||||
|         Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) { | ||||
|         } | ||||
| 
 | ||||
|         CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) : | ||||
|         Opcode(_Opcode), Service_Action(0), LUN(_LUN), | ||||
|         LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)), | ||||
|         Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) { | ||||
|         } | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| typedef CDB10 CDB10_t; | ||||
| 
 | ||||
| struct CDB12 { | ||||
|         uint8_t Opcode; | ||||
| 
 | ||||
|         unsigned Service_Action : 5; | ||||
|         unsigned Misc : 3; | ||||
| 
 | ||||
|         uint8_t LBA_L_M_LB; | ||||
|         uint8_t LBA_L_L_MB; | ||||
|         uint8_t LBA_L_L_LB; | ||||
| 
 | ||||
|         uint8_t ALC_M_LB; | ||||
|         uint8_t ALC_L_MB; | ||||
|         uint8_t ALC_L_LB; | ||||
|         uint8_t Control; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| typedef CDB12 CDB12_t; | ||||
| 
 | ||||
| struct CDB_LBA32_16 { | ||||
|         uint8_t Opcode; | ||||
| 
 | ||||
|         unsigned Service_Action : 5; | ||||
|         unsigned Misc : 3; | ||||
| 
 | ||||
|         uint8_t LBA_L_M_MB; | ||||
|         uint8_t LBA_L_M_LB; | ||||
|         uint8_t LBA_L_L_MB; | ||||
|         uint8_t LBA_L_L_LB; | ||||
| 
 | ||||
|         uint8_t A_M_M_MB; | ||||
|         uint8_t A_M_M_LB; | ||||
|         uint8_t A_M_L_MB; | ||||
|         uint8_t A_M_L_LB; | ||||
| 
 | ||||
|         uint8_t ALC_M_MB; | ||||
|         uint8_t ALC_M_LB; | ||||
|         uint8_t ALC_L_MB; | ||||
|         uint8_t ALC_L_LB; | ||||
| 
 | ||||
|         uint8_t Misc2; | ||||
|         uint8_t Control; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct CDB_LBA64_16 { | ||||
|         uint8_t Opcode; | ||||
|         uint8_t Misc; | ||||
| 
 | ||||
|         uint8_t LBA_M_M_MB; | ||||
|         uint8_t LBA_M_M_LB; | ||||
|         uint8_t LBA_M_L_MB; | ||||
|         uint8_t LBA_M_L_LB; | ||||
| 
 | ||||
|         uint8_t LBA_L_M_MB; | ||||
|         uint8_t LBA_L_M_LB; | ||||
|         uint8_t LBA_L_L_MB; | ||||
|         uint8_t LBA_L_L_LB; | ||||
| 
 | ||||
|         uint8_t ALC_M_MB; | ||||
|         uint8_t ALC_M_LB; | ||||
|         uint8_t ALC_L_MB; | ||||
|         uint8_t ALC_L_LB; | ||||
| 
 | ||||
|         uint8_t Misc2; | ||||
|         uint8_t Control; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct InquiryResponse { | ||||
|         uint8_t DeviceType : 5; | ||||
|         uint8_t PeripheralQualifier : 3; | ||||
| 
 | ||||
|         unsigned Reserved : 7; | ||||
|         unsigned Removable : 1; | ||||
| 
 | ||||
|         uint8_t Version; | ||||
| 
 | ||||
|         unsigned ResponseDataFormat : 4; | ||||
|         unsigned HISUP : 1; | ||||
|         unsigned NormACA : 1; | ||||
|         unsigned TrmTsk : 1; | ||||
|         unsigned AERC : 1; | ||||
| 
 | ||||
|         uint8_t AdditionalLength; | ||||
|         //uint8_t Reserved3[2];
 | ||||
| 
 | ||||
|         unsigned PROTECT : 1; | ||||
|         unsigned Res : 2; | ||||
|         unsigned ThreePC : 1; | ||||
|         unsigned TPGS : 2; | ||||
|         unsigned ACC : 1; | ||||
|         unsigned SCCS : 1; | ||||
| 
 | ||||
|         unsigned ADDR16 : 1; | ||||
|         unsigned R1 : 1; | ||||
|         unsigned R2 : 1; | ||||
|         unsigned MCHNGR : 1; | ||||
|         unsigned MULTIP : 1; | ||||
|         unsigned VS : 1; | ||||
|         unsigned ENCSERV : 1; | ||||
|         unsigned BQUE : 1; | ||||
| 
 | ||||
|         unsigned SoftReset : 1; | ||||
|         unsigned CmdQue : 1; | ||||
|         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; | ||||
| public: | ||||
| 
 | ||||
|         CommandBlockWrapperBase() { | ||||
|         } | ||||
| 
 | ||||
|         CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) : | ||||
|         dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) { | ||||
|         } | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct CommandBlockWrapper : public CommandBlockWrapperBase { | ||||
| 
 | ||||
|         struct { | ||||
|                 uint8_t bmCBWLUN : 4; | ||||
|                 uint8_t bmReserved1 : 4; | ||||
|         }; | ||||
| 
 | ||||
|         struct { | ||||
|                 uint8_t bmCBWCBLength : 4; | ||||
|                 uint8_t bmReserved2 : 4; | ||||
|         }; | ||||
| 
 | ||||
|         uint8_t CBWCB[16]; | ||||
| 
 | ||||
| public: | ||||
|         // All zeroed.
 | ||||
| 
 | ||||
|         CommandBlockWrapper() : | ||||
|         CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) { | ||||
|                 for(int i = 0; i < 16; i++) CBWCB[i] = 0; | ||||
|         } | ||||
| 
 | ||||
|         // Generic Wrap, CDB zeroed.
 | ||||
| 
 | ||||
|         CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) : | ||||
|         CommandBlockWrapperBase(tag, xflen, flgs), | ||||
|         bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) { | ||||
|                 for(int i = 0; i < 16; i++) CBWCB[i] = 0; | ||||
|                 // Type punning can cause optimization problems and bugs.
 | ||||
|                 // Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
 | ||||
|                 //(((BASICCDB_t *) CBWCB)->LUN) = cmd;
 | ||||
|                 BASICCDB_t *x = reinterpret_cast<BASICCDB_t *>(CBWCB); | ||||
|                 x->LUN = cmd; | ||||
|         } | ||||
| 
 | ||||
|         // Wrap for CDB of 6
 | ||||
| 
 | ||||
|         CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) : | ||||
|         CommandBlockWrapperBase(tag, xflen, dir), | ||||
|         bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) { | ||||
|                 memcpy(&CBWCB, cdb, 6); | ||||
|         } | ||||
|         // Wrap for CDB of 10
 | ||||
| 
 | ||||
|         CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) : | ||||
|         CommandBlockWrapperBase(tag, xflen, dir), | ||||
|         bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) { | ||||
|                 memcpy(&CBWCB, cdb, 10); | ||||
|         } | ||||
| } __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)); | ||||
| 
 | ||||
| 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
 | ||||
|         uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
 | ||||
|         uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
 | ||||
|         bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
 | ||||
|         bool WriteOk[MASS_MAX_SUPPORTED_LUN]; | ||||
|         void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); | ||||
| 
 | ||||
| 
 | ||||
|         // Additional Initialization Method for Subclasses
 | ||||
| 
 | ||||
|         virtual uint8_t OnInit() { | ||||
|                 return 0; | ||||
|         }; | ||||
| public: | ||||
|         BulkOnly(USB *p); | ||||
| 
 | ||||
|         uint8_t GetLastUsbError() { | ||||
|                 return bLastUsbError; | ||||
|         }; | ||||
| 
 | ||||
|         uint8_t GetbMaxLUN() { | ||||
|                 return bMaxLUN; // Max LUN
 | ||||
|         } | ||||
| 
 | ||||
|         uint8_t GetbTheLUN() { | ||||
|                 return bTheLUN; // Active LUN
 | ||||
|         } | ||||
| 
 | ||||
|         boolean WriteProtected(uint8_t lun); | ||||
|         uint8_t MediaCTL(uint8_t lun, uint8_t ctl); | ||||
|         uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf); | ||||
|         uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs); | ||||
|         uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf); | ||||
|         uint8_t LockMedia(uint8_t lun, uint8_t lock); | ||||
| 
 | ||||
|         bool LUNIsGood(uint8_t lun); | ||||
|         uint32_t GetCapacity(uint8_t lun); | ||||
|         uint16_t GetSectorSize(uint8_t lun); | ||||
| 
 | ||||
|         // USBDeviceConfig implementation
 | ||||
|         virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); | ||||
|         virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed); | ||||
| 
 | ||||
|         virtual uint8_t Release(); | ||||
|         virtual uint8_t Poll(); | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|         virtual boolean DEVCLASSOK(uint8_t klass) { | ||||
|                 return (klass == USB_CLASS_MASS_STORAGE); | ||||
|         } | ||||
| 
 | ||||
|         uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); | ||||
|         uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); | ||||
| 
 | ||||
| private: | ||||
|         uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf); | ||||
|         uint8_t TestUnitReady(uint8_t lun); | ||||
|         uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf); | ||||
|         uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf); | ||||
|         uint8_t GetMaxLUN(uint8_t *max_lun); | ||||
|         uint8_t SetCurLUN(uint8_t lun); | ||||
|         void Reset(); | ||||
|         uint8_t ResetRecovery(); | ||||
|         uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf); | ||||
|         void ClearAllEP(); | ||||
|         void CheckMedia(); | ||||
|         boolean CheckLUN(uint8_t lun); | ||||
|         uint8_t Page3F(uint8_t lun); | ||||
|         bool IsValidCBW(uint8_t size, uint8_t *pcbw); | ||||
|         bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw); | ||||
| 
 | ||||
|         bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw); | ||||
| 
 | ||||
|         uint8_t ClearEpHalt(uint8_t index); | ||||
| #if MS_WANT_PARSER | ||||
|         uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags); | ||||
| #endif | ||||
|         uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf); | ||||
|         uint8_t HandleUsbError(uint8_t error, uint8_t index); | ||||
|         uint8_t HandleSCSIError(uint8_t status); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif // __MASSTORAGE_H__
 | ||||
| @ -0,0 +1,233 @@ | ||||
| /* 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(_usb_h_) || defined(_max3421e_h_) | ||||
| #error "Never include max3421e.h directly; include Usb.h instead" | ||||
| #else | ||||
| 
 | ||||
| #define _max3421e_h_ | ||||
| 
 | ||||
| /* MAX3421E register/bit names and bitmasks */ | ||||
| 
 | ||||
| /* Arduino pin definitions */ | ||||
| /* pin numbers to port numbers */ | ||||
| 
 | ||||
| 
 | ||||
| //#define MAX_INT   9		// Duemielanove
 | ||||
| 
 | ||||
| //#define MAX_GPX   8
 | ||||
| 
 | ||||
| #define SE0     0 | ||||
| #define SE1     1 | ||||
| #define FSHOST  2 | ||||
| #define LSHOST  3 | ||||
| 
 | ||||
| /* MAX3421E command byte format: rrrrr0wa where 'r' is register number  */ | ||||
| //
 | ||||
| // MAX3421E Registers in HOST mode.
 | ||||
| //
 | ||||
| #define rRCVFIFO    0x08    //1<<3
 | ||||
| #define rSNDFIFO    0x10    //2<<3
 | ||||
| #define rSUDFIFO    0x20    //4<<3
 | ||||
| #define rRCVBC      0x30    //6<<3
 | ||||
| #define rSNDBC      0x38    //7<<3
 | ||||
| 
 | ||||
| #define rUSBIRQ     0x68    //13<<3
 | ||||
| /* USBIRQ Bits  */ | ||||
| #define bmVBUSIRQ   0x40    //b6
 | ||||
| #define bmNOVBUSIRQ 0x20    //b5
 | ||||
| #define bmOSCOKIRQ  0x01    //b0
 | ||||
| 
 | ||||
| #define rUSBIEN     0x70    //14<<3
 | ||||
| /* USBIEN Bits  */ | ||||
| #define bmVBUSIE    0x40    //b6
 | ||||
| #define bmNOVBUSIE  0x20    //b5
 | ||||
| #define bmOSCOKIE   0x01    //b0
 | ||||
| 
 | ||||
| #define rUSBCTL     0x78    //15<<3
 | ||||
| /* USBCTL Bits  */ | ||||
| #define bmCHIPRES   0x20    //b5
 | ||||
| #define bmPWRDOWN   0x10    //b4
 | ||||
| 
 | ||||
| #define rCPUCTL     0x80    //16<<3
 | ||||
| /* CPUCTL Bits  */ | ||||
| #define bmPUSLEWID1 0x80    //b7
 | ||||
| #define bmPULSEWID0 0x40    //b6
 | ||||
| #define bmIE        0x01    //b0
 | ||||
| 
 | ||||
| #define rPINCTL     0x88    //17<<3
 | ||||
| /* PINCTL Bits  */ | ||||
| #define bmFDUPSPI   0x10    //b4
 | ||||
| #define bmINTLEVEL  0x08    //b3
 | ||||
| #define bmPOSINT    0x04    //b2
 | ||||
| #define bmGPXB      0x02    //b1
 | ||||
| #define bmGPXA      0x01    //b0
 | ||||
| // GPX pin selections
 | ||||
| #define GPX_OPERATE 0x00 | ||||
| #define GPX_VBDET   0x01 | ||||
| #define GPX_BUSACT  0x02 | ||||
| #define GPX_SOF     0x03 | ||||
| 
 | ||||
| #define rREVISION   0x90    //18<<3
 | ||||
| 
 | ||||
| #define rIOPINS1    0xa0    //20<<3
 | ||||
| 
 | ||||
| /* IOPINS1 Bits */ | ||||
| #define bmGPOUT0    0x01 | ||||
| #define bmGPOUT1    0x02 | ||||
| #define bmGPOUT2    0x04 | ||||
| #define bmGPOUT3    0x08 | ||||
| #define bmGPIN0     0x10 | ||||
| #define bmGPIN1     0x20 | ||||
| #define bmGPIN2     0x40 | ||||
| #define bmGPIN3     0x80 | ||||
| 
 | ||||
| #define rIOPINS2    0xa8    //21<<3
 | ||||
| /* IOPINS2 Bits */ | ||||
| #define bmGPOUT4    0x01 | ||||
| #define bmGPOUT5    0x02 | ||||
| #define bmGPOUT6    0x04 | ||||
| #define bmGPOUT7    0x08 | ||||
| #define bmGPIN4     0x10 | ||||
| #define bmGPIN5     0x20 | ||||
| #define bmGPIN6     0x40 | ||||
| #define bmGPIN7     0x80 | ||||
| 
 | ||||
| #define rGPINIRQ    0xb0    //22<<3
 | ||||
| /* GPINIRQ Bits */ | ||||
| #define bmGPINIRQ0 0x01 | ||||
| #define bmGPINIRQ1 0x02 | ||||
| #define bmGPINIRQ2 0x04 | ||||
| #define bmGPINIRQ3 0x08 | ||||
| #define bmGPINIRQ4 0x10 | ||||
| #define bmGPINIRQ5 0x20 | ||||
| #define bmGPINIRQ6 0x40 | ||||
| #define bmGPINIRQ7 0x80 | ||||
| 
 | ||||
| #define rGPINIEN    0xb8    //23<<3
 | ||||
| /* GPINIEN Bits */ | ||||
| #define bmGPINIEN0 0x01 | ||||
| #define bmGPINIEN1 0x02 | ||||
| #define bmGPINIEN2 0x04 | ||||
| #define bmGPINIEN3 0x08 | ||||
| #define bmGPINIEN4 0x10 | ||||
| #define bmGPINIEN5 0x20 | ||||
| #define bmGPINIEN6 0x40 | ||||
| #define bmGPINIEN7 0x80 | ||||
| 
 | ||||
| #define rGPINPOL    0xc0    //24<<3
 | ||||
| /* GPINPOL Bits */ | ||||
| #define bmGPINPOL0 0x01 | ||||
| #define bmGPINPOL1 0x02 | ||||
| #define bmGPINPOL2 0x04 | ||||
| #define bmGPINPOL3 0x08 | ||||
| #define bmGPINPOL4 0x10 | ||||
| #define bmGPINPOL5 0x20 | ||||
| #define bmGPINPOL6 0x40 | ||||
| #define bmGPINPOL7 0x80 | ||||
| 
 | ||||
| #define rHIRQ       0xc8    //25<<3
 | ||||
| /* HIRQ Bits */ | ||||
| #define bmBUSEVENTIRQ   0x01   // indicates BUS Reset Done or BUS Resume
 | ||||
| #define bmRWUIRQ        0x02 | ||||
| #define bmRCVDAVIRQ     0x04 | ||||
| #define bmSNDBAVIRQ     0x08 | ||||
| #define bmSUSDNIRQ      0x10 | ||||
| #define bmCONDETIRQ     0x20 | ||||
| #define bmFRAMEIRQ      0x40 | ||||
| #define bmHXFRDNIRQ     0x80 | ||||
| 
 | ||||
| #define rHIEN			0xd0    //26<<3
 | ||||
| 
 | ||||
| /* HIEN Bits */ | ||||
| #define bmBUSEVENTIE    0x01 | ||||
| #define bmRWUIE         0x02 | ||||
| #define bmRCVDAVIE      0x04 | ||||
| #define bmSNDBAVIE      0x08 | ||||
| #define bmSUSDNIE       0x10 | ||||
| #define bmCONDETIE      0x20 | ||||
| #define bmFRAMEIE       0x40 | ||||
| #define bmHXFRDNIE      0x80 | ||||
| 
 | ||||
| #define rMODE			0xd8    //27<<3
 | ||||
| 
 | ||||
| /* MODE Bits */ | ||||
| #define bmHOST          0x01 | ||||
| #define bmLOWSPEED      0x02 | ||||
| #define bmHUBPRE        0x04 | ||||
| #define bmSOFKAENAB     0x08 | ||||
| #define bmSEPIRQ        0x10 | ||||
| #define bmDELAYISO      0x20 | ||||
| #define bmDMPULLDN      0x40 | ||||
| #define bmDPPULLDN      0x80 | ||||
| 
 | ||||
| #define rPERADDR    0xe0    //28<<3
 | ||||
| 
 | ||||
| #define rHCTL       0xe8    //29<<3
 | ||||
| /* HCTL Bits */ | ||||
| #define bmBUSRST        0x01 | ||||
| #define bmFRMRST        0x02 | ||||
| #define bmSAMPLEBUS     0x04 | ||||
| #define bmSIGRSM        0x08 | ||||
| #define bmRCVTOG0       0x10 | ||||
| #define bmRCVTOG1       0x20 | ||||
| #define bmSNDTOG0       0x40 | ||||
| #define bmSNDTOG1       0x80 | ||||
| 
 | ||||
| #define rHXFR       0xf0    //30<<3
 | ||||
| /* Host transfer token values for writing the HXFR register (R30)   */ | ||||
| /* OR this bit field with the endpoint number in bits 3:0               */ | ||||
| #define tokSETUP  0x10  // HS=0, ISO=0, OUTNIN=0, SETUP=1
 | ||||
| #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 tokISOIN  0x40  // HS=0, ISO=1, OUTNIN=0, SETUP=0
 | ||||
| #define tokISOOUT 0x60  // HS=0, ISO=1, OUTNIN=1, SETUP=0
 | ||||
| 
 | ||||
| #define rHRSL       0xf8    //31<<3
 | ||||
| 
 | ||||
| /* HRSL Bits */ | ||||
| #define bmRCVTOGRD  0x10 | ||||
| #define bmSNDTOGRD  0x20 | ||||
| #define bmKSTATUS   0x40 | ||||
| #define bmJSTATUS   0x80 | ||||
| #define bmSE0       0x00    //SE0 - disconnect state
 | ||||
| #define bmSE1       0xc0    //SE1 - illegal state
 | ||||
| 
 | ||||
| /* Host error result codes, the 4 LSB's in the HRSL register */ | ||||
| #define hrSUCCESS   0x00 | ||||
| #define hrBUSY      0x01 | ||||
| #define hrBADREQ    0x02 | ||||
| #define hrUNDEF     0x03 | ||||
| #define hrNAK       0x04 | ||||
| #define hrSTALL     0x05 | ||||
| #define hrTOGERR    0x06 | ||||
| #define hrWRONGPID  0x07 | ||||
| #define hrBADBC     0x08 | ||||
| #define hrPIDERR    0x09 | ||||
| #define hrPKTERR    0x0A | ||||
| #define hrCRCERR    0x0B | ||||
| #define hrKERR      0x0C | ||||
| #define hrJERR      0x0D | ||||
| #define hrTIMEOUT   0x0E | ||||
| #define hrBABBLE    0x0F | ||||
| 
 | ||||
| #define MODE_FS_HOST    (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB) | ||||
| #define MODE_LS_HOST    (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB) | ||||
| 
 | ||||
| 
 | ||||
| #endif //_max3421e_h_
 | ||||
| @ -0,0 +1,116 @@ | ||||
| /* 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 "Usb.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 by software
 | ||||
| int UsbDEBUGlvl = 0x80; | ||||
| 
 | ||||
| void E_Notifyc(char c, int lvl) { | ||||
|         if(UsbDEBUGlvl < lvl) return; | ||||
| #if defined(ARDUINO) && ARDUINO >=100 | ||||
|         USB_HOST_SERIAL.print(c); | ||||
| #else | ||||
|         USB_HOST_SERIAL.print(c, BYTE); | ||||
| #endif | ||||
|         //USB_HOST_SERIAL.flush();
 | ||||
| } | ||||
| 
 | ||||
| void E_Notify(char const * msg, int lvl) { | ||||
|         if(UsbDEBUGlvl < lvl) return; | ||||
|         if(!msg) return; | ||||
|         char c; | ||||
| 
 | ||||
|         while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl); | ||||
| } | ||||
| 
 | ||||
| void E_NotifyStr(char const * msg, int lvl) { | ||||
|         if(UsbDEBUGlvl < lvl) return; | ||||
|         if(!msg) return; | ||||
|         char c; | ||||
| 
 | ||||
|         while((c = *msg++)) E_Notifyc(c, lvl); | ||||
| } | ||||
| 
 | ||||
| void E_Notify(uint8_t b, int lvl) { | ||||
|         if(UsbDEBUGlvl < lvl) return; | ||||
| #if defined(ARDUINO) && ARDUINO >=100 | ||||
|         USB_HOST_SERIAL.print(b); | ||||
| #else | ||||
|         USB_HOST_SERIAL.print(b, DEC); | ||||
| #endif | ||||
|         //USB_HOST_SERIAL.flush();
 | ||||
| } | ||||
| 
 | ||||
| void E_Notify(double d, int lvl) { | ||||
|         if(UsbDEBUGlvl < lvl) return; | ||||
|         USB_HOST_SERIAL.print(d); | ||||
|         //USB_HOST_SERIAL.flush();
 | ||||
| } | ||||
| 
 | ||||
| #ifdef DEBUG_USB_HOST | ||||
| 
 | ||||
| void NotifyFailGetDevDescr(void) { | ||||
|         Notify(PSTR("\r\ngetDevDescr "), 0x80); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailSetDevTblEntry(void) { | ||||
|         Notify(PSTR("\r\nsetDevTblEn "), 0x80); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailGetConfDescr(void) { | ||||
|         Notify(PSTR("\r\ngetConf "), 0x80); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailSetConfDescr(void) { | ||||
|         Notify(PSTR("\r\nsetConf "), 0x80); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailGetDevDescr(uint8_t reason) { | ||||
|         NotifyFailGetDevDescr(); | ||||
|         NotifyFail(reason); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailSetDevTblEntry(uint8_t reason) { | ||||
|         NotifyFailSetDevTblEntry(); | ||||
|         NotifyFail(reason); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void NotifyFailGetConfDescr(uint8_t reason) { | ||||
|         NotifyFailGetConfDescr(); | ||||
|         NotifyFail(reason); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailSetConfDescr(uint8_t reason) { | ||||
|         NotifyFailSetConfDescr(); | ||||
|         NotifyFail(reason); | ||||
| } | ||||
| 
 | ||||
| void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) { | ||||
|         Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); | ||||
|         D_PrintHex<uint16_t > (VID, 0x80); | ||||
|         Notify(PSTR(" PID: "), 0x80); | ||||
|         D_PrintHex<uint16_t > (PID, 0x80); | ||||
| } | ||||
| 
 | ||||
| void NotifyFail(uint8_t rcode) { | ||||
|         D_PrintHex<uint8_t > (rcode, 0x80); | ||||
|         Notify(PSTR("\r\n"), 0x80); | ||||
| } | ||||
| #endif | ||||
| @ -0,0 +1,78 @@ | ||||
| /* 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(_usb_h_) || defined(__MESSAGE_H__) | ||||
| #error "Never include message.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define __MESSAGE_H__ | ||||
| 
 | ||||
| extern int UsbDEBUGlvl; | ||||
| 
 | ||||
| void E_Notify(char const * msg, int lvl); | ||||
| void E_Notify(uint8_t b, int lvl); | ||||
| void E_NotifyStr(char const * msg, int lvl); | ||||
| void E_Notifyc(char c, int lvl); | ||||
| 
 | ||||
| #ifdef DEBUG_USB_HOST | ||||
| #define Notify E_Notify | ||||
| #define NotifyStr E_NotifyStr | ||||
| #define Notifyc E_Notifyc | ||||
| void NotifyFailGetDevDescr(uint8_t reason); | ||||
| void NotifyFailSetDevTblEntry(uint8_t reason); | ||||
| void NotifyFailGetConfDescr(uint8_t reason); | ||||
| void NotifyFailSetConfDescr(uint8_t reason); | ||||
| void NotifyFailGetDevDescr(void); | ||||
| void NotifyFailSetDevTblEntry(void); | ||||
| void NotifyFailGetConfDescr(void); | ||||
| void NotifyFailSetConfDescr(void); | ||||
| void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID); | ||||
| void NotifyFail(uint8_t rcode); | ||||
| #else | ||||
| #define Notify(...) ((void)0) | ||||
| #define NotifyStr(...) ((void)0) | ||||
| #define Notifyc(...) ((void)0) | ||||
| #define NotifyFailGetDevDescr(...) ((void)0) | ||||
| #define NotifyFailSetDevTblEntry(...) ((void)0) | ||||
| #define NotifyFailGetConfDescr(...) ((void)0) | ||||
| #define NotifyFailGetDevDescr(...) ((void)0) | ||||
| #define NotifyFailSetDevTblEntry(...) ((void)0) | ||||
| #define NotifyFailGetConfDescr(...) ((void)0) | ||||
| #define NotifyFailSetConfDescr(...) ((void)0) | ||||
| #define NotifyFailUnknownDevice(...) ((void)0) | ||||
| #define NotifyFail(...) ((void)0) | ||||
| #endif | ||||
| 
 | ||||
| template <class ERROR_TYPE> | ||||
| void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) { | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         Notify(msg, level); | ||||
|         Notify(PSTR(": "), level); | ||||
|         D_PrintHex<ERROR_TYPE > (rcode, level); | ||||
|         Notify(PSTR("\r\n"), level); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| template <class ERROR_TYPE> | ||||
| void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) { | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         Notify(msg, 0x80); | ||||
|         Notify(PSTR(": "), 0x80); | ||||
|         D_PrintHex<ERROR_TYPE > (rcode, 0x80); | ||||
|         Notify(PSTR("\r\n"), 0x80); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #endif // __MESSAGE_H__
 | ||||
| @ -0,0 +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 "Usb.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; | ||||
| } | ||||
| @ -0,0 +1,140 @@ | ||||
| /* 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(_usb_h_) || defined(__PARSETOOLS_H__) | ||||
| #error "Never include parsetools.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define __PARSETOOLS_H__ | ||||
| 
 | ||||
| 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__
 | ||||
| @ -0,0 +1,84 @@ | ||||
| /* 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(_usb_h_) || defined(__PRINTHEX_H__) | ||||
| #error "Never include printhex.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define __PRINTHEX_H__ | ||||
| 
 | ||||
| void E_Notifyc(char c, int lvl); | ||||
| 
 | ||||
| template <class T> | ||||
| 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; | ||||
|                 E_Notifyc(v, lvl); | ||||
|         } while(--num_nibbles); | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| void PrintBin(T val, int lvl) { | ||||
|         for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1) | ||||
|                 if(val & mask) | ||||
|                         E_Notifyc('1', lvl); | ||||
|                 else | ||||
|                         E_Notifyc('0', lvl); | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| 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; | ||||
|                 USB_HOST_SERIAL.print(v); | ||||
|         } while(--num_nibbles); | ||||
| } | ||||
| 
 | ||||
| /*template <class T>
 | ||||
| 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 <class T> void D_PrintHex(T val, int lvl) { | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         PrintHex<T > (val, lvl); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| void D_PrintBin(T val, int lvl) { | ||||
| #ifdef DEBUG_USB_HOST | ||||
|         PrintBin<T > (val, lvl); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif // __PRINTHEX_H__
 | ||||
| @ -0,0 +1,143 @@ | ||||
| /* 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 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef USB_HOST_SHIELD_SETTINGS_H | ||||
| #define USB_HOST_SHIELD_SETTINGS_H | ||||
| #include "macros.h" | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| /* Added by Bill Greiman to speed up mass storage initialization with USB
 | ||||
|  * flash drives and simple USB hard drives. | ||||
|  * Disable this by defining DELAY(x) to be delay(x). | ||||
|  */ | ||||
| #define DELAY(x) if((x) < 200)delay(x) | ||||
| /* Almost all USB flash drives and simple USB hard drives fail the write
 | ||||
|  * protect test and add 20 - 30 seconds to USB init.  Set SKIP_WRITE_PROTECT | ||||
|  * to nonzero to skip the test and assume the drive is writable. | ||||
|  */ | ||||
| #define SKIP_WRITE_PROTECT 1 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // DEBUGGING
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /* Set this to 1 to activate serial debugging */ | ||||
| #define ENABLE_UHS_DEBUGGING 0 | ||||
| 
 | ||||
| /* This can be used to select which serial port to use for debugging if
 | ||||
|  * multiple serial ports are available. | ||||
|  * For example Serial3. | ||||
|  */ | ||||
| #ifndef USB_HOST_SERIAL | ||||
| #define USB_HOST_SERIAL Serial | ||||
| #endif | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Manual board activation
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */ | ||||
| #define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually
 | ||||
| 
 | ||||
| /* Set this to 1 if you are using a Black Widdow */ | ||||
| #define USE_UHS_BLACK_WIDDOW 0 | ||||
| 
 | ||||
| /* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */ | ||||
| #define USE_XMEM_SPI_LOCK 0 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // MASS STORAGE
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // <<<<<<<<<<<<<<<< IMPORTANT >>>>>>>>>>>>>>>
 | ||||
| // Set this to 1 to support single LUN devices, and save RAM. -- I.E. thumb drives.
 | ||||
| // Each LUN needs ~13 bytes to be able to track the state of each unit.
 | ||||
| #ifndef MASS_MAX_SUPPORTED_LUN | ||||
| #define MASS_MAX_SUPPORTED_LUN  1 ///// 8  WHG
 | ||||
| #endif | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Set to 1 to use the faster spi4teensy3 driver.
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| #ifndef USE_SPI4TEENSY3 | ||||
| #define USE_SPI4TEENSY3 1 | ||||
| #endif | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // AUTOMATIC Settings
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| // No user serviceable parts below this line.
 | ||||
| // DO NOT change anything below here unless you are a developer!
 | ||||
| 
 | ||||
| #if defined(ARDUINO) && ARDUINO >=100 | ||||
| #include <Arduino.h> | ||||
| #else | ||||
| #include <WProgram.h> | ||||
| #include <pins_arduino.h> | ||||
| #include <avr/pgmspace.h> | ||||
| #include <avr/io.h> | ||||
| #define F(str) (str) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__GNUC__) && defined(__AVR__) | ||||
| #ifndef GCC_VERSION | ||||
| #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) | ||||
| #endif | ||||
| #if GCC_VERSION < 40602 // Test for GCC < 4.6.2
 | ||||
| #ifdef PROGMEM | ||||
| #undef PROGMEM | ||||
| #define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734#c4
 | ||||
| #ifdef PSTR | ||||
| #undef PSTR | ||||
| #define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) // Copied from pgmspace.h in avr-libc source
 | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(DEBUG_USB_HOST) && ENABLE_UHS_DEBUGGING | ||||
| #define DEBUG_USB_HOST | ||||
| #endif | ||||
| 
 | ||||
| // To use some other locking (e.g. freertos),
 | ||||
| // define XMEM_ACQUIRE_SPI and XMEM_RELEASE_SPI to point to your lock and unlock.
 | ||||
| // NOTE: NO argument is passed. You have to do this within your routine for
 | ||||
| // whatever you are using to lock and unlock.
 | ||||
| #if !defined(XMEM_ACQUIRE_SPI) | ||||
| #if USE_XMEM_SPI_LOCK || defined(USE_MULTIPLE_APP_API) | ||||
| #include <xmem.h> | ||||
| #else | ||||
| #define XMEM_ACQUIRE_SPI() (void(0)) | ||||
| #define XMEM_RELEASE_SPI() (void(0)) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP) | ||||
| #include <xmem.h> | ||||
| #else | ||||
| #define EXT_RAM 0 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) | ||||
| #define USING_SPI4TEENSY3 USE_SPI4TEENSY3 | ||||
| #else | ||||
| #define USING_SPI4TEENSY3 0 | ||||
| #endif | ||||
| 
 | ||||
| #if (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) | ||||
| #include <SPI.h> // Use the Arduino SPI library for the Arduino Due and RedBearLab nRF51822 | ||||
| #endif | ||||
| 
 | ||||
| #endif	/* SETTINGS_H */ | ||||
| @ -0,0 +1,166 @@ | ||||
| /* 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(_usb_h_) || defined(_ch9_h_) | ||||
| #error "Never include usb_ch9.h directly; include Usb.h instead" | ||||
| #else | ||||
| 
 | ||||
| /* USB chapter 9 structures */ | ||||
| #define _ch9_h_ | ||||
| 
 | ||||
| /* Misc.USB constants */ | ||||
| #define DEV_DESCR_LEN   18      //device descriptor length
 | ||||
| #define CONF_DESCR_LEN  9       //configuration descriptor length
 | ||||
| #define INTR_DESCR_LEN  9       //interface descriptor length
 | ||||
| #define EP_DESCR_LEN    7       //endpoint descriptor length
 | ||||
| 
 | ||||
| /* Standard Device Requests */ | ||||
| 
 | ||||
| #define USB_REQUEST_GET_STATUS                  0       // Standard Device Request - GET STATUS
 | ||||
| #define USB_REQUEST_CLEAR_FEATURE               1       // Standard Device Request - CLEAR FEATURE
 | ||||
| #define USB_REQUEST_SET_FEATURE                 3       // Standard Device Request - SET FEATURE
 | ||||
| #define USB_REQUEST_SET_ADDRESS                 5       // Standard Device Request - SET ADDRESS
 | ||||
| #define USB_REQUEST_GET_DESCRIPTOR              6       // Standard Device Request - GET DESCRIPTOR
 | ||||
| #define USB_REQUEST_SET_DESCRIPTOR              7       // Standard Device Request - SET DESCRIPTOR
 | ||||
| #define USB_REQUEST_GET_CONFIGURATION           8       // Standard Device Request - GET CONFIGURATION
 | ||||
| #define USB_REQUEST_SET_CONFIGURATION           9       // Standard Device Request - SET CONFIGURATION
 | ||||
| #define USB_REQUEST_GET_INTERFACE               10      // Standard Device Request - GET INTERFACE
 | ||||
| #define USB_REQUEST_SET_INTERFACE               11      // Standard Device Request - SET INTERFACE
 | ||||
| #define USB_REQUEST_SYNCH_FRAME                 12      // Standard Device Request - SYNCH FRAME
 | ||||
| 
 | ||||
| #define USB_FEATURE_ENDPOINT_HALT               0       // CLEAR/SET FEATURE - Endpoint Halt
 | ||||
| #define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // CLEAR/SET FEATURE - Device remote wake-up
 | ||||
| #define USB_FEATURE_TEST_MODE                   2       // CLEAR/SET FEATURE - Test mode
 | ||||
| 
 | ||||
| /* Setup Data Constants */ | ||||
| 
 | ||||
| #define USB_SETUP_HOST_TO_DEVICE                0x00    // Device Request bmRequestType transfer direction - host to device transfer
 | ||||
| #define USB_SETUP_DEVICE_TO_HOST                0x80    // Device Request bmRequestType transfer direction - device to host transfer
 | ||||
| #define USB_SETUP_TYPE_STANDARD                 0x00    // Device Request bmRequestType type - standard
 | ||||
| #define USB_SETUP_TYPE_CLASS                    0x20    // Device Request bmRequestType type - class
 | ||||
| #define USB_SETUP_TYPE_VENDOR                   0x40    // Device Request bmRequestType type - vendor
 | ||||
| #define USB_SETUP_RECIPIENT_DEVICE              0x00    // Device Request bmRequestType recipient - device
 | ||||
| #define USB_SETUP_RECIPIENT_INTERFACE           0x01    // Device Request bmRequestType recipient - interface
 | ||||
| #define USB_SETUP_RECIPIENT_ENDPOINT            0x02    // Device Request bmRequestType recipient - endpoint
 | ||||
| #define USB_SETUP_RECIPIENT_OTHER               0x03    // Device Request bmRequestType recipient - other
 | ||||
| 
 | ||||
| /* USB descriptors  */ | ||||
| 
 | ||||
| #define USB_DESCRIPTOR_DEVICE           0x01    // bDescriptorType for a Device Descriptor.
 | ||||
| #define USB_DESCRIPTOR_CONFIGURATION    0x02    // bDescriptorType for a Configuration Descriptor.
 | ||||
| #define USB_DESCRIPTOR_STRING           0x03    // bDescriptorType for a String Descriptor.
 | ||||
| #define USB_DESCRIPTOR_INTERFACE        0x04    // bDescriptorType for an Interface Descriptor.
 | ||||
| #define USB_DESCRIPTOR_ENDPOINT         0x05    // bDescriptorType for an Endpoint Descriptor.
 | ||||
| #define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06    // bDescriptorType for a Device Qualifier.
 | ||||
| #define USB_DESCRIPTOR_OTHER_SPEED      0x07    // bDescriptorType for a Other Speed Configuration.
 | ||||
| #define USB_DESCRIPTOR_INTERFACE_POWER  0x08    // bDescriptorType for Interface Power.
 | ||||
| #define USB_DESCRIPTOR_OTG              0x09    // bDescriptorType for an OTG Descriptor.
 | ||||
| 
 | ||||
| #define HID_DESCRIPTOR_HID			0x21 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* OTG SET FEATURE Constants    */ | ||||
| #define OTG_FEATURE_B_HNP_ENABLE                3       // SET FEATURE OTG - Enable B device to perform HNP
 | ||||
| #define OTG_FEATURE_A_HNP_SUPPORT               4       // SET FEATURE OTG - A device supports HNP
 | ||||
| #define OTG_FEATURE_A_ALT_HNP_SUPPORT           5       // SET FEATURE OTG - Another port on the A device supports HNP
 | ||||
| 
 | ||||
| /* USB Endpoint Transfer Types  */ | ||||
| #define USB_TRANSFER_TYPE_CONTROL               0x00    // Endpoint is a control endpoint.
 | ||||
| #define USB_TRANSFER_TYPE_ISOCHRONOUS           0x01    // Endpoint is an isochronous endpoint.
 | ||||
| #define USB_TRANSFER_TYPE_BULK                  0x02    // Endpoint is a bulk endpoint.
 | ||||
| #define USB_TRANSFER_TYPE_INTERRUPT             0x03    // Endpoint is an interrupt endpoint.
 | ||||
| #define bmUSB_TRANSFER_TYPE                     0x03    // bit mask to separate transfer type from ISO attributes
 | ||||
| 
 | ||||
| 
 | ||||
| /* Standard Feature Selectors for CLEAR_FEATURE Requests    */ | ||||
| #define USB_FEATURE_ENDPOINT_STALL              0       // Endpoint recipient
 | ||||
| #define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // Device recipient
 | ||||
| #define USB_FEATURE_TEST_MODE                   2       // Device recipient
 | ||||
| 
 | ||||
| /* descriptor data structures */ | ||||
| 
 | ||||
| /* 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.
 | ||||
| } __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.
 | ||||
| } __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.
 | ||||
| } __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.
 | ||||
| } __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
 | ||||
| } __attribute__((packed)) USB_HID_DESCRIPTOR; | ||||
| 
 | ||||
| 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_
 | ||||
| @ -0,0 +1,462 @@ | ||||
| /* 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 | ||||
|  */ | ||||
| /* MAX3421E-based USB Host Library header file */ | ||||
| 
 | ||||
| 
 | ||||
| #if !defined(_usb_h_) || defined(_USBHOST_H_) | ||||
| #error "Never include usbhost.h directly; include Usb.h instead" | ||||
| #else | ||||
| #define _USBHOST_H_ | ||||
| 
 | ||||
| #if USING_SPI4TEENSY3 | ||||
| #include <spi4teensy3.h> | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| /* SPI initialization */ | ||||
| template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi { | ||||
| public: | ||||
| #if USING_SPI4TEENSY3 | ||||
|         static void init() { | ||||
|                 // spi4teensy3 inits everything for us, except /SS
 | ||||
|                 // CLK, MOSI and MISO are hard coded for now.
 | ||||
|                 // spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
 | ||||
|                 spi4teensy3::init(); // full speed, cpol 0, cpha 0
 | ||||
|                 SPI_SS::SetDirWrite(); | ||||
|                 SPI_SS::Set(); | ||||
|         } | ||||
| #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) | ||||
|         static void init() { | ||||
|                 SPI_SS::SetDirWrite(); | ||||
|                 SPI_SS::Set(); | ||||
|                 SPI.begin(); | ||||
|                 SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
 | ||||
|         } | ||||
| #elif defined(RBL_NRF51822) | ||||
|         static void init() { | ||||
|                 SPI_SS::SetDirWrite(); | ||||
|                 SPI_SS::Set(); | ||||
|                 SPI.begin(); | ||||
|                 // SPI.setFrequency(SPI_FREQUENCY_8M);
 | ||||
|         } | ||||
| #else | ||||
|         static void init() { | ||||
|                 //uint8_t tmp;
 | ||||
|                 SPI_CLK::SetDirWrite(); | ||||
|                 SPI_MOSI::SetDirWrite(); | ||||
|                 SPI_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; // 0x01
 | ||||
|                 /**/ | ||||
|                 //tmp = SPSR;
 | ||||
|                 //tmp = SPDR;
 | ||||
|         } | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| /* SPI pin definitions. see avrpins.h   */ | ||||
| #if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | ||||
| typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi; | ||||
| #elif  defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) | ||||
| typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; | ||||
| #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | ||||
| typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; | ||||
| #elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) | ||||
| typedef SPi< P13, P11, P12, P10 > spi; | ||||
| #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) | ||||
| typedef SPi< P76, P75, P74, P10 > spi; | ||||
| #elif defined(RBL_NRF51822) | ||||
| typedef SPi< P16, P18, P17, P10 > spi; | ||||
| #else | ||||
| #error "No SPI entry in usbhost.h" | ||||
| #endif | ||||
| 
 | ||||
| typedef enum { | ||||
|         vbus_on = 0, | ||||
|         vbus_off = GPX_VBDET | ||||
| } VBUS_t; | ||||
| 
 | ||||
| template< typename SPI_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(); | ||||
|         int8_t Init(int mseconds); | ||||
| 
 | ||||
|         void vbusPower(VBUS_t state) { | ||||
|                 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state)); | ||||
|         } | ||||
| 
 | ||||
|         uint8_t getVbusState(void) { | ||||
|                 return vbusState; | ||||
|         }; | ||||
|         void busprobe(); | ||||
|         uint8_t GpxHandler(); | ||||
|         uint8_t IntHandler(); | ||||
|         uint8_t Task(); | ||||
| }; | ||||
| 
 | ||||
| template< typename SPI_SS, typename INTR > | ||||
|         uint8_t MAX3421e< SPI_SS, INTR >::vbusState = 0; | ||||
| 
 | ||||
| /* constructor */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| MAX3421e< SPI_SS, INTR >::MAX3421e() { | ||||
|         // Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
 | ||||
| #ifdef BOARD_MEGA_ADK | ||||
|         // For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
 | ||||
|         P55::SetDirWrite(); | ||||
|         P55::Set(); | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| /* write single byte into MAX3421 register */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         SPI_SS::Clear(); | ||||
| #if USING_SPI4TEENSY3 | ||||
|         uint8_t c[2]; | ||||
|         c[0] = reg | 0x02; | ||||
|         c[1] = data; | ||||
|         spi4teensy3::send(c, 2); | ||||
| #elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) ||  defined(RBL_NRF51822) | ||||
|         SPI.transfer(reg | 0x02); | ||||
|         SPI.transfer(data); | ||||
| #else | ||||
|         SPDR = (reg | 0x02); | ||||
|         while(!(SPSR & (1 << SPIF))); | ||||
|         SPDR = data; | ||||
|         while(!(SPSR & (1 << SPIF))); | ||||
| #endif | ||||
|         SPI_SS::Set(); | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         return; | ||||
| }; | ||||
| /* multiple-byte write                            */ | ||||
| 
 | ||||
| /* returns a pointer to memory position after last written */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         SPI_SS::Clear(); | ||||
| #if USING_SPI4TEENSY3 | ||||
|         spi4teensy3::send(reg | 0x02); | ||||
|         spi4teensy3::send(data_p, nbytes); | ||||
|         data_p += nbytes; | ||||
| #elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) ||  defined(RBL_NRF51822) | ||||
|         SPI.transfer(reg | 0x02); | ||||
|         while(nbytes) { | ||||
|                 SPI.transfer(*data_p); | ||||
|                 nbytes--; | ||||
|                 data_p++; // advance data pointer
 | ||||
|         } | ||||
| #else | ||||
|         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
 | ||||
|                 nbytes--; | ||||
|                 data_p++; // advance data pointer
 | ||||
|         } | ||||
|         while(!(SPSR & (1 << SPIF))); | ||||
| #endif | ||||
|         SPI_SS::Set(); | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         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 SPI_SS, typename INTR > | ||||
| void MAX3421e< SPI_SS, INTR >::gpioWr(uint8_t data) { | ||||
|         regWr(rIOPINS1, data); | ||||
|         data >>= 4; | ||||
|         regWr(rIOPINS2, data); | ||||
|         return; | ||||
| } | ||||
| 
 | ||||
| /* single host register read    */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         SPI_SS::Clear(); | ||||
| #if USING_SPI4TEENSY3 | ||||
|         spi4teensy3::send(reg); | ||||
|         uint8_t rv = spi4teensy3::receive(); | ||||
|         SPI_SS::Set(); | ||||
| #elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) ||  defined(RBL_NRF51822) | ||||
|         SPI.transfer(reg); | ||||
|         uint8_t rv = SPI.transfer(0); | ||||
|         SPI_SS::Set(); | ||||
| #else | ||||
|         SPDR = reg; | ||||
|         while(!(SPSR & (1 << SPIF))); | ||||
|         SPDR = 0; //send empty byte
 | ||||
|         while(!(SPSR & (1 << SPIF))); | ||||
|         SPI_SS::Set(); | ||||
|         uint8_t rv = SPDR; | ||||
| #endif | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         return (rv); | ||||
| } | ||||
| /* multiple-byte register read  */ | ||||
| 
 | ||||
| /* returns a pointer to a memory position after last read   */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         SPI_SS::Clear(); | ||||
| #if USING_SPI4TEENSY3 | ||||
|         spi4teensy3::send(reg); | ||||
|         spi4teensy3::receive(data_p, nbytes); | ||||
|         data_p += nbytes; | ||||
| #elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) ||  defined(RBL_NRF51822) | ||||
|         SPI.transfer(reg); | ||||
|         while(nbytes) { | ||||
|             *data_p++ = SPI.transfer(0); | ||||
|             nbytes--; | ||||
|         } | ||||
| #else | ||||
|         SPDR = reg; | ||||
|         while(!(SPSR & (1 << SPIF))); //wait
 | ||||
|         while(nbytes) { | ||||
|                 SPDR = 0; //send empty byte
 | ||||
|                 nbytes--; | ||||
|                 while(!(SPSR & (1 << SPIF))); | ||||
| #if 0 | ||||
|                 { | ||||
|                         *data_p = SPDR; | ||||
|                         printf("%2.2x ", *data_p); | ||||
|                 } | ||||
|                 data_p++; | ||||
|         } | ||||
|         printf("\r\n"); | ||||
| #else | ||||
|                 *data_p++ = SPDR; | ||||
|         } | ||||
| #endif | ||||
| #endif | ||||
|         SPI_SS::Set(); | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         return ( data_p); | ||||
| } | ||||
| /* GPIO read. See gpioWr for explanation */ | ||||
| 
 | ||||
| /* GPIN pins are in high nibbles of IOPINS1, IOPINS2    */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| uint8_t MAX3421e< SPI_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 SPI_SS, typename INTR > | ||||
| uint16_t MAX3421e< SPI_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 SPI_SS, typename INTR > | ||||
| int8_t MAX3421e< SPI_SS, INTR >::Init() { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         // Moved here.
 | ||||
|         // you really should not init hardware in the constructor when it involves locks.
 | ||||
|         // Also avoids the vbus flicker issue confusing some devices.
 | ||||
|         /* pin and peripheral setup */ | ||||
|         SPI_SS::SetDirWrite(); | ||||
|         SPI_SS::Set(); | ||||
|         spi::init(); | ||||
|         INTR::SetDirRead(); | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         /* MAX3421E - full-duplex SPI, level interrupt */ | ||||
|         // GPX pin on. Moved here, otherwise we flicker the vbus.
 | ||||
|         regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); | ||||
| 
 | ||||
|         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
 | ||||
| 
 | ||||
|         /* check if device is connected */ | ||||
|         regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
 | ||||
|         while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
 | ||||
| 
 | ||||
|         busprobe(); //check if anything is connected
 | ||||
| 
 | ||||
|         regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
 | ||||
|         regWr(rCPUCTL, 0x01); //enable interrupt pin
 | ||||
| 
 | ||||
|         return ( 0); | ||||
| } | ||||
| 
 | ||||
| /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) { | ||||
|         XMEM_ACQUIRE_SPI(); | ||||
|         // Moved here.
 | ||||
|         // you really should not init hardware in the constructor when it involves locks.
 | ||||
|         // Also avoids the vbus flicker issue confusing some devices.
 | ||||
|         /* pin and peripheral setup */ | ||||
|         SPI_SS::SetDirWrite(); | ||||
|         SPI_SS::Set(); | ||||
|         spi::init(); | ||||
|         INTR::SetDirRead(); | ||||
|         XMEM_RELEASE_SPI(); | ||||
|         /* MAX3421E - full-duplex SPI, level interrupt, vbus off */ | ||||
|         regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET)); | ||||
| 
 | ||||
|         if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
 | ||||
|                 return ( -1); | ||||
|         } | ||||
| 
 | ||||
|         // Delay a minimum of 1 second to ensure any capacitors are drained.
 | ||||
|         // 1 second is required to make sure we do not smoke a Microdrive!
 | ||||
|         if(mseconds < 1000) mseconds = 1000; | ||||
|         delay(mseconds); | ||||
| 
 | ||||
|         regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
 | ||||
| 
 | ||||
|         regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
 | ||||
| 
 | ||||
|         /* check if device is connected */ | ||||
|         regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
 | ||||
|         while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
 | ||||
| 
 | ||||
|         busprobe(); //check if anything is connected
 | ||||
| 
 | ||||
|         regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
 | ||||
|         regWr(rCPUCTL, 0x01); //enable interrupt pin
 | ||||
| 
 | ||||
|         // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
 | ||||
|         regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); | ||||
| 
 | ||||
|         return ( 0); | ||||
| } | ||||
| 
 | ||||
| /* probe bus to determine device presence and speed and switch host to this speed */ | ||||
| template< typename SPI_SS, typename INTR > | ||||
| void MAX3421e< SPI_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 SPI_SS, typename INTR > | ||||
| uint8_t MAX3421e< SPI_SS, INTR >::Task(void) { | ||||
|         uint8_t rcode = 0; | ||||
|         uint8_t pinvalue; | ||||
|         //USB_HOST_SERIAL.print("Vbus state: ");
 | ||||
|         //USB_HOST_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 SPI_SS, typename INTR > | ||||
| uint8_t MAX3421e< SPI_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 SPI_SS, typename INTR >
 | ||||
| //uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
 | ||||
| //{
 | ||||
| //	uint8_t GPINIRQ = regRd( rGPINIRQ );          //read GPIN IRQ register
 | ||||
| ////    if( GPINIRQ & bmGPINIRQ7 ) {            //vbus overload
 | ||||
| ////        vbusPwr( OFF );                     //attempt powercycle
 | ||||
| ////        delay( 1000 );
 | ||||
| ////        vbusPwr( ON );
 | ||||
| ////        regWr( rGPINIRQ, bmGPINIRQ7 );
 | ||||
| ////    }
 | ||||
| //    return( GPINIRQ );
 | ||||
| //}
 | ||||
| 
 | ||||
| #endif //_USBHOST_H_
 | ||||
					Loading…
					
					
				
		Reference in new issue
	
	 Marcio Teixeira
						Marcio Teixeira