Project restructuring
This commit is contained in:
19
c8_arduino/CMakeLists.txt
Normal file
19
c8_arduino/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
set(CMAKE_TOOLCHAIN_FILE cmake/ArduinoToolchain.cmake)
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
project(checkm8_arduino)
|
||||
|
||||
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(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 src/checkm8_arduino.ino)
|
||||
set(checkm8_arduino_PROGRAMMER avrispmkii)
|
||||
set(checkm8_arduino_PORT /dev/ttyACM0)
|
||||
|
||||
include_directories(include)
|
||||
include_directories(../include)
|
||||
generate_arduino_firmware(checkm8_arduino)
|
||||
89
c8_arduino/cmake/ArduinoToolchain.cmake
Normal file
89
c8_arduino/cmake/ArduinoToolchain.cmake
Normal file
@@ -0,0 +1,89 @@
|
||||
#=============================================================================#
|
||||
# Author: Tomasz Bogdal (QueezyTheGreat)
|
||||
# Home: https://github.com/queezythegreat/arduino-cmake
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#=============================================================================#
|
||||
set(CMAKE_SYSTEM_NAME Arduino)
|
||||
|
||||
set(CMAKE_C_COMPILER avr-gcc)
|
||||
set(CMAKE_CXX_COMPILER avr-g++)
|
||||
|
||||
# Add current directory to CMake Module path automatically
|
||||
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/Platform/Arduino.cmake)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
#=============================================================================#
|
||||
# System Paths #
|
||||
#=============================================================================#
|
||||
if(UNIX)
|
||||
include(Platform/UnixPaths)
|
||||
if(APPLE)
|
||||
list(APPEND CMAKE_SYSTEM_PREFIX_PATH ~/Applications
|
||||
/Applications
|
||||
/Developer/Applications
|
||||
/sw # Fink
|
||||
/opt/local) # MacPorts
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
include(Platform/WindowsPaths)
|
||||
endif()
|
||||
|
||||
|
||||
#=============================================================================#
|
||||
# Detect Arduino SDK #
|
||||
#=============================================================================#
|
||||
if(NOT ARDUINO_SDK_PATH)
|
||||
set(ARDUINO_PATHS)
|
||||
|
||||
foreach(DETECT_VERSION_MAJOR 1)
|
||||
foreach(DETECT_VERSION_MINOR RANGE 5 0)
|
||||
list(APPEND ARDUINO_PATHS arduino-${DETECT_VERSION_MAJOR}.${DETECT_VERSION_MINOR})
|
||||
foreach(DETECT_VERSION_PATCH RANGE 3 0)
|
||||
list(APPEND ARDUINO_PATHS arduino-${DETECT_VERSION_MAJOR}.${DETECT_VERSION_MINOR}.${DETECT_VERSION_PATCH})
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(VERSION RANGE 23 19)
|
||||
list(APPEND ARDUINO_PATHS arduino-00${VERSION})
|
||||
endforeach()
|
||||
|
||||
if(UNIX)
|
||||
file(GLOB SDK_PATH_HINTS /usr/share/arduino*
|
||||
/opt/local/arduino*
|
||||
/opt/arduino*
|
||||
/usr/local/share/arduino*)
|
||||
elseif(WIN32)
|
||||
set(SDK_PATH_HINTS "C:\\Program Files\\Arduino"
|
||||
"C:\\Program Files (x86)\\Arduino"
|
||||
)
|
||||
endif()
|
||||
list(SORT SDK_PATH_HINTS)
|
||||
list(REVERSE SDK_PATH_HINTS)
|
||||
endif()
|
||||
|
||||
find_path(ARDUINO_SDK_PATH
|
||||
NAMES lib/version.txt
|
||||
PATH_SUFFIXES share/arduino
|
||||
Arduino.app/Contents/Resources/Java/
|
||||
Arduino.app/Contents/Java/
|
||||
${ARDUINO_PATHS}
|
||||
HINTS ${SDK_PATH_HINTS}
|
||||
DOC "Arduino SDK path.")
|
||||
|
||||
if(ARDUINO_SDK_PATH)
|
||||
list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr)
|
||||
list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/utils)
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find Arduino SDK (set ARDUINO_SDK_PATH)!")
|
||||
endif()
|
||||
|
||||
set(ARDUINO_CPUMENU)
|
||||
if(ARDUINO_CPU)
|
||||
set(ARDUINO_CPUMENU ".menu.cpu.${ARDUINO_CPU}")
|
||||
endif(ARDUINO_CPU)
|
||||
|
||||
2341
c8_arduino/cmake/Platform/Arduino.cmake
Normal file
2341
c8_arduino/cmake/Platform/Arduino.cmake
Normal file
File diff suppressed because it is too large
Load Diff
324
c8_arduino/include/SPI.h
Normal file
324
c8_arduino/include/SPI.h
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
|
||||
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
|
||||
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
|
||||
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (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 "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
|
||||
42
c8_arduino/include/Usb.h
Normal file
42
c8_arduino/include/Usb.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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/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"
|
||||
|
||||
#endif //_usb_h_
|
||||
5
c8_arduino/include/User_Setup.h
Normal file
5
c8_arduino/include/User_Setup.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifndef CHECKM8_ARDUINO_USER_SETUP_H
|
||||
#define CHECKM8_ARDUINO_USER_SETUP_H
|
||||
|
||||
|
||||
#endif //CHECKM8_ARDUINO_USER_SETUP_H
|
||||
201
c8_arduino/lib/hostshield/SPI.cpp
Normal file
201
c8_arduino/lib/hostshield/SPI.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
|
||||
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
|
||||
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
|
||||
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (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<<INT0)
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#define SPI_INT3_MASK (1<<INT3)
|
||||
#define SPI_INT4_MASK (1<<INT6)
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#define SPI_INT0_MASK (1<<INT0)
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#define SPI_INT3_MASK (1<<INT3)
|
||||
#define SPI_INT4_MASK (1<<INT4)
|
||||
#define SPI_INT5_MASK (1<<INT5)
|
||||
#define SPI_INT6_MASK (1<<INT6)
|
||||
#define SPI_INT7_MASK (1<<INT7)
|
||||
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
#define SPI_INT0_MASK (1<<INT4)
|
||||
#define SPI_INT1_MASK (1<<INT5)
|
||||
#define SPI_INT2_MASK (1<<INT0)
|
||||
#define SPI_INT3_MASK (1<<INT1)
|
||||
#define SPI_INT4_MASK (1<<INT2)
|
||||
#define SPI_INT5_MASK (1<<INT3)
|
||||
#define SPI_INT6_MASK (1<<INT6)
|
||||
#define SPI_INT7_MASK (1<<INT7)
|
||||
#else
|
||||
#ifdef INT0
|
||||
#define SPI_INT0_MASK (1<<INT0)
|
||||
#endif
|
||||
#ifdef INT1
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#endif
|
||||
#ifdef INT2
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
switch (interruptNumber) {
|
||||
#ifdef SPI_INT0_MASK
|
||||
case 0: mask = SPI_INT0_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT1_MASK
|
||||
case 1: mask = SPI_INT1_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT2_MASK
|
||||
case 2: mask = SPI_INT2_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT3_MASK
|
||||
case 3: mask = SPI_INT3_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT4_MASK
|
||||
case 4: mask = SPI_INT4_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT5_MASK
|
||||
case 5: mask = SPI_INT5_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT6_MASK
|
||||
case 6: mask = SPI_INT6_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT7_MASK
|
||||
case 7: mask = SPI_INT7_MASK; break;
|
||||
#endif
|
||||
default:
|
||||
interruptMode = 2;
|
||||
break;
|
||||
}
|
||||
interruptMask |= mask;
|
||||
if (!interruptMode)
|
||||
interruptMode = 1;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
// Once in mode 2 we can't go back to 0 without a proper reference count
|
||||
if (interruptMode == 2)
|
||||
return;
|
||||
uint8_t mask = 0;
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
switch (interruptNumber) {
|
||||
#ifdef SPI_INT0_MASK
|
||||
case 0: mask = SPI_INT0_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT1_MASK
|
||||
case 1: mask = SPI_INT1_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT2_MASK
|
||||
case 2: mask = SPI_INT2_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT3_MASK
|
||||
case 3: mask = SPI_INT3_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT4_MASK
|
||||
case 4: mask = SPI_INT4_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT5_MASK
|
||||
case 5: mask = SPI_INT5_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT6_MASK
|
||||
case 6: mask = SPI_INT6_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT7_MASK
|
||||
case 7: mask = SPI_INT7_MASK; break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
// this case can't be reached
|
||||
}
|
||||
interruptMask &= ~mask;
|
||||
if (!interruptMask)
|
||||
interruptMode = 0;
|
||||
SREG = sreg;
|
||||
}
|
||||
872
c8_arduino/lib/hostshield/Usb.cpp
Normal file
872
c8_arduino/lib/hostshield/Usb.cpp
Normal file
@@ -0,0 +1,872 @@
|
||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
/* USB functions */
|
||||
|
||||
#include "Usb.h"
|
||||
|
||||
static uint8_t usb_error = 0;
|
||||
static uint8_t usb_task_state;
|
||||
|
||||
/* constructor */
|
||||
USB::USB() : bmHubPre(0) {
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
|
||||
init();
|
||||
}
|
||||
|
||||
/* Initialize data structures */
|
||||
void USB::init() {
|
||||
//devConfigIndex = 0;
|
||||
bmHubPre = 0;
|
||||
}
|
||||
|
||||
uint8_t USB::getUsbTaskState(void) {
|
||||
return ( usb_task_state);
|
||||
}
|
||||
|
||||
void USB::setUsbTaskState(uint8_t state) {
|
||||
usb_task_state = state;
|
||||
}
|
||||
|
||||
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if(!p || !p->epinfo)
|
||||
return NULL;
|
||||
|
||||
EpInfo *pep = p->epinfo;
|
||||
|
||||
for(uint8_t i = 0; i < p->epcount; i++) {
|
||||
if((pep)->epAddr == ep)
|
||||
return pep;
|
||||
|
||||
pep++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set device table entry */
|
||||
|
||||
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
|
||||
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
|
||||
if(!eprecord_ptr)
|
||||
return USB_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if(!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->address.devAddress = addr;
|
||||
p->epinfo = eprecord_ptr;
|
||||
p->epcount = epcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if(!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if(!p->epinfo)
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
||||
*ppep = getEpInfoEntry(addr, ep);
|
||||
|
||||
if(!*ppep)
|
||||
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
||||
|
||||
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
|
||||
(*nak_limit)--;
|
||||
/*
|
||||
USBTRACE2("\r\nAddress: ", addr);
|
||||
USBTRACE2(" EP: ", ep);
|
||||
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
|
||||
USBTRACE2(" NAK Limit: ", nak_limit);
|
||||
USBTRACE("\r\n");
|
||||
*/
|
||||
regWr(rPERADDR, addr); //set peripheral address
|
||||
|
||||
uint8_t mode = regRd(rMODE);
|
||||
|
||||
//Serial.print("\r\nMode: ");
|
||||
//Serial.println( mode, HEX);
|
||||
//Serial.print("\r\nLS: ");
|
||||
//Serial.println(p->lowspeed, HEX);
|
||||
|
||||
|
||||
|
||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
||||
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
|
||||
/* depending on request. Actual requests are defined as inlines */
|
||||
/* return codes: */
|
||||
/* 00 = success */
|
||||
|
||||
/* 01-0f = non-zero HRSLT */
|
||||
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
|
||||
bool direction = false; //request direction, IN or OUT
|
||||
uint8_t rcode;
|
||||
SETUP_PKT setup_pkt;
|
||||
|
||||
EpInfo *pep = NULL;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||
|
||||
if(rcode)
|
||||
return rcode;
|
||||
|
||||
direction = ((bmReqType & 0x80) > 0);
|
||||
|
||||
/* fill in setup packet */
|
||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
||||
setup_pkt.bRequest = bRequest;
|
||||
setup_pkt.wVal_u.wValueLo = wValLo;
|
||||
setup_pkt.wVal_u.wValueHi = wValHi;
|
||||
setup_pkt.wIndex = wInd;
|
||||
setup_pkt.wLength = total;
|
||||
|
||||
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
|
||||
|
||||
rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
|
||||
|
||||
if(rcode) //return HRSLT if not zero
|
||||
return ( rcode);
|
||||
|
||||
if(dataptr != NULL) //data stage, if present
|
||||
{
|
||||
if(direction) //IN transfer
|
||||
{
|
||||
uint16_t left = total;
|
||||
|
||||
pep->bmRcvToggle = 1; //bmRCVTOG1;
|
||||
|
||||
while(left) {
|
||||
// Bytes read into buffer
|
||||
#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 = (left<nbytes) ? left : nbytes;
|
||||
|
||||
rcode = InTransfer(pep, nak_limit, &read, dataptr);
|
||||
if(rcode == hrTOGERR) {
|
||||
// yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rcode)
|
||||
return rcode;
|
||||
|
||||
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
|
||||
if(!rcode && p)
|
||||
((USBReadParser*)p)->Parse(read, dataptr, total - left);
|
||||
|
||||
left -= read;
|
||||
|
||||
if(read < nbytes)
|
||||
break;
|
||||
}
|
||||
} else //OUT transfer
|
||||
{
|
||||
pep->bmSndToggle = 1; //bmSNDTOG1;
|
||||
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
||||
}
|
||||
if(rcode) //return error
|
||||
return ( rcode);
|
||||
}
|
||||
// Status stage
|
||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
|
||||
}
|
||||
|
||||
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)
|
||||
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<USB_DEVICE_DESCRIPTOR *>(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<USB_CONFIGURATION_DESCRIPTOR *>(buf);
|
||||
|
||||
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
|
||||
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
uint16_t total = ucd->wTotalLength;
|
||||
|
||||
//USBTRACE2("\r\ntotal conf.size:", total);
|
||||
|
||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
|
||||
}
|
||||
|
||||
//get string descriptor
|
||||
|
||||
uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
|
||||
}
|
||||
//set address
|
||||
|
||||
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||
uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
|
||||
//delay(2); //per USB 2.0 sect.9.2.6.3
|
||||
delay(300); // Older spec says you should wait at least 200ms
|
||||
return rcode;
|
||||
//return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
|
||||
}
|
||||
//set configuration
|
||||
|
||||
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
|
||||
}
|
||||
|
||||
#endif // defined(USB_METHODS_INLINE)
|
||||
312
c8_arduino/lib/hostshield/UsbCore.h
Normal file
312
c8_arduino/lib/hostshield/UsbCore.h
Normal file
@@ -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<P6, P3> MAX3421E; // Black Widow
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
#if EXT_RAM
|
||||
typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
|
||||
#else
|
||||
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
|
||||
#endif
|
||||
#elif defined(BOARD_MEGA_ADK)
|
||||
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
||||
#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06
|
||||
typedef MAX3421e<P3, P2> MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3
|
||||
#elif defined(ESP8266)
|
||||
typedef MAX3421e<P15, P5> MAX3421E; // ESP8266 boards
|
||||
#elif defined(ESP32)
|
||||
typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
|
||||
#elif (defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__))
|
||||
typedef MAX3421e<Pb4, Pb3> MAX3421E; // Sanguino
|
||||
#else
|
||||
typedef MAX3421e<P10, P9> 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<USB_NUMDEVICES> addrPool;
|
||||
USBDeviceConfig* devConfig[USB_NUMDEVICES];
|
||||
uint8_t bmHubPre;
|
||||
|
||||
public:
|
||||
USB(void);
|
||||
|
||||
void SetHubPreMask() {
|
||||
bmHubPre |= bmHUBPRE;
|
||||
};
|
||||
|
||||
void ResetHubPreMask() {
|
||||
bmHubPre &= (~bmHUBPRE);
|
||||
};
|
||||
|
||||
AddressPool& GetAddressPool() {
|
||||
return (AddressPool&)addrPool;
|
||||
};
|
||||
|
||||
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if(!devConfig[i]) {
|
||||
devConfig[i] = pdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
|
||||
};
|
||||
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
uint8_t getUsbTaskState(void);
|
||||
void setUsbTaskState(uint8_t state);
|
||||
|
||||
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
|
||||
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
|
||||
|
||||
/* Control requests */
|
||||
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
|
||||
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
|
||||
|
||||
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
|
||||
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
|
||||
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
|
||||
/**/
|
||||
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, 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 */
|
||||
290
c8_arduino/lib/hostshield/address.h
Normal file
290
c8_arduino/lib/hostshield/address.h
Normal file
@@ -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 <const uint8_t MAX_DEVICES_ALLOWED>
|
||||
class AddressPoolImpl : public AddressPool {
|
||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
|
||||
uint8_t hubCounter; // hub counter is kept
|
||||
// in order to avoid hub address duplication
|
||||
|
||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||
|
||||
// Initializes address pool entry
|
||||
|
||||
void InitEntry(uint8_t index) {
|
||||
thePool[index].address.devAddress = 0;
|
||||
thePool[index].epcount = 1;
|
||||
thePool[index].lowspeed = 0;
|
||||
thePool[index].epinfo = &dev0ep;
|
||||
};
|
||||
|
||||
// Returns thePool index for a given address
|
||||
|
||||
uint8_t FindAddressIndex(uint8_t address = 0) {
|
||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
|
||||
if(thePool[i].address.devAddress == address)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Returns thePool child index for a given parent
|
||||
|
||||
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
|
||||
for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
|
||||
if(thePool[i].address.bmParent == addr.bmAddress)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Frees address entry specified by index parameter
|
||||
|
||||
void FreeAddressByIndex(uint8_t index) {
|
||||
// Zero field is reserved and should not be affected
|
||||
if(index == 0)
|
||||
return;
|
||||
|
||||
UsbDeviceAddress uda = thePool[index].address;
|
||||
// If a hub was switched off all port addresses should be freed
|
||||
if(uda.bmHub == 1) {
|
||||
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
|
||||
FreeAddressByIndex(i);
|
||||
|
||||
// If the hub had the last allocated address, hubCounter should be decremented
|
||||
if(hubCounter == uda.bmAddress)
|
||||
hubCounter--;
|
||||
}
|
||||
InitEntry(index);
|
||||
}
|
||||
|
||||
// Initializes the whole address pool at once
|
||||
|
||||
void InitAllAddresses() {
|
||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
InitEntry(i);
|
||||
|
||||
hubCounter = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
AddressPoolImpl() : hubCounter(0) {
|
||||
// Zero address is reserved
|
||||
InitEntry(0);
|
||||
|
||||
thePool[0].address.devAddress = 0;
|
||||
thePool[0].epinfo = &dev0ep;
|
||||
dev0ep.epAddr = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
dev0ep.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<MAX_DEVICES_ALLOWED; i++)
|
||||
// if (thePool[i].address != 0);
|
||||
// counter ++;
|
||||
|
||||
// return counter;
|
||||
//};
|
||||
};
|
||||
|
||||
#endif // __ADDRESS_H__
|
||||
1495
c8_arduino/lib/hostshield/avrpins.h
Normal file
1495
c8_arduino/lib/hostshield/avrpins.h
Normal file
File diff suppressed because it is too large
Load Diff
340
c8_arduino/lib/hostshield/gpl2.txt
Normal file
340
c8_arduino/lib/hostshield/gpl2.txt
Normal file
@@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
||||
235
c8_arduino/lib/hostshield/max3421e.h
Normal file
235
c8_arduino/lib/hostshield/max3421e.h
Normal file
@@ -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_
|
||||
214
c8_arduino/lib/hostshield/settings.h
Normal file
214
c8_arduino/lib/hostshield/settings.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/* 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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <xmem.h>
|
||||
#else
|
||||
#define XMEM_ACQUIRE_SPI() (void(0))
|
||||
#define XMEM_RELEASE_SPI() (void(0))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP)
|
||||
#include <xmem.h>
|
||||
#else
|
||||
#define EXT_RAM 0
|
||||
#endif
|
||||
|
||||
#if defined(CORE_TEENSY) && defined(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 <nrf_gpio.h>
|
||||
#include <SPI_Master.h>
|
||||
#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<const uint8_t*>(addr))
|
||||
#undef pgm_read_word
|
||||
#define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*>(addr))
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ESP8266_WIFIO
|
||||
#error "This board is currently not supported"
|
||||
#endif
|
||||
|
||||
#endif /* SETTINGS_H */
|
||||
173
c8_arduino/lib/hostshield/usb_ch9.h
Normal file
173
c8_arduino/lib/hostshield/usb_ch9.h
Normal file
@@ -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_
|
||||
585
c8_arduino/lib/hostshield/usbhost.h
Normal file
585
c8_arduino/lib/hostshield/usbhost.h
Normal file
@@ -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 <spi4teensy3.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/* SPI initialization */
|
||||
template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
|
||||
public:
|
||||
#if USING_SPI4TEENSY3
|
||||
static void init() {
|
||||
// spi4teensy3 inits everything for us, except /SS
|
||||
// CLK, MOSI and MISO are hard coded for now.
|
||||
// spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
|
||||
spi4teensy3::init(); // full speed, cpol 0, cpha 0
|
||||
SPI_SS::SetDirWrite();
|
||||
SPI_SS::Set();
|
||||
}
|
||||
#elif defined(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_
|
||||
201
c8_arduino/lib/hostshield/version_helper.h
Normal file
201
c8_arduino/lib/hostshield/version_helper.h
Normal file
@@ -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 <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __PGMSPACE_H_
|
||||
#define __PGMSPACE_H_ 1
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#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
|
||||
304
c8_arduino/src/checkm8_arduino.ino
Normal file
304
c8_arduino/src/checkm8_arduino.ino
Normal file
@@ -0,0 +1,304 @@
|
||||
#include "../include/User_Setup.h"
|
||||
#include "../include/Usb.h"
|
||||
#include "checkm8_config.h"
|
||||
#include "ard_protocol.h"
|
||||
|
||||
USB Usb;
|
||||
uint8_t state, rcode, addr = 1;
|
||||
uint8_t usb_data_buf[ARD_BUF_SIZE];
|
||||
|
||||
uint8_t desc_buf_val = 0;
|
||||
USB_DEVICE_DESCRIPTOR desc_buf;
|
||||
struct serial_desc_args sd_args;
|
||||
struct usb_xfer_args usb_args;
|
||||
|
||||
int i, chunk_i;
|
||||
int size, chunk_size;
|
||||
char cmd;
|
||||
|
||||
void recv_serial(uint8_t *target, int len)
|
||||
{
|
||||
for(i = 0; i < len; i = i + 1)
|
||||
{
|
||||
while(Serial.available() == 0);
|
||||
|
||||
if(target == NULL) Serial.read();
|
||||
else target[i] = (uint8_t) Serial.read();
|
||||
}
|
||||
}
|
||||
|
||||
void get_dev_descriptor()
|
||||
{
|
||||
if(!desc_buf_val)
|
||||
{
|
||||
Usb.getDevDescr(addr, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t * ) & desc_buf);
|
||||
desc_buf_val = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t send_usb(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
Usb.bytesWr(rSNDFIFO, len, buf);
|
||||
Usb.regWr(rSNDBC, len);
|
||||
Usb.regWr(rHXFR, tokOUT);
|
||||
while(!(Usb.regRd(rHIRQ) & bmHXFRDNIRQ));
|
||||
Usb.regWr(rHIRQ, bmHXFRDNIRQ);
|
||||
return (Usb.regRd(rHRSL) & 0x0f);
|
||||
}
|
||||
|
||||
uint8_t respond_rcode()
|
||||
{
|
||||
if(rcode)
|
||||
{
|
||||
Serial.write(PROT_FAIL_USB);
|
||||
Serial.write(rcode);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(ARDUINO_BAUD);
|
||||
while(Serial.available() > 0) Serial.read();
|
||||
|
||||
if(Usb.Init() == -1) Serial.write(PROT_FAIL_INITUSB);
|
||||
else Serial.write(PROT_SUCCESS);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
state = Usb.getUsbTaskState();
|
||||
while(state != USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE && state != USB_STATE_RUNNING)
|
||||
{
|
||||
Usb.Task();
|
||||
state = Usb.getUsbTaskState();
|
||||
}
|
||||
|
||||
if(state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE)
|
||||
{
|
||||
desc_buf_val = 0;
|
||||
}
|
||||
|
||||
if(Serial.available() > 0)
|
||||
{
|
||||
cmd = (char) Serial.read();
|
||||
switch(cmd)
|
||||
{
|
||||
case PROT_PARTIAL_CTRL_XFER:
|
||||
recv_serial((uint8_t * ) & usb_args, sizeof(struct usb_xfer_args));
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
rcode = Usb.ctrlReq_SETUP(addr, 0,
|
||||
usb_args.bmRequestType,
|
||||
usb_args.bRequest,
|
||||
usb_args.wValue & 0xFFu,
|
||||
(usb_args.wValue >> 8u) & 0xFFu,
|
||||
usb_args.wIndex,
|
||||
usb_args.data_len);
|
||||
if(respond_rcode()) break;
|
||||
|
||||
if(usb_args.bmRequestType & 0x80u)
|
||||
{
|
||||
Usb.regWr(rHCTL, bmRCVTOG1);
|
||||
rcode = Usb.dispatchPkt(tokIN, 0, 0);
|
||||
}
|
||||
else rcode = Usb.dispatchPkt(tokOUTHS, 0, 0);
|
||||
|
||||
if(respond_rcode()) break;
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
|
||||
case PROT_NO_ERROR_CTRL_XFER:
|
||||
recv_serial((uint8_t * ) & usb_args, sizeof(struct usb_xfer_args));
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
rcode = Usb.ctrlReq_SETUP(addr, 0,
|
||||
usb_args.bmRequestType,
|
||||
usb_args.bRequest,
|
||||
usb_args.wValue & 0xFFu,
|
||||
(usb_args.wValue >> 8u) & 0xFFu,
|
||||
usb_args.wIndex,
|
||||
usb_args.data_len);
|
||||
|
||||
if(usb_args.bmRequestType & 0x80u)
|
||||
{
|
||||
Usb.regWr(rHCTL, bmRCVTOG1);
|
||||
rcode = Usb.dispatchPkt(tokIN, 0, 0);
|
||||
}
|
||||
else rcode = Usb.dispatchPkt(tokOUTHS, 0, 0);
|
||||
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
|
||||
case PROT_NO_ERROR_CTRL_XFER_DATA:
|
||||
recv_serial((uint8_t * ) & usb_args, sizeof(struct usb_xfer_args));
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
rcode = Usb.ctrlReq_SETUP(addr, 0,
|
||||
usb_args.bmRequestType,
|
||||
usb_args.bRequest,
|
||||
usb_args.wValue & 0xFFu,
|
||||
(usb_args.wValue >> 8u) & 0xFFu,
|
||||
usb_args.wIndex,
|
||||
usb_args.data_len);
|
||||
Usb.regWr(rHCTL, bmSNDTOG0);
|
||||
rcode = send_usb(usb_data_buf, 0);
|
||||
|
||||
chunk_i = 0;
|
||||
while(chunk_i < usb_args.data_len)
|
||||
{
|
||||
if(usb_args.data_len - chunk_i > ARD_BUF_SIZE) chunk_size = ARD_BUF_SIZE;
|
||||
else chunk_size = usb_args.data_len - chunk_i;
|
||||
|
||||
recv_serial(usb_data_buf, chunk_size);
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
// i is the current data index
|
||||
i = 0;
|
||||
while(i < chunk_size)
|
||||
{
|
||||
if(chunk_size - i > 64) size = 64;
|
||||
else size = chunk_size - i;
|
||||
|
||||
rcode = send_usb(&usb_data_buf[i], size);
|
||||
i += size;
|
||||
}
|
||||
|
||||
chunk_i += chunk_size;
|
||||
}
|
||||
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
|
||||
case PROT_CTRL_XFER:
|
||||
recv_serial((uint8_t * ) & usb_args, sizeof(struct usb_xfer_args));
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
get_dev_descriptor();
|
||||
rcode = Usb.ctrlReq_SETUP(addr, 0,
|
||||
usb_args.bmRequestType,
|
||||
usb_args.bRequest,
|
||||
usb_args.wValue & 0xFFu,
|
||||
(usb_args.wValue >> 8u) & 0xFFu,
|
||||
usb_args.wIndex,
|
||||
usb_args.data_len);
|
||||
|
||||
if(usb_args.bmRequestType & 0x80u)
|
||||
{
|
||||
i = 0;
|
||||
Usb.regWr(rHCTL, bmRCVTOG1);
|
||||
|
||||
while(i < usb_args.data_len)
|
||||
{
|
||||
Usb.regWr(rHXFR, tokIN);
|
||||
|
||||
while(!(Usb.regRd(rHIRQ) & bmHXFRDNIRQ));
|
||||
Usb.regWr(rHIRQ, bmHXFRDNIRQ);
|
||||
|
||||
if(Usb.regRd(rHIRQ) & bmRCVDAVIRQ)
|
||||
{
|
||||
size = Usb.regRd(rRCVBC);
|
||||
Usb.bytesRd(rRCVFIFO, size, usb_data_buf);
|
||||
Usb.regWr(rHIRQ, bmRCVDAVIRQ);
|
||||
|
||||
Serial.write(size);
|
||||
Serial.write(usb_data_buf, size);
|
||||
i += size;
|
||||
|
||||
if(size != desc_buf.bMaxPacketSize0) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rcode = (Usb.regRd(rHRSL) & 0x0f);
|
||||
if(rcode == hrNAK) continue;
|
||||
|
||||
Serial.write(PROT_FAIL_USB);
|
||||
Serial.write(rcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Usb.regWr(rHXFR, tokOUTHS);
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk_i = 0;
|
||||
Usb.regWr(rHCTL, bmSNDTOG0);
|
||||
|
||||
rcode = send_usb(usb_data_buf, 0);
|
||||
while(chunk_i < usb_args.data_len)
|
||||
{
|
||||
if(usb_args.data_len - chunk_i > ARD_BUF_SIZE) chunk_size = ARD_BUF_SIZE;
|
||||
else chunk_size = usb_args.data_len - chunk_i;
|
||||
|
||||
recv_serial(usb_data_buf, chunk_size);
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
i = 0;
|
||||
while(i < chunk_size)
|
||||
{
|
||||
if(chunk_size - i > desc_buf.bMaxPacketSize0) size = desc_buf.bMaxPacketSize0;
|
||||
else size = chunk_size - i;
|
||||
|
||||
rcode = send_usb(&usb_data_buf[i], size);
|
||||
i += size;
|
||||
}
|
||||
|
||||
chunk_i += chunk_size;
|
||||
}
|
||||
|
||||
Usb.regWr(rHXFR, tokINHS);
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROT_RESET:
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
Usb.setUsbTaskState(USB_ATTACHED_SUBSTATE_RESET_DEVICE);
|
||||
while((state = Usb.getUsbTaskState()) != USB_STATE_RUNNING) Usb.Task();
|
||||
|
||||
Serial.write(PROT_SUCCESS);
|
||||
break;
|
||||
|
||||
case PROT_SERIAL_DESC:
|
||||
recv_serial((uint8_t * ) & sd_args, sizeof(struct serial_desc_args));
|
||||
Serial.write(PROT_ACK);
|
||||
|
||||
state = Usb.getUsbTaskState();
|
||||
if(state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE)
|
||||
{
|
||||
Serial.write(PROT_FAIL_NODEV);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dev_descriptor();
|
||||
if(desc_buf.idVendor != sd_args.dev_idVendor ||
|
||||
desc_buf.idProduct != sd_args.dev_idProduct)
|
||||
{
|
||||
Serial.write(PROT_FAIL_WRONGDEV);
|
||||
break;
|
||||
}
|
||||
|
||||
// multiplication by 2 is necessary here because iphone returns 16-bit characters
|
||||
Usb.getStrDescr(addr, 0, sd_args.len * 2, desc_buf.iSerialNumber, 0x0409, usb_data_buf);
|
||||
Serial.write(PROT_SUCCESS);
|
||||
|
||||
// not sure what the first byte is; skip it
|
||||
for(i = 1; i < sd_args.len + 1; i++)
|
||||
{
|
||||
Serial.write(((uint16_t *) usb_data_buf)[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
// default:
|
||||
// Serial.write(PROT_FAIL_BADCMD);
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user