- 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