diff --git a/Marlin/AO_FT810_Constants.h b/Marlin/AO_FT810_Constants.h index 9c5c67aed..15c7e9510 100644 --- a/Marlin/AO_FT810_Constants.h +++ b/Marlin/AO_FT810_Constants.h @@ -715,6 +715,7 @@ namespace FTDI { enum note_t { END_SONG = 0x00, + REST = 0x00, NOTE_C3 = 0x32, NOTE_D3 = 0x33, NOTE_D3S = 0x34, @@ -733,7 +734,8 @@ namespace FTDI { NOTE_F4 = 0x41, NOTE_F4S = 0x42, NOTE_G4 = 0x43, - NOTE_G4S = 0x44 + NOTE_G4S = 0x44, + NOTE_A4 = 0x45 }; } diff --git a/Marlin/AO_FT810_Functions.h b/Marlin/AO_FT810_Functions.h index d3200e4cf..fbb25de0f 100644 --- a/Marlin/AO_FT810_Functions.h +++ b/Marlin/AO_FT810_Functions.h @@ -304,7 +304,7 @@ class CLCD::CommandFifo { } template FORCEDINLINE void Cmd_Draw_Button_Text(int16_t x, int16_t y, int16_t w, int16_t h, T text, int16_t font, uint16_t options = OPT_CENTER) { Cmd_Draw_Text( - x + ((options & OPT_CENTERX) ? w/2 : 0), + x + ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0)), y + ((options & OPT_CENTERY) ? h/2 : h), text, font, options); } @@ -886,13 +886,14 @@ void CLCD::Init (void) { /* tiny_interval() downsamples a 32-bit millis() value into a 8-bit value which can record periods of - up to 4.096 seconds with a rougly 16 millisecond + a few seconds with a rougly 1/16th of second resolution. This allows us to measure small intervals without needing to use four-byte counters. - However, dues to wrap-arounds, this class may misfire - often and thus should only be used where memory savings - outweigh accuracy. + However, dues to wrap-arounds, this class may + have a burst of misfires every 16 seconds or so and + thus should only be used where this is harmless and + memory savings outweigh accuracy. */ class tiny_interval_t { private: @@ -903,12 +904,18 @@ class tiny_interval_t { } inline void wait_for(uint32_t ms) { - end = tiny_interval(millis() + ms); + uint32_t now = millis(); + end = tiny_interval(now + ms); + if(tiny_interval(now + ms*2) < end) { + // Avoid special case where timer + // might get wedged and stop firing. + end = 0; + } } inline bool elapsed() { - if(end == 0 || tiny_interval(millis()) > end) { - end = 0; + uint8_t now = tiny_interval(millis()); + if(now > end) { return true; } else { return false; @@ -929,22 +936,31 @@ class CLCD::SoundPlayer { const uint8_t WAIT = 0; + static const PROGMEM sound_t silence[]; + private: const sound_t *sequence; uint8_t next; + note_t frequencyToMidiNote(const uint16_t frequency); + public: static void setVolume(uint8_t volume); static void play(effect_t effect, note_t note = NOTE_C4); static bool soundPlaying(); void play(const sound_t* seq); + void playTone(const uint16_t frequency_hz, const uint16_t duration_ms); void onIdle(); bool hasMoreNotes() {return sequence != 0;}; }; +const PROGMEM CLCD::SoundPlayer::sound_t CLCD::SoundPlayer::silence[] = { + {SILENCE, END_SONG, 0} +}; + void CLCD::SoundPlayer::setVolume(uint8_t vol) { CLCD::Mem_Write8(REG_VOL_SOUND, vol); } @@ -961,9 +977,27 @@ void CLCD::SoundPlayer::play(effect_t effect, note_t note) { #endif } + +note_t CLCD::SoundPlayer::frequencyToMidiNote(const uint16_t frequency_hz) { + const float f0 = 440; + return note_t(NOTE_A4 + (log(frequency_hz)-log(f0))*12/log(2) + 0.5); +} + +// Plays a tone of a given frequency and duration. Since the FTDI FT810 only +// supports MIDI notes, we round down to the nearest note. + +void CLCD::SoundPlayer::playTone(const uint16_t frequency_hz, const uint16_t duration_ms) { + play(ORGAN, frequencyToMidiNote(frequency_hz)); + + // Schedule silence to squelch the note after the duration expires. + sequence = silence; + next = tiny_interval_t::tiny_interval(millis() + duration_ms); +} + void CLCD::SoundPlayer::play(const sound_t* seq) { sequence = seq; - next = tiny_interval_t::tiny_interval(millis()) + 1; + // Delaying the start of the sound seems to prevent glitches. Not sure why... + next = tiny_interval_t::tiny_interval(millis()+250); } bool CLCD::SoundPlayer::soundPlaying() { @@ -983,13 +1017,14 @@ void CLCD::SoundPlayer::onIdle() { if(ms == 0 && fx == SILENCE && nt == 0) { sequence = 0; + play(SILENCE, REST); } else { #if defined(UI_FRAMEWORK_DEBUG) #if defined (SERIAL_PROTOCOLLNPAIR) SERIAL_PROTOCOLLNPAIR("Scheduling note in ", ms); #endif #endif - next = (ms == WAIT) ? 0 : (tiny_millis + tiny_interval_t::tiny_interval(ms)); + next = (ms == WAIT) ? 0 : (tiny_interval_t::tiny_interval(millis() + ms)); play(fx, (nt == 0) ? NOTE_C4 : nt); sequence++; } diff --git a/Marlin/AO_FT810_UI_Screens.h b/Marlin/AO_FT810_UI_Screens.h index a5ffac53b..4903bbcef 100644 --- a/Marlin/AO_FT810_UI_Screens.h +++ b/Marlin/AO_FT810_UI_Screens.h @@ -24,7 +24,7 @@ // cache, so we reserve a large chunk of memory for the DL cache #define STATUS_SCREEN_DL_SIZE 2048 -#define CONFIRMATION_SCREEN_DL_SIZE 3072 +#define DIALOG_BOX_DL_SIZE 3072 #define N_ELEMENTS(a) (sizeof(a)/sizeof(a[0])) @@ -110,8 +110,8 @@ // in a union. The values should be initialized in the onEntry method. static union { - struct {uint8_t increment;} ValueAdjusters; - struct {uint8_t page, selected;} FilesScreen; + struct {uint8_t increment;} ValueAdjusters; + struct {uint8_t page, selected_tag;} FilesScreen; } screen_data; /************************* MENU SCREEN DECLARATIONS *************************/ @@ -193,6 +193,12 @@ class MenuScreen : public UIScreen { static bool onTouchStart(uint8_t tag); }; +class TuneScreen : public UIScreen { + public: + static void onRefresh(); + static bool onTouchStart(uint8_t tag); +}; + class CalibrationScreen : public UIScreen { public: static void onEntry(); @@ -272,6 +278,12 @@ class ZOffsetScreen : public ValueAdjusters { static bool onTouchHeld(uint8_t tag); }; +class FeedrateScreen : public ValueAdjusters { + public: + static void onRefresh(); + static bool onTouchHeld(uint8_t tag); +}; + class TemperatureScreen : public ValueAdjusters { public: static void onRefresh(); @@ -281,6 +293,8 @@ class TemperatureScreen : public ValueAdjusters { class FilesScreen : public UIScreen { private: static const char *getSelectedShortFilename(); + static uint8_t getTagForIndex(uint16_t index); + static uint16_t getIndexForTag(uint8_t tag); public: static void onEntry(); static void onRefresh(); @@ -298,10 +312,12 @@ SCREEN_TABLE { DECL_SCREEN(CalibrationScreen), DECL_SCREEN(StatusScreen), DECL_SCREEN(MenuScreen), + DECL_SCREEN(TuneScreen), DECL_SCREEN(MoveAxisScreen), DECL_SCREEN(AdvancedSettingsScreen), DECL_SCREEN(StepsScreen), DECL_SCREEN(ZOffsetScreen), + DECL_SCREEN(FeedrateScreen), DECL_SCREEN(TemperatureScreen), DECL_SCREEN(CalibrationRegistersScreen), DECL_SCREEN(FilesScreen), @@ -318,12 +334,14 @@ SCREEN_TABLE_POST enum { STATUS_SCREEN_CACHE, MENU_SCREEN_CACHE, - CONFIRMATION_SCREEN_CACHE, + TUNE_SCREEN_CACHE, + DIALOG_BOX_CACHE, ADVANCED_SETTINGS_SCREEN_CACHE, MOVE_AXIS_SCREEN_CACHE, TEMPERATURE_SCREEN_CACHE, STEPS_SCREEN_CACHE, ZOFFSET_SCREEN_CACHE, + FEEDRATE_SCREEN_CACHE, FILES_SCREEN_CACHE }; @@ -341,6 +359,7 @@ namespace Theme { const uint32_t y_axis = 0x005000; const uint32_t z_axis = 0x000050; const uint32_t e_axis = 0x000000; + const uint32_t feedrate = 0x000000; const uint32_t toggle_on = theme_light; const uint32_t toggle_off = theme_darkest; @@ -480,7 +499,7 @@ bool AboutScreen::onTouchStart(uint8_t tag) { /**************************** GENERIC DIALOG BOX SCREEN ****************************/ void DialogBoxBaseClass::show(const progmem_str lines[], size_t n_lines, progmem_str btn1, progmem_str btn2 ) { - CLCD::DLCache dlcache(CONFIRMATION_SCREEN_CACHE); + CLCD::DLCache dlcache(DIALOG_BOX_CACHE); CLCD::CommandFifo cmd; cmd.Cmd(CMD_DLSTART); @@ -507,7 +526,7 @@ void DialogBoxBaseClass::show(const progmem_str lines[], size_t n_lines, progmem cmd.Cmd(CMD_SWAP); cmd.Cmd_Execute(); - if(!dlcache.store(CONFIRMATION_SCREEN_DL_SIZE)) { + if(!dlcache.store(DIALOG_BOX_DL_SIZE)) { #if defined (SERIAL_PROTOCOLLNPAIR) SERIAL_PROTOCOLLN("Unable to set the confirmation message, not enough DL cache space"); #else @@ -519,7 +538,7 @@ void DialogBoxBaseClass::show(const progmem_str lines[], size_t n_lines, progmem } void DialogBoxBaseClass::onRefresh() { - CLCD::DLCache dlcache(CONFIRMATION_SCREEN_CACHE); + CLCD::DLCache dlcache(DIALOG_BOX_CACHE); CLCD::CommandFifo cmd; cmd.Cmd(CMD_DLSTART); @@ -1025,9 +1044,19 @@ bool StatusScreen::onTouchStart(uint8_t tag) { GOTO_SCREEN(ConfirmAbortPrint); break; case 3: GOTO_SCREEN(FilesScreen); break; - case 4: GOTO_SCREEN(MenuScreen); break; + case 4: + if(Marlin_LCD_API::isPrinting()) { + GOTO_SCREEN(TuneScreen); + } else { + GOTO_SCREEN(MenuScreen); + } + break; case 5: GOTO_SCREEN(TemperatureScreen); break; - case 6: GOTO_SCREEN(MoveAxisScreen); break; + case 6: + if(!Marlin_LCD_API::isPrinting()) { + GOTO_SCREEN(MoveAxisScreen); + } + break; } return true; } @@ -1104,6 +1133,68 @@ bool MenuScreen::onTouchStart(uint8_t tag) { return true; } +/************************************ TUNE SCREEN *******************************/ + +#if defined(LCD_PORTRAIT) + #define GRID_ROWS 5 + #define GRID_COLS 2 +#else + #define GRID_ROWS 3 + #define GRID_COLS 2 +#endif + +void TuneScreen::onRefresh() { + CLCD::DLCache dlcache(TUNE_SCREEN_CACHE); + CLCD::CommandFifo cmd; + cmd.Cmd(CMD_DLSTART); + + if(dlcache.hasData()) { + dlcache.append(); + } else { + cmd.Cmd_Set_Clear_Color(Theme::background); + cmd.Cmd_Clear(1,1,1); + + #if defined(LCD_PORTRAIT) + BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(2,1), F("Temperature"), MENU_BTN_STYLE); + BTN_TAG(3) BTN_ENABLED(0) BTN( BTN_POS(1,2), BTN_SIZE(2,1), F("Change Filament"), MENU_BTN_STYLE); + BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(2,1), F("Z Offset"), MENU_BTN_STYLE); + BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(1,4), BTN_SIZE(2,1), F("Print Speed"), MENU_BTN_STYLE); + #else + BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("Temperature"), MENU_BTN_STYLE); + BTN_TAG(3) BTN_ENABLED(0) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("Change Filament"), MENU_BTN_STYLE); + BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Z Offset"), MENU_BTN_STYLE); + BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(2,2), BTN_SIZE(2,1), F("Print Speed"), MENU_BTN_STYLE); + #endif + + #if defined(LCD_PORTRAIT) + #define MARGIN_T 15 + BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE); + #else + BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,3), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE); + #endif + + #define MARGIN_T 5 + + dlcache.store(); + } + + cmd.Cmd(DL_DISPLAY); + cmd.Cmd(CMD_SWAP); + cmd.Cmd_Execute(); +} + +bool TuneScreen::onTouchStart(uint8_t tag) { + switch(tag) { + case 1: GOTO_PREVIOUS(); break; + case 2: GOTO_SCREEN(TemperatureScreen); break; + case 4: GOTO_SCREEN(ZOffsetScreen); break; + case 5: GOTO_SCREEN(FeedrateScreen); break; + default: + return false; + } + return true; +} + /******************************* CONFIGURATION SCREEN ****************************/ #if defined(LCD_PORTRAIT) @@ -1487,11 +1578,17 @@ void MoveAxisScreen::onRefresh() { cmd.Cmd(CMD_DLSTART); /* Tag Label: Units: Color: Precision: */ - const heading_t h = { PSTR("Move Axis") }; - const adjuster_t x = {2, PSTR("X:"), PSTR("mm"), Theme::x_axis, 1 }; - const adjuster_t y = {4, PSTR("Y:"), PSTR("mm"), Theme::y_axis, 1 }; - const adjuster_t z = {6, PSTR("Z:"), PSTR("mm"), Theme::z_axis, 1 }; - const increment_t i = { 1 }; + const heading_t h = { PSTR("Move Axis") }; + const adjuster_t x = {2, PSTR("X:"), PSTR("mm"), Theme::x_axis, 1 }; + const adjuster_t y = {4, PSTR("Y:"), PSTR("mm"), Theme::y_axis, 1 }; + const adjuster_t z = {6, PSTR("Z:"), PSTR("mm"), Theme::z_axis, 1 }; + #if EXTRUDERS == 1 + const adjuster_t e0 = {8, PSTR("E:"), PSTR("mm"), Theme::e_axis, 1 }; + #else EXTRUDERS == 2 + const adjuster_t e0 = {8, PSTR("E0:"), PSTR("mm"), Theme::e_axis, 1 }; + const adjuster_t e1 = {10, PSTR("E1:"), PSTR("mm"), Theme::e_axis, 1 }; + #endif + const increment_t i = { 1 }; stacker_t s; if(dlcache.hasData()) { @@ -1502,6 +1599,10 @@ void MoveAxisScreen::onRefresh() { x.static_parts(s); y.static_parts(s); z.static_parts(s); + e0.static_parts(s); + #if EXTRUDERS == 2 + e1.static_parts(s); + #endif i.static_parts(s); dlcache.store(); } @@ -1510,6 +1611,10 @@ void MoveAxisScreen::onRefresh() { x.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::X)); y.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Y)); z.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Z)); + e0.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::E0)); + #if EXTRUDERS == 2 + e1.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::E1)); + #endif i.dynamic_parts(s); cmd.Cmd(DL_DISPLAY); @@ -1529,12 +1634,16 @@ bool MoveAxisScreen::onTouchHeld(uint8_t tag) { const float feedrate_mm_s = inc * TOUCH_REPEATS_PER_SECOND; switch(tag) { - case 2: axis = Marlin_LCD_API::X; inc *= -1; break; - case 3: axis = Marlin_LCD_API::X; inc *= 1; break; - case 4: axis = Marlin_LCD_API::Y; inc *= -1; break; - case 5: axis = Marlin_LCD_API::Y; inc *= 1; break; - case 6: axis = Marlin_LCD_API::Z; inc *= -1; break; - case 7: axis = Marlin_LCD_API::Z; inc *= 1; break; + case 2: axis = Marlin_LCD_API::X; inc *= -1; break; + case 3: axis = Marlin_LCD_API::X; inc *= 1; break; + case 4: axis = Marlin_LCD_API::Y; inc *= -1; break; + case 5: axis = Marlin_LCD_API::Y; inc *= 1; break; + case 6: axis = Marlin_LCD_API::Z; inc *= -1; break; + case 7: axis = Marlin_LCD_API::Z; inc *= 1; break; + case 8: axis = Marlin_LCD_API::E0; inc *= -1; break; + case 9: axis = Marlin_LCD_API::E0; inc *= 1; break; + case 10: axis = Marlin_LCD_API::E1; inc *= -1; break; + case 11: axis = Marlin_LCD_API::E1; inc *= 1; break; default: return false; } @@ -1724,6 +1833,50 @@ bool ZOffsetScreen::onTouchHeld(uint8_t tag) { return true; } +/***************************** FEEDRATE SCREEN ***************************/ + +void FeedrateScreen::onRefresh() { + CLCD::DLCache dlcache(FEEDRATE_SCREEN_CACHE); + CLCD::CommandFifo cmd; + cmd.Cmd(CMD_DLSTART); + + /* Tag Label: Units: Color: Precision: */ + const heading_t h = { PSTR("Print Speed") }; + const adjuster_t f = {4, PSTR("Speed"), PSTR("%"), Theme::feedrate, 0 }; + const increment_t i = { 0 }; + + stacker_t s; + if(dlcache.hasData()) { + dlcache.append(); + } else { + s.static_parts(); + h.static_parts(s); + f.static_parts(s); + i.static_parts(s); + dlcache.store(); + } + s.dynamic_parts(); + h.dynamic_parts(s); + f.dynamic_parts(s,Marlin_LCD_API::getFeedRate_percent()); + i.dynamic_parts(s); + + cmd.Cmd(DL_DISPLAY); + cmd.Cmd(CMD_SWAP); + cmd.Cmd_Execute(); +} + +bool FeedrateScreen::onTouchHeld(uint8_t tag) { + float inc = getIncrement(); + switch(tag) { + case 4: Marlin_LCD_API::setFeedrate_percent(Marlin_LCD_API::getFeedRate_percent() - inc); break; + case 5: Marlin_LCD_API::setFeedrate_percent(Marlin_LCD_API::getFeedRate_percent() + inc); break; + default: + return false; + } + onRefresh(); + return true; +} + /***************************** FILES SCREEN ***************************/ #if defined(LCD_PORTRAIT) @@ -1737,20 +1890,22 @@ bool ZOffsetScreen::onTouchHeld(uint8_t tag) { const uint16_t filesPerPage = GRID_ROWS - 4; void FilesScreen::onEntry() { - screen_data.FilesScreen.page = 0; - screen_data.FilesScreen.selected = 0xFF; + screen_data.FilesScreen.page = 0; + screen_data.FilesScreen.selected_tag = 0xFF; UIScreen::onEntry(); } const char *FilesScreen::getSelectedShortFilename() { - Marlin_LCD_API::Marlin_LCD_API::Media_Iterator iterator(screen_data.FilesScreen.page * filesPerPage); + Marlin_LCD_API::Media_Iterator iterator(getIndexForTag(screen_data.FilesScreen.selected_tag)); + return iterator.shortFilename(); +} - while(iterator.hasMore()) { - if(screen_data.FilesScreen.selected == iterator.value() + 1) { - return iterator.shortFilename(); - } - iterator.next(); - } +uint8_t FilesScreen::getTagForIndex(uint16_t fileIndex) { + return fileIndex + 1; +} + +uint16_t FilesScreen::getIndexForTag(uint8_t tag) { + return tag - 1; } void FilesScreen::onRefresh() { @@ -1761,18 +1916,32 @@ void FilesScreen::onRefresh() { cmd.Cmd_Set_Clear_Color(Theme::background); cmd.Cmd_Clear(1,1,1); - Marlin_LCD_API::Marlin_LCD_API::Media_Iterator iterator(screen_data.FilesScreen.page * filesPerPage); - #define MARGIN_T 0 #define MARGIN_B 0 - while(iterator.hasMore()) { - const uint16_t tag = iterator.value() + 1; - BTN_TAG(tag) - RGB(screen_data.FilesScreen.selected == tag ? Theme::files_selected : Theme::background) - BTN( BTN_POS(1,tag+2), BTN_SIZE(6,1), F(""), FONT_SML, OPT_FLAT); - BTX( BTN_POS(1,tag+2), BTN_SIZE(6,1), iterator.filename(), FONT_LRG, OPT_CENTERY); - iterator.next(); + bool dirSelected = false; + + Marlin_LCD_API::Media_Iterator iterator(screen_data.FilesScreen.page * filesPerPage); + if(iterator.count()) { + do { + const uint16_t tag = getTagForIndex(iterator.value()); + const bool isDir = iterator.isDirectory(); + + BTN_TAG(tag) + if(screen_data.FilesScreen.selected_tag == tag) { + RGB(Theme::files_selected) + dirSelected = isDir; + } else { + RGB(Theme::background) + } + BTN( BTN_POS(1,tag+2), BTN_SIZE(6,1), F(""), FONT_SML, OPT_FLAT); + BTX( BTN_POS(1,tag+2), BTN_SIZE(6,1), iterator.filename(), FONT_LRG, OPT_CENTERY); + if(isDir) { + BTX( BTN_POS(1,tag+2), BTN_SIZE(6,1), F("> "), FONT_LRG, OPT_CENTERY | OPT_RIGHTX); + } + + iterator.next(); + } while(iterator.hasMore()); } #define MARGIN_T 5 @@ -1781,7 +1950,8 @@ void FilesScreen::onRefresh() { const uint16_t pageCount = iterator.count() / filesPerPage + 1; const bool prevEnabled = screen_data.FilesScreen.page > 0; const bool nextEnabled = screen_data.FilesScreen.page < (pageCount - 1); - const bool fileSelected = screen_data.FilesScreen.selected != 0xFF; + const bool itemSelected = screen_data.FilesScreen.selected_tag != 0xFF; + const uint8_t backTag = Marlin_LCD_API::isAtRootDir() ? 240 : 245; char page_str[15]; sprintf_P(page_str, PSTR("Page %d of %d"), screen_data.FilesScreen.page + 1, pageCount); @@ -1794,14 +1964,16 @@ void FilesScreen::onRefresh() { if(nextEnabled) {BTN_TAG(242); BTN( BTN_POS(6,1), BTN_SIZE(1,2), F(">"), MENU_BTN_STYLE);} #define MARGIN_T 15 + BTN_TAG(backTag) THEME(back_btn) BTN( BTN_POS(5,13), BTN_SIZE(2,2), F("Back"), MENU_BTN_STYLE); - BTN_TAG(240) THEME(back_btn) - BTN( BTN_POS(5,13), BTN_SIZE(2,2), F("Back"), MENU_BTN_STYLE); - - BTN_ENABLED(fileSelected) - BTN_TAG(243); BTN( BTN_POS(1,13), BTN_SIZE(4,2), F("Print"), MENU_BTN_STYLE); + BTN_ENABLED(itemSelected) + if(dirSelected) { + BTN_TAG(244); BTN( BTN_POS(1,13), BTN_SIZE(4,2), F("Open"), MENU_BTN_STYLE); + } else { + BTN_TAG(243); BTN( BTN_POS(1,13), BTN_SIZE(4,2), F("Print"), MENU_BTN_STYLE); + } #else - BTN_TAG(240) THEME(back_btn) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("Back"), MENU_BTN_STYLE); + BTN_TAG(backTag) THEME(back_btn) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("Back"), MENU_BTN_STYLE); #endif #define MARGIN_T 5 @@ -1818,14 +1990,20 @@ bool FilesScreen::onTouchStart(uint8_t tag) { case 242: screen_data.FilesScreen.page++; break; case 243: Marlin_LCD_API::printFromSDCard(getSelectedShortFilename()); - sound.play(start_print); lcd_setstatusPGM(PSTR("Print Starting"), 0); GOTO_SCREEN(StatusScreen); + sound.play(start_print); return true; + case 244: + Marlin_LCD_API::changeDir(getSelectedShortFilename()); + break; + case 245: + Marlin_LCD_API::upDir(); + break; default: if(tag < 240) { - if(screen_data.FilesScreen.selected != tag) { - screen_data.FilesScreen.selected = tag; + if(screen_data.FilesScreen.selected_tag != tag) { + screen_data.FilesScreen.selected_tag = tag; } else { // Double clicked. } @@ -2004,3 +2182,7 @@ void Marlin_LCD_API::onCardRemoved() { lcd_setstatusPGM(PSTR(MSG_SD_REMOVED), 0); sound.play(card_removed); } + +void Marlin_LCD_API::onPlayTone(const uint16_t frequency, const uint16_t duration) { + sound.playTone(frequency, duration); +} diff --git a/Marlin/AO_FT810_UI_Sounds.h b/Marlin/AO_FT810_UI_Sounds.h index 211e40a28..383009795 100644 --- a/Marlin/AO_FT810_UI_Sounds.h +++ b/Marlin/AO_FT810_UI_Sounds.h @@ -61,9 +61,12 @@ const PROGMEM CLCD::SoundPlayer::sound_t c_maj_arpeggio[] = { const PROGMEM CLCD::SoundPlayer::sound_t start_print[] = { {TRUMPET, NOTE_A3, 4}, + {SILENCE, REST, 1}, {TRUMPET, NOTE_A3, 2}, + {SILENCE, REST, 1}, {TRUMPET, NOTE_A3, 2}, - {TRUMPET, NOTE_E4, 16}, + {SILENCE, REST, 1}, + {TRUMPET, NOTE_E4, 10}, {SILENCE, END_SONG, 0} }; diff --git a/Marlin/AO_UI_Marlin_LCD_API.h b/Marlin/AO_UI_Marlin_LCD_API.h index 5aaa3f41a..1c6032bb9 100644 --- a/Marlin/AO_UI_Marlin_LCD_API.h +++ b/Marlin/AO_UI_Marlin_LCD_API.h @@ -15,6 +15,9 @@ * location: . * ****************************************************************************/ +#ifndef __MARLIN_LCD_API_H__ +#define __MARLIN_LCD_API_H__ + class Marlin_LCD_API { public: typedef const __FlashStringHelper *progmem_str; @@ -38,7 +41,7 @@ class Marlin_LCD_API { static float getAxisSteps_per_mm(const axis_t axis); static uint8_t getProgress_percent(); static uint32_t getProgress_seconds_elapsed(); - static uint8_t getFeedRate_percent(); + static float getFeedRate_percent(); static float getZOffset_mm(); static bool isAxisPositionKnown(const axis_t axis); static bool isMoving(); @@ -50,6 +53,7 @@ class Marlin_LCD_API { static void setAxisPosition_mm(const axis_t axis, float position, float _feedrate_mm_s); static void setAxisSteps_per_mm(const axis_t axis, float steps_per_mm); static void incrementZOffset_mm(const float z_offset); + static void setFeedrate_percent(const float percent); static void runGCode(progmem_str gcode); @@ -58,6 +62,7 @@ class Marlin_LCD_API { static void initMedia(); static void checkMedia(); static bool isPrintingFromMedia(); + static bool isPrinting(); static bool isMediaInserted(); static void stopPrint(); static void pausePrint(); @@ -66,10 +71,14 @@ class Marlin_LCD_API { static void onCardInserted(); static void onCardRemoved(); static void onPrinterKilled(const char* lcd_msg); + static void onPlayTone(const uint16_t frequency, const uint16_t duration); static uint16_t getMediaFileCount(); static void printFromSDCard(const char *filename); + static void changeDir(const char *dirname); + static void upDir(); + static bool isAtRootDir(); class Media_Iterator; }; @@ -79,7 +88,7 @@ class Marlin_LCD_API::Media_Iterator { uint16_t index; uint16_t num_files; public: - Media_Iterator(uint16_t start_index = 0); + Media_Iterator(uint16_t start_index /* = 0*/); bool hasMore(); void seek(uint16_t); void next(); @@ -88,6 +97,7 @@ class Marlin_LCD_API::Media_Iterator { const char *filename(); uint16_t value() {return index;} uint16_t count() {return num_files;} + bool isDirectory(); }; #if defined(MSG_MARLIN) @@ -188,7 +198,7 @@ uint32_t Marlin_LCD_API::getProgress_seconds_elapsed() { return elapsed.value; } -uint8_t Marlin_LCD_API::getFeedRate_percent() { +float Marlin_LCD_API::getFeedRate_percent() { return feedrate_percentage; } @@ -226,10 +236,27 @@ void Marlin_LCD_API::setFan_percent(const uint8_t fan, float percent) { } } +void Marlin_LCD_API::setFeedrate_percent(const float percent) { + feedrate_percentage = clamp(percent, 10, 500); +} + void Marlin_LCD_API::printFromSDCard(const char *filename) { card.openAndPrintFile(filename); } +void Marlin_LCD_API::changeDir(const char *dirname) { + card.chdir(dirname); +} + +void Marlin_LCD_API::upDir() { + card.updir(); +} + +bool Marlin_LCD_API::isAtRootDir() { + card.getWorkDirName(); + return card.filename[0] == '/'; +} + void lcd_setstatusPGM(const char * const message, int8_t level /* = 0 */); uint8_t lcd_sd_status; @@ -272,8 +299,17 @@ bool Marlin_LCD_API::isPrintingFromMedia() { #endif } +bool Marlin_LCD_API::isPrinting() { + return (planner.movesplanned() || IS_SD_PRINTING || + #if ENABLED(SDSUPPORT) + (card.cardOK && card.isFileOpen())); + #else + false; + #endif +} + bool Marlin_LCD_API::isMediaInserted() { - #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) + #if ENABLED(SDSUPPORT) return IS_SD_INSERTED; #else return false; @@ -324,7 +360,7 @@ Marlin_LCD_API::Media_Iterator::Media_Iterator(uint16_t start_index /* = 0*/) { } bool Marlin_LCD_API::Media_Iterator::hasMore() { - return index < (num_files - 1); + return (index < (num_files - 1)) && (num_files > 0); } void Marlin_LCD_API::Media_Iterator::next() { @@ -349,7 +385,7 @@ void Marlin_LCD_API::Media_Iterator::seek(uint16_t index) { } const char *Marlin_LCD_API::Media_Iterator::filename() { - return card.longFilename[0] ? card.longFilename : card.filename; + return (card.longFilename && card.longFilename[0]) ? card.longFilename : card.filename; } const char *Marlin_LCD_API::Media_Iterator::shortFilename() { @@ -359,4 +395,10 @@ const char *Marlin_LCD_API::Media_Iterator::shortFilename() { const char *Marlin_LCD_API::Media_Iterator::longFilename() { return card.longFilename; } -#endif \ No newline at end of file + +bool Marlin_LCD_API::Media_Iterator::isDirectory() { + return card.filenameIsDir; +} +#endif + +#endif MARLIN_LCD_API__MARLIN_LCD_API_H__ \ No newline at end of file diff --git a/Marlin/Conditionals_LulzBot.h b/Marlin/Conditionals_LulzBot.h index bb3a65346..432828a58 100644 --- a/Marlin/Conditionals_LulzBot.h +++ b/Marlin/Conditionals_LulzBot.h @@ -13,7 +13,7 @@ * got disabled. */ -#define LULZBOT_FW_VERSION ".17" // Change this with each update +#define LULZBOT_FW_VERSION ".18" // Change this with each update #if ( \ !defined(LULZBOT_Gladiola_Mini) && \ @@ -143,6 +143,7 @@ #define LULZBOT_USE_32_MICROSTEPS_ON_Z #define LULZBOT_UUID "e5502411-d46d-421d-ba3a-a20126d7930f" #define LULZBOT_USE_EXPERIMENTAL_FEATURES + #define LULZBOT_USE_USB_STICK #endif #if defined(LULZBOT_Quiver_TAZ7) @@ -204,6 +205,7 @@ #define LULZBOT_USE_32_MICROSTEPS_ON_Z #define LULZBOT_UUID "e5502411-d46d-421d-ba3a-a20126d7930f" #define LULZBOT_USE_EXPERIMENTAL_FEATURES + #define LULZBOT_USE_USB_STICK #endif /****************************** DEBUGGING OPTIONS *******************************/ @@ -1800,7 +1802,7 @@ #else #define LCD_IS_FT800 #endif - #define UI_FRAMEWORK_DEBUG + //#define UI_FRAMEWORK_DEBUG #define LULZBOT_SDSUPPORT #define LULZBOT_DISABLE_SD_DETECT_INVERTED #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d47396079..635a817be 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -520,7 +520,7 @@ static millis_t stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL // Buzzer - I2C on the LCD or a BEEPER_PIN #if ENABLED(LCD_USE_I2C_BUZZER) #define BUZZ(d,f) lcd_buzz(d, f) -#elif PIN_EXISTS(BEEPER) +#elif PIN_EXISTS(BEEPER) || defined(LULZBOT_USE_TOUCH_UI) Buzzer buzzer; #define BUZZ(d,f) buzzer.tone(d, f) #else diff --git a/Marlin/Sd2Card.cpp b/Marlin/Sd2Card.cpp index 6683e4b4f..dd202ea58 100644 --- a/Marlin/Sd2Card.cpp +++ b/Marlin/Sd2Card.cpp @@ -28,7 +28,12 @@ */ #include "MarlinConfig.h" -#if ENABLED(SDSUPPORT) +#if defined(LULZBOT_USE_USB_STICK) + #undef MACROS_H + #include "usb-flashdrive/Fake_Sd2Card_impl.h" +#endif + +#if ENABLED(SDSUPPORT) && not defined(LULZBOT_USE_USB_STICK) #include "Sd2Card.h" diff --git a/Marlin/SdVolume.h b/Marlin/SdVolume.h index 7cde194eb..2d285ef62 100644 --- a/Marlin/SdVolume.h +++ b/Marlin/SdVolume.h @@ -35,7 +35,11 @@ #define _SDVOLUME_H_ #include "SdFatConfig.h" -#include "Sd2Card.h" +#if defined(LULZBOT_USE_USB_STICK) + #include "usb-flashdrive/Fake_Sd2Card.h" +#else + #include "Sd2Card.h" +#endif #include "SdFatStructs.h" //============================================================================== diff --git a/Marlin/buzzer.h b/Marlin/buzzer.h index 530b72968..b41204397 100644 --- a/Marlin/buzzer.h +++ b/Marlin/buzzer.h @@ -30,6 +30,10 @@ #include "MarlinConfig.h" +#if ENABLED(LULZBOT_USE_TOUCH_UI) + #include "AO_UI_Marlin_LCD_API.h" +#endif + #define TONE_QUEUE_LENGTH 4 /** @@ -128,7 +132,11 @@ class Buzzer { this->state.endtime = now + this->state.tone.duration; if (this->state.tone.frequency > 0) { - #if ENABLED(SPEAKER) + #if ENABLED(LULZBOT_USE_TOUCH_UI) + CRITICAL_SECTION_START; + Marlin_LCD_API::onPlayTone(this->state.tone.frequency, this->state.tone.duration); + CRITICAL_SECTION_END; + #elif ENABLED(SPEAKER) CRITICAL_SECTION_START; ::tone(BEEPER_PIN, this->state.tone.frequency, this->state.tone.duration); CRITICAL_SECTION_END; diff --git a/Marlin/pins_EINSYRAMBO.h b/Marlin/pins_EINSYRAMBO.h index e56d75743..e8f2e9d42 100644 --- a/Marlin/pins_EINSYRAMBO.h +++ b/Marlin/pins_EINSYRAMBO.h @@ -189,7 +189,9 @@ // #if ENABLED(ULTRA_LCD) || defined(LULZBOT_USE_TOUCH_UI) - #define KILL_PIN 32 + #if not defined(LULZBOT_DISABLE_KILL_BUTTON) + #define KILL_PIN 32 + #endif #if ENABLED(NEWPANEL) || defined(LULZBOT_USE_TOUCH_UI) @@ -215,7 +217,9 @@ #define BTN_EN2 72 #define BTN_ENC 9 // the click - #define SD_DETECT_PIN 15 + #if not defined(LULZBOT_USE_USB_STICK) + #define SD_DETECT_PIN 15 + #endif #endif // NEWPANEL #endif // ULTRA_LCD diff --git a/Marlin/usb-flashdrive/Fake_Sd2Card.h b/Marlin/usb-flashdrive/Fake_Sd2Card.h new file mode 100644 index 000000000..9d228d518 --- /dev/null +++ b/Marlin/usb-flashdrive/Fake_Sd2Card.h @@ -0,0 +1,85 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * \file + * \brief Sd2Card class for V2 SD/SDHC cards + */ + +#ifndef _FAKE_SD2CARD_H_ +#define _FAKE_SD2CARD_H_ + +#include "SdFatConfig.h" +#include "SdInfo.h" + +// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6 +uint8_t const SPI_FULL_SPEED = 0, // Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). + SPI_HALF_SPEED = 1, // Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). + SPI_QUARTER_SPEED = 2, // Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). + SPI_EIGHTH_SPEED = 3, // Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). + SPI_SIXTEENTH_SPEED = 4; // Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). + +/** + * define SOFTWARE_SPI to use bit-bang SPI + */ +#if MEGA_SOFT_SPI + #define SOFTWARE_SPI +#elif USE_SOFTWARE_SPI + #define SOFTWARE_SPI +#endif + +// SPI pin definitions - do not edit here - change in SdFatConfig.h +#if DISABLED(SOFTWARE_SPI) + // hardware pin defs + #define SD_CHIP_SELECT_PIN SS_PIN // The default chip select pin for the SD card is SS. + // The following three pins must not be redefined for hardware SPI. + #define SPI_MOSI_PIN MOSI_PIN // SPI Master Out Slave In pin + #define SPI_MISO_PIN MISO_PIN // SPI Master In Slave Out pin + #define SPI_SCK_PIN SCK_PIN // SPI Clock pin +#else // SOFTWARE_SPI + #define SD_CHIP_SELECT_PIN SOFT_SPI_CS_PIN // SPI chip select pin + #define SPI_MOSI_PIN SOFT_SPI_MOSI_PIN // SPI Master Out Slave In pin + #define SPI_MISO_PIN SOFT_SPI_MISO_PIN // SPI Master In Slave Out pin + #define SPI_SCK_PIN SOFT_SPI_SCK_PIN // SPI Clock pin +#endif // SOFTWARE_SPI + +/** + * \class Sd2Card + * \brief Raw access to SD and SDHC flash memory cards. + */ +class Sd2Card { + public: + + Sd2Card(); + + /** + * Initialize an SD flash memory card with default clock rate and chip + * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). + * + * \return true for success or false for failure. + */ + bool init(uint8_t sckRateID = 0, uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); + bool readBlock(uint32_t block, uint8_t* dst); + bool writeBlock(uint32_t blockNumber, const uint8_t* src); +}; + +#endif // _FAKE_SD2CARD_H_ diff --git a/Marlin/usb-flashdrive/Fake_Sd2Card_impl.h b/Marlin/usb-flashdrive/Fake_Sd2Card_impl.h new file mode 100644 index 000000000..6d44d53af --- /dev/null +++ b/Marlin/usb-flashdrive/Fake_Sd2Card_impl.h @@ -0,0 +1,147 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/******************************************************************************************** + * This program/sketch is used to run a USB Thumb Drive. * + * * + * NOTE - This Arduino Sketch has been modified to initialize a MAX3421E USB Host Interface * + * chip, write 3 test files, print out the directory of the thumb drive and print out the * + * contents of a short .txt file. * + * * + * The code is leveraged from the following: * + * * + * Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. * + * * + * This software may be distributed and modified under the terms of the GNU * + * General Public License version 2 (GPL2) as published by the Free Software * + * Foundation and appearing in the file GPL2.TXT included in the packaging of * + * this file. Please note that GPL2 Section 2[b] requires that all works based * + * on this software must also be made publicly available under the terms of * + * the GPL2 ("Copyleft"). * + * * + * Contact information * + * ------------------- * + * * + * Circuits At Home, LTD * + * Web : http://www.circuitsathome.com * + * e-mail : support@circuitsathome.com * + * * + * SPECIAL NOTE - In order to work with a modified Eisny or RAMBo, the SPI chip select pin * + * (CS) (D10) has been remapped from PORTB Pin-4 to PORTB Pin-0. This has been done in the * + * __AVR_ATmega2560__ section of the avrpins.h file. * + * * + ********************************************************************************************/ + +#include + +//#define _usb_h_ + +#include "Marlin.h" +#include "../watchdog.h" + +#undef MACROS_H + +#define USB_HOST_SERIAL customizedSerial + +#include "lib/masstorage.h" +#include "lib/masstorage.cpp" +#include "lib/message.cpp" +#include "lib/parsetools.cpp" +#include "lib/Usb.cpp" + + +#include "Fake_Sd2Card.h" + +#define MAX_USB_RST 7 + +// USB host objects.v +USB usb; +BulkOnly bulk(&usb); + +#define error(msg) {Serial.print("Error: "); Serial.println(msg);} + +#define TIMEOUT_MILLIS 4000 + +//------------------------------------------------------------------------------ +bool initUSB(USB* usb) { + uint8_t current_state = 0; + uint32_t m = millis(); + + for (uint8_t i = 0; usb->Init(1000) == -1; i++) + { + SERIAL_ECHOLNPGM("No USB HOST Shield?"); + watchdog_reset(); + if (i > 10) { + return false; + } + } + + usb->vbusPower(vbus_on); + + while ((millis() - m) < TIMEOUT_MILLIS) { + usb->Task(); + current_state = usb->getUsbTaskState(); + if(current_state == USB_STATE_RUNNING) { + return true; + } + watchdog_reset(); + } + return false; +} + +Sd2Card::Sd2Card() { +}; + +bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { + if (!initUSB(&usb)) + { + SERIAL_ECHOLNPGM("initUSB failed"); + } + else + { + SERIAL_ECHOLNPGM("USB Initialized\n"); + } + + if(!bulk.LUNIsGood(0)) { + SERIAL_ECHOLNPGM("LUN zero is not good\n"); + return false; + } + + SERIAL_ECHOLNPAIR("LUN Capacity: ",bulk.GetCapacity(0)); + + const uint32_t sectorSize = bulk.GetSectorSize(0); + if(sectorSize != 512) { + SERIAL_ECHOLNPAIR("Expecting sector size of 512, got: ",sectorSize); + return false; + } + + return true; +} + +bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) { + return bulk.Read(0, block, 512, 1, dst) == 0; +} + +bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { + return bulk.Write(0, blockNumber, 512, 1, src) == 0; +} + diff --git a/Marlin/usb-flashdrive/lib/Usb.cpp b/Marlin/usb-flashdrive/lib/Usb.cpp new file mode 100644 index 000000000..a9fbcd38b --- /dev/null +++ b/Marlin/usb-flashdrive/lib/Usb.cpp @@ -0,0 +1,812 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +/* USB functions */ + +#include "Usb.h" + +static uint8_t usb_error = 0; +static uint8_t usb_task_state; + +/* constructor */ +USB::USB() : bmHubPre(0) { + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine + init(); +} + +/* Initialize data structures */ +void USB::init() { + //devConfigIndex = 0; + bmHubPre = 0; +} + +uint8_t USB::getUsbTaskState(void) { + return ( usb_task_state); +} + +void USB::setUsbTaskState(uint8_t state) { + usb_task_state = state; +} + +EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) { + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); + + if(!p || !p->epinfo) + return NULL; + + EpInfo *pep = p->epinfo; + + for(uint8_t i = 0; i < p->epcount; i++) { + if((pep)->epAddr == ep) + return pep; + + pep++; + } + return NULL; +} + +/* set device table entry */ + +/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */ +uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) { + if(!eprecord_ptr) + return USB_ERROR_INVALID_ARGUMENT; + + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->address.devAddress = addr; + p->epinfo = eprecord_ptr; + p->epcount = epcount; + + return 0; +} + +uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit) { + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if(!p->epinfo) + return USB_ERROR_EPINFO_IS_NULL; + + *ppep = getEpInfoEntry(addr, ep); + + if(!*ppep) + return USB_ERROR_EP_NOT_FOUND_IN_TBL; + + nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower)); + nak_limit--; + /* + USBTRACE2("\r\nAddress: ", addr); + USBTRACE2(" EP: ", ep); + USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower); + USBTRACE2(" NAK Limit: ", nak_limit); + USBTRACE("\r\n"); + */ + regWr(rPERADDR, addr); //set peripheral address + + uint8_t mode = regRd(rMODE); + + //Serial.print("\r\nMode: "); + //Serial.println( mode, HEX); + //Serial.print("\r\nLS: "); + //Serial.println(p->lowspeed, HEX); + + + + // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise + regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); + + return 0; +} + +/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ +/* depending on request. Actual requests are defined as inlines */ +/* return codes: */ +/* 00 = success */ + +/* 01-0f = non-zero HRSLT */ +uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, + uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) { + bool direction = false; //request direction, IN or OUT + uint8_t rcode; + SETUP_PKT setup_pkt; + + EpInfo *pep = NULL; + uint16_t nak_limit = 0; + + rcode = SetAddress(addr, ep, &pep, nak_limit); + + if(rcode) + return rcode; + + direction = ((bmReqType & 0x80) > 0); + + /* fill in setup packet */ + setup_pkt.ReqType_u.bmRequestType = bmReqType; + setup_pkt.bRequest = bRequest; + setup_pkt.wVal_u.wValueLo = wValLo; + setup_pkt.wVal_u.wValueHi = wValHi; + setup_pkt.wIndex = wInd; + setup_pkt.wLength = total; + + bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO + + rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet + + if(rcode) //return HRSLT if not zero + return ( rcode); + + if(dataptr != NULL) //data stage, if present + { + if(direction) //IN transfer + { + uint16_t left = total; + + pep->bmRcvToggle = 1; //bmRCVTOG1; + + while(left) { + // Bytes read into buffer + uint16_t read = nbytes; + //uint16_t read = (leftbmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; + continue; + } + + if(rcode) + return rcode; + + // Invoke callback function if inTransfer completed successfully and callback function pointer is specified + if(!rcode && p) + ((USBReadParser*)p)->Parse(read, dataptr, total - left); + + left -= read; + + if(read < nbytes) + break; + } + } else //OUT transfer + { + pep->bmSndToggle = 1; //bmSNDTOG1; + rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); + } + if(rcode) //return error + return ( rcode); + } + // Status stage + return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction +} + +/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ +/* Keep sending INs and writes data to memory area pointed by 'data' */ + +/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, + fe USB xfer timeout */ +uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) { + EpInfo *pep = NULL; + uint16_t nak_limit = 0; + + uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); + + if(rcode) { + USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81); + USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81); + USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81); + return rcode; + } + return InTransfer(pep, nak_limit, nbytesptr, data); +} + +uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) { + uint8_t rcode = 0; + uint8_t pktsize; + + uint16_t nbytes = *nbytesptr; + //printf("Requesting %i bytes ", nbytes); + uint8_t maxpktsize = pep->maxPktSize; + + *nbytesptr = 0; + regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value + + // use a 'break' to exit this loop + while(1) { + rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS. + if(rcode == hrTOGERR) { + // yes, we flip it wrong here so that next time it is actually correct! + pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; + regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value + continue; + } + if(rcode) { + //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode); + break; //should be 0, indicating ACK. Else return error code. + } + /* check for RCVDAVIRQ and generate error if not present */ + /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */ + if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) { + //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n"); + rcode = 0xf0; //receive error + break; + } + pktsize = regRd(rRCVBC); //number of received bytes + //printf("Got %i bytes \r\n", pktsize); + // This would be OK, but... + //assert(pktsize <= nbytes); + if(pktsize > nbytes) { + // This can happen. Use of assert on Arduino locks up the Arduino. + // So I will trim the value, and hope for the best. + //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize); + pktsize = nbytes; + } + + int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); + + if(mem_left < 0) + mem_left = 0; + + data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); + + regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer + *nbytesptr += pktsize; // add this packet's byte count to total transfer length + + /* The transfer is complete under two conditions: */ + /* 1. The device sent a short packet (L.T. maxPacketSize) */ + /* 2. 'nbytes' have been transferred. */ + if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? + { + // Save toggle value + pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0; + //printf("\r\n"); + rcode = 0; + break; + } // if + } //while( 1 ) + return ( rcode); +} + +/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ +/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */ + +/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */ +uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) { + EpInfo *pep = NULL; + uint16_t nak_limit = 0; + + uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); + + if(rcode) + return rcode; + + return OutTransfer(pep, nak_limit, nbytes, data); +} + +uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) { + uint8_t rcode = hrSUCCESS, retry_count; + uint8_t *data_p = data; //local copy of the data pointer + uint16_t bytes_tosend, nak_count; + uint16_t bytes_left = nbytes; + + uint8_t maxpktsize = pep->maxPktSize; + + if(maxpktsize < 1 || maxpktsize > 64) + return USB_ERROR_INVALID_MAX_PKT_SIZE; + + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + + regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value + + while(bytes_left) { + retry_count = 0; + nak_count = 0; + bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; + bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO + regWr(rSNDBC, bytes_tosend); //set number of bytes + regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet + while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ + regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ + rcode = (regRd(rHRSL) & 0x0f); + + while(rcode && ((long)(millis() - timeout) < 0L)) { + switch(rcode) { + case hrNAK: + nak_count++; + if(nak_limit && (nak_count == nak_limit)) + goto breakout; + //return ( rcode); + break; + case hrTIMEOUT: + retry_count++; + if(retry_count == USB_RETRY_LIMIT) + goto breakout; + //return ( rcode); + break; + case hrTOGERR: + // yes, we flip it wrong here so that next time it is actually correct! + pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; + regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value + break; + default: + goto breakout; + }//switch( rcode + + /* process NAK according to Host out NAK bug */ + regWr(rSNDBC, 0); + regWr(rSNDFIFO, *data_p); + regWr(rSNDBC, bytes_tosend); + regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet + while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ + regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ + rcode = (regRd(rHRSL) & 0x0f); + }//while( rcode && .... + bytes_left -= bytes_tosend; + data_p += bytes_tosend; + }//while( bytes_left... +breakout: + + pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle + return ( rcode); //should be 0 in all cases +} +/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */ +/* If NAK, tries to re-send up to nak_limit times */ +/* If nak_limit == 0, do not count NAKs, exit after timeout */ +/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */ + +/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ +uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) { + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + uint8_t tmpdata; + uint8_t rcode = hrSUCCESS; + uint8_t retry_count = 0; + uint16_t nak_count = 0; + + while((long)(millis() - timeout) < 0L) { + regWr(rHXFR, (token | ep)); //launch the transfer + rcode = USB_ERROR_TRANSFER_TIMEOUT; + + while((long)(millis() - timeout) < 0L) //wait for transfer completion + { + tmpdata = regRd(rHIRQ); + + if(tmpdata & bmHXFRDNIRQ) { + regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt + rcode = 0x00; + break; + }//if( tmpdata & bmHXFRDNIRQ + + }//while ( millis() < timeout + + //if (rcode != 0x00) //exit if timeout + // return ( rcode); + + rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result + + switch(rcode) { + case hrNAK: + nak_count++; + if(nak_limit && (nak_count == nak_limit)) + return (rcode); + break; + case hrTIMEOUT: + retry_count++; + if(retry_count == USB_RETRY_LIMIT) + return (rcode); + break; + default: + return (rcode); + }//switch( rcode + + }//while( timeout > millis() + return ( rcode); +} + +/* USB main task. Performs enumeration/cleanup */ +void USB::Task(void) //USB state machine +{ + uint8_t rcode; + uint8_t tmpdata; + static unsigned long delay = 0; + //USB_DEVICE_DESCRIPTOR buf; + bool lowspeed = false; + + MAX3421E::Task(); + + tmpdata = getVbusState(); + + /* modify USB task state if Vbus changed */ + switch(tmpdata) { + case SE1: //illegal state + usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; + lowspeed = false; + break; + case SE0: //disconnected + if((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED) + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; + lowspeed = false; + break; + case LSHOST: + + lowspeed = true; + //intentional fallthrough + case FSHOST: //attached + if((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) { + delay = millis() + USB_SETTLE_DELAY; + usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; + } + break; + }// switch( tmpdata + + for(uint8_t i = 0; i < USB_NUMDEVICES; i++) + if(devConfig[i]) + rcode = devConfig[i]->Poll(); + + switch(usb_task_state) { + case USB_DETACHED_SUBSTATE_INITIALIZE: + init(); + + for(uint8_t i = 0; i < USB_NUMDEVICES; i++) + if(devConfig[i]) + rcode = devConfig[i]->Release(); + + usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; + break; + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here + break; + case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here + break; + case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device + if((long)(millis() - delay) >= 0L) + usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; + else break; // don't fall through + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: + regWr(rHCTL, bmBUSRST); //issue bus reset + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; + break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: + if((regRd(rHCTL) & bmBUSRST) == 0) { + tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation + regWr(rMODE, tmpdata); + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF; + //delay = millis() + 20; //20ms wait after reset per USB spec + } + break; + case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order + if(regRd(rHIRQ) & bmFRAMEIRQ) { + //when first SOF received _and_ 20ms has passed we can continue + /* + if (delay < millis()) //20ms passed + usb_task_state = USB_STATE_CONFIGURING; + */ + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET; + delay = millis() + 20; + } + break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET: + if((long)(millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING; + else break; // don't fall through + case USB_STATE_CONFIGURING: + + //Serial.print("\r\nConf.LS: "); + //Serial.println(lowspeed, HEX); + + rcode = Configuring(0, 0, lowspeed); + + if(rcode) { + if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) { + usb_error = rcode; + usb_task_state = USB_STATE_ERROR; + } + } else + usb_task_state = USB_STATE_RUNNING; + break; + case USB_STATE_RUNNING: + break; + case USB_STATE_ERROR: + //MAX3421E::Init(); + break; + } // switch( usb_task_state ) +} + +uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) { + //uint8_t buf[12]; + uint8_t rcode; + UsbDevice *p0 = NULL, *p = NULL; + + // Get pointer to pseudo device with address 0 assigned + p0 = addrPool.GetUsbDevicePtr(0); + + if(!p0) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if(!p0->epinfo) + return USB_ERROR_EPINFO_IS_NULL; + + p0->lowspeed = (lowspeed) ? true : false; + + // Allocate new address according to device class + uint8_t bAddress = addrPool.AllocAddress(parent, false, port); + + if(!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + // Assign new address to the device + rcode = setAddr(0, 0, bAddress); + + if(rcode) { + addrPool.FreeAddress(bAddress); + bAddress = 0; + return rcode; + } + return 0; +}; + +uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) { + //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port); + uint8_t retries = 0; + +again: + uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed); + if(rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) { + if(parent == 0) { + // Send a bus reset on the root interface. + regWr(rHCTL, bmBUSRST); //issue bus reset + DELAY(102); // delay 102ms, compensate for clock inaccuracy. + } else { + // reset parent port + devConfig[parent]->ResetHubPort(port); + } + } else if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works + DELAY(100); + retries++; + goto again; + } else if(rcode) + return rcode; + + rcode = devConfig[driver]->Init(parent, port, lowspeed); + if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works + DELAY(100); + retries++; + goto again; + } + if(rcode) { + // Issue a bus reset, because the device may be in a limbo state + if(parent == 0) { + // Send a bus reset on the root interface. + regWr(rHCTL, bmBUSRST); //issue bus reset + DELAY(102); // delay 102ms, compensate for clock inaccuracy. + } else { + // reset parent port + devConfig[parent]->ResetHubPort(port); + } + } + return rcode; +} + +/* + * This is broken. We need to enumerate differently. + * It causes major problems with several devices if detected in an unexpected order. + * + * + * Oleg - I wouldn't do anything before the newly connected device is considered sane. + * i.e.(delays are not indicated for brevity): + * 1. reset + * 2. GetDevDescr(); + * 3a. If ACK, continue with allocating address, addressing, etc. + * 3b. Else reset again, count resets, stop at some number (5?). + * 4. When max.number of resets is reached, toggle power/fail + * If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD() + * it doesn't need to be reset again + * New steps proposal: + * 1: get address pool instance. exit on fail + * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail. + * 3: bus reset, 100ms delay + * 4: set address + * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail + * 6: while (configurations) { + * for(each configuration) { + * for (each driver) { + * 6a: Ask device if it likes configuration. Returns 0 on OK. + * If successful, the driver configured device. + * The driver now owns the endpoints, and takes over managing them. + * The following will need codes: + * Everything went well, instance consumed, exit with success. + * Instance already in use, ignore it, try next driver. + * Not a supported device, ignore it, try next driver. + * Not a supported configuration for this device, ignore it, try next driver. + * Could not configure device, fatal, exit with fail. + * } + * } + * } + * 7: for(each driver) { + * 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID + * 8: if we get here, no driver likes the device plugged in, so exit failure. + * + */ +uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { + //uint8_t bAddress = 0; + //printf("Configuring: parent = %i, port = %i\r\n", parent, port); + uint8_t devConfigIndex; + uint8_t rcode = 0; + uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; + USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast(buf); + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + EpInfo epInfo; + + epInfo.epAddr = 0; + epInfo.maxPktSize = 8; + epInfo.epAttribs = 0; + epInfo.bmNakPower = USB_NAK_MAX_POWER; + + //DELAY(2000); + AddressPool &addrPool = GetAddressPool(); + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + if(!p) { + //printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n"); + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to + // avoid toggle inconsistence + + p->epinfo = &epInfo; + + p->lowspeed = lowspeed; + // Get device descriptor + rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if(rcode) { + //printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n"); + return rcode; + } + + // to-do? + // Allocate new address according to device class + //bAddress = addrPool.AllocAddress(parent, false, port); + + uint16_t vid = udd->idVendor; + uint16_t pid = udd->idProduct; + uint8_t klass = udd->bDeviceClass; + uint8_t subklass = udd->bDeviceSubClass; + // Attempt to configure if VID/PID or device class matches with a driver + // Qualify with subclass too. + // + // VID/PID & class tests default to false for drivers not yet ported + // subclass defaults to true, so you don't have to define it if you don't have to. + // + for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { + if(!devConfig[devConfigIndex]) continue; // no driver + if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed + if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) { + rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); + if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED) + break; + } + } + + if(devConfigIndex < USB_NUMDEVICES) { + return rcode; + } + + + // blindly attempt to configure + for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { + if(!devConfig[devConfigIndex]) continue; + if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed + if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above + rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); + + //printf("ERROR ENUMERATING %2.2x\r\n", rcode); + if(!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) { + // in case of an error dev_index should be reset to 0 + // in order to start from the very beginning the + // next time the program gets here + //if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) + // devConfigIndex = 0; + return rcode; + } + } + // if we get here that means that the device class is not supported by any of registered classes + rcode = DefaultAddressing(parent, port, lowspeed); + + return rcode; +} + +uint8_t USB::ReleaseDevice(uint8_t addr) { + if(!addr) + return 0; + + for(uint8_t i = 0; i < USB_NUMDEVICES; i++) { + if(!devConfig[i]) continue; + if(devConfig[i]->GetAddress() == addr) + return devConfig[i]->Release(); + } + return 0; +} + +#if 1 //!defined(USB_METHODS_INLINE) +//get device descriptor + +uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL)); +} +//get configuration descriptor + +uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL)); +} + +/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this + total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */ +uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) { + const uint8_t bufSize = 64; + uint8_t buf[bufSize]; + USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast(buf); + + uint8_t ret = getConfDescr(addr, ep, 9, conf, buf); + + if(ret) + return ret; + + uint16_t total = ucd->wTotalLength; + + //USBTRACE2("\r\ntotal conf.size:", total); + + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p)); +} + +//get string descriptor + +uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL)); +} +//set address + +uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) { + uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL); + //DELAY(2); //per USB 2.0 sect.9.2.6.3 + DELAY(300); // Older spec says you should wait at least 200ms + return rcode; + //return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL)); +} +//set configuration + +uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) { + return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL)); +} + +#endif // defined(USB_METHODS_INLINE) diff --git a/Marlin/usb-flashdrive/lib/Usb.h b/Marlin/usb-flashdrive/lib/Usb.h new file mode 100644 index 000000000..946af7eb2 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/Usb.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +/* USB functions */ +#ifndef _usb_h_ +#define _usb_h_ + +// WARNING: Do not change the order of includes, or stuff will break! +#include +#include +#include + +// None of these should ever be included by a driver, or a user's sketch. +#include "settings.h" +#include "printhex.h" +#include "message.h" +#include "max3421e.h" +#include "address.h" +#include "avrpins.h" +#include "usb_ch9.h" +#include "usbhost.h" +#include "UsbCore.h" +#include "parsetools.h" +#include "confdescparser.h" + +#endif //_usb_h_ diff --git a/Marlin/usb-flashdrive/lib/UsbCore.h b/Marlin/usb-flashdrive/lib/UsbCore.h new file mode 100644 index 000000000..f514195cd --- /dev/null +++ b/Marlin/usb-flashdrive/lib/UsbCore.h @@ -0,0 +1,296 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(USBCORE_H) +#error "Never include UsbCore.h directly; include Usb.h instead" +#else +#define USBCORE_H + +// Not used anymore? If anyone uses this, please let us know so that this may be +// moved to the proper place, settings.h. +//#define USB_METHODS_INLINE + +/* shield pins. First parameter - SS pin, second parameter - INT pin */ +#ifdef BOARD_BLACK_WIDDOW +typedef MAX3421e MAX3421E; // Black Widow +#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) +#if EXT_RAM +typedef MAX3421e MAX3421E; // Teensy++ 2.0 with XMEM2 +#else +typedef MAX3421e MAX3421E; // Teensy++ 1.0 and 2.0 +#endif +#elif defined(BOARD_MEGA_ADK) +typedef MAX3421e MAX3421E; // Arduino Mega ADK +#elif defined(ARDUINO_AVR_BALANDUINO) +typedef MAX3421e MAX3421E; // Balanduino +#else +typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.) or Teensy 2.0 and 3.0 +#endif + +/* Common setup data constant combinations */ +#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type +#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface' +#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type + +// D7 data transfer direction (0 - host-to-device, 1 - device-to-host) +// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved) +// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved) + +// USB Device Classes +#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors +#define USB_CLASS_AUDIO 0x01 // Audio +#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control +#define USB_CLASS_HID 0x03 // HID +#define USB_CLASS_PHYSICAL 0x05 // Physical +#define USB_CLASS_IMAGE 0x06 // Image +#define USB_CLASS_PRINTER 0x07 // Printer +#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage +#define USB_CLASS_HUB 0x09 // Hub +#define USB_CLASS_CDC_DATA 0x0a // CDC-Data +#define USB_CLASS_SMART_CARD 0x0b // Smart-Card +#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security +#define USB_CLASS_VIDEO 0x0e // Video +#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare +#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device +#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller +#define USB_CLASS_MISC 0xef // Miscellaneous +#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific +#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific + +// Additional Error Codes +#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1 +#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2 +#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3 +#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4 +#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5 +#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6 +#define USB_ERROR_EPINFO_IS_NULL 0xD7 +#define USB_ERROR_INVALID_ARGUMENT 0xD8 +#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9 +#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA +#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB +#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0 +#define USB_ERROR_FailGetDevDescr 0xE1 +#define USB_ERROR_FailSetDevTblEntry 0xE2 +#define USB_ERROR_FailGetConfDescr 0xE3 +#define USB_ERROR_TRANSFER_TIMEOUT 0xFF + +#define USB_XFER_TIMEOUT 10000 //30000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec +//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted +#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer +#define USB_SETTLE_DELAY 200 //settle delay in milliseconds + +#define USB_NUMDEVICES 16 //number of USB devices +//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller +#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms + +/* USB state machine states */ +#define USB_STATE_MASK 0xf0 + +#define USB_STATE_DETACHED 0x10 +#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11 +#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12 +#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13 +#define USB_ATTACHED_SUBSTATE_SETTLE 0x20 +#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30 +#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40 +#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50 +#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51 +#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60 +#define USB_STATE_ADDRESSING 0x70 +#define USB_STATE_CONFIGURING 0x80 +#define USB_STATE_RUNNING 0x90 +#define USB_STATE_ERROR 0xa0 + +class USBDeviceConfig { +public: + + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) { + return 0; + } + + virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { + return 0; + } + + virtual uint8_t Release() { + return 0; + } + + virtual uint8_t Poll() { + return 0; + } + + virtual uint8_t GetAddress() { + return 0; + } + + virtual void ResetHubPort(uint8_t port) { + return; + } // Note used for hubs only! + + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return false; + } + + virtual boolean DEVCLASSOK(uint8_t klass) { + return false; + } + + virtual boolean DEVSUBCLASSOK(uint8_t subklass) { + return true; + } + +}; + +/* USB Setup Packet Structure */ +typedef struct { + + union { // offset description + uint8_t bmRequestType; // 0 Bit-map of request type + + struct { + uint8_t recipient : 5; // Recipient of the request + uint8_t type : 2; // Type of request + uint8_t direction : 1; // Direction of data X-fer + } __attribute__((packed)); + } ReqType_u; + uint8_t bRequest; // 1 Request + + union { + uint16_t wValue; // 2 Depends on bRequest + + struct { + uint8_t wValueLo; + uint8_t wValueHi; + } __attribute__((packed)); + } wVal_u; + uint16_t wIndex; // 4 Depends on bRequest + uint16_t wLength; // 6 Depends on bRequest +} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT; + + + +// Base class for incoming data parser + +class USBReadParser { +public: + virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; +}; + +class USB : public MAX3421E { + AddressPoolImpl addrPool; + USBDeviceConfig* devConfig[USB_NUMDEVICES]; + uint8_t bmHubPre; + +public: + USB(void); + + void SetHubPreMask() { + bmHubPre |= bmHUBPRE; + }; + + void ResetHubPreMask() { + bmHubPre &= (~bmHUBPRE); + }; + + AddressPool& GetAddressPool() { + return (AddressPool&)addrPool; + }; + + uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) { + for(uint8_t i = 0; i < USB_NUMDEVICES; i++) { + if(!devConfig[i]) { + devConfig[i] = pdev; + return 0; + } + } + return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS; + }; + + void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { + addrPool.ForEachUsbDevice(pfunc); + }; + uint8_t getUsbTaskState(void); + void setUsbTaskState(uint8_t state); + + EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep); + uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr); + + /* Control requests */ + uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr); + uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr); + + uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p); + + uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr); + uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr); + uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value); + /**/ + uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction); + uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit); + uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data); + uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data); + uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit); + + void Task(void); + + uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed); + uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed); + uint8_t ReleaseDevice(uint8_t addr); + + uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, + uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p); + +private: + void init(); + uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit); + uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data); + uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data); + uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed); +}; + +#if 0 //defined(USB_METHODS_INLINE) +//get device descriptor + +inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr)); +} +//get configuration descriptor + +inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr)); +} +//get string descriptor + +inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) { + return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr)); +} +//set address + +inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) { + return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL)); +} +//set configuration + +inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) { + return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL)); +} + +#endif // defined(USB_METHODS_INLINE) + +#endif /* USBCORE_H */ diff --git a/Marlin/usb-flashdrive/lib/UsbDriveBulkOnly.ino b/Marlin/usb-flashdrive/lib/UsbDriveBulkOnly.ino new file mode 100644 index 000000000..2ca923857 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/UsbDriveBulkOnly.ino @@ -0,0 +1,147 @@ +/******************************************************************************************** + * This program/sketch is used to run a USB Thumb Drive. * + * * + * NOTE - This Arduino Sketch has been modified to initialize a MAX3421E USB Host Interface * + * chip, write 3 test files, print out the directory of the thumb drive and print out the * + * contents of a short .txt file. * + * * + * The code is leveraged from the following: * + * * + * Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. * + * * + * This software may be distributed and modified under the terms of the GNU * + * General Public License version 2 (GPL2) as published by the Free Software * + * Foundation and appearing in the file GPL2.TXT included in the packaging of * + * this file. Please note that GPL2 Section 2[b] requires that all works based * + * on this software must also be made publicly available under the terms of * + * the GPL2 ("Copyleft"). * + * * + * Contact information * + * ------------------- * + * * + * Circuits At Home, LTD * + * Web : http://www.circuitsathome.com * + * e-mail : support@circuitsathome.com * + * * + * SPECIAL NOTE - In order to work with a modified Eisny or RAMBo, the SPI chip select pin * + * (CS) (D10) has been remapped from PORTB Pin-4 to PORTB Pin-0. This has been done in the * + * __AVR_ATmega2560__ section of the avrpins.h file. * + * * + ********************************************************************************************/ + +#include +#include "masstorage.h" + +#define MAX_USB_RST 7 + +// USB host objects.v +USB usb; +BulkOnly bulk(&usb); + +#define error(msg) {Serial.print("Error: "); Serial.println(msg);} + +#define TIMEOUT_MILLIS 4000 + +//------------------------------------------------------------------------------ +bool initUSB(USB* usb) { + uint8_t last_state = 0; + uint8_t current_state = 0; + uint32_t m = millis(); + + for (uint8_t i = 0; usb->Init(1000) == -1; i++) + { + //if (USB_FAT_DBG_MODE) { + Serial.println(F("No USB HOST Shield?")); + //} + if (i > 10) { + return false; + } + } +#if USB_FAT_DBG_MODE + Serial.print(F("Host initialized, ms: ")); + Serial.println(millis() - m); +#endif // USB_FAT_DBG_MODE + + usb->vbusPower(vbus_on); +#if USB_FAT_DBG_MODE + Serial.print(F("USB powered, ms: ")); + Serial.println(millis() - m); +#endif // USB_FAT_DBG_MODE + + while ((millis() - m) < TIMEOUT_MILLIS) { + usb->Task(); + current_state = usb->getUsbTaskState(); +#if USB_FAT_DBG_MODE + if (last_state != current_state) { + Serial.print(F("USB state: ")); + Serial.print(current_state, HEX); + Serial.print(F(", ms: ")); + Serial.println(millis() - m); + } + last_state = current_state; +#endif // USB_FAT_DBG_MODE + if(current_state == USB_STATE_RUNNING) { + return true; + } + } + return false; +} + +//------------------------------------------------------------------------------ +void setup() +{ + pinMode(MAX_USB_RST, OUTPUT); + digitalWrite(MAX_USB_RST, HIGH); + + Serial.begin(9600); + + Serial.print("USB THUMB DRIVE FILE TEST\n\n"); + + Serial.print("Initializing The USB Bus\n"); + + // Initialize the USB bus. + + if (!initUSB(&usb)) + { + error("initUSB failed"); + } + else + { + Serial.print("USB Initialized\n"); + } + + if(bulk.LUNIsGood(0)) { + Serial.print("LUN Capacity: "); + Serial.println(bulk.GetCapacity(0)); + + const uint32_t sectorSize = bulk.GetSectorSize(0); + + Serial.print("Sector Size: "); + Serial.println(sectorSize); + + uint8_t buf[512]; + + + const uint8_t lun = 0; + const uint32_t addr = 0; + if(bulk.Read(lun, addr, sectorSize, 1, buf) == 0) { + Serial.print("Read a block: \n"); + Serial.println((char*)buf); + } else { + Serial.print("Failed to a read block\n"); + } + + const char *message = PSTR("This is a test of writing raw data!"); + strcpy_P(buf, message); + + if(bulk.Write(lun, addr, sectorSize, 1, buf) == 0) { + Serial.print("Wrote a block\n"); + } else { + Serial.print("Failed to write a block\n"); + } + } else { + Serial.print("LUN zero is not good\n"); + } +} +//------------------------------------------------------------------------------ +void loop () {} diff --git a/Marlin/usb-flashdrive/lib/address.h b/Marlin/usb-flashdrive/lib/address.h new file mode 100644 index 000000000..74473dc93 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/address.h @@ -0,0 +1,282 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(__ADDRESS_H__) +#error "Never include address.h directly; include Usb.h instead" +#else +#define __ADDRESS_H__ + + + +/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */ +/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */ +#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value +#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up +#define USB_NAK_NOWAIT 1 //Single NAK stops transfer +#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout + +struct EpInfo { + uint8_t epAddr; // Endpoint address + uint8_t maxPktSize; // Maximum packet size + + union { + uint8_t epAttribs; + + struct { + uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise + uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise + uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value + } __attribute__((packed)); + }; +} __attribute__((packed)); + +// 7 6 5 4 3 2 1 0 +// --------------------------------- +// | | H | P | P | P | A | A | A | +// --------------------------------- +// +// H - if 1 the address is a hub address +// P - parent hub address +// A - device address / port number in case of hub +// + +struct UsbDeviceAddress { + + union { + + struct { + uint8_t bmAddress : 3; // device address/port number + uint8_t bmParent : 3; // parent hub address + uint8_t bmHub : 1; // hub flag + uint8_t bmReserved : 1; // reserved, must be zero + } __attribute__((packed)); + uint8_t devAddress; + }; +} __attribute__((packed)); + +#define bmUSB_DEV_ADDR_ADDRESS 0x07 +#define bmUSB_DEV_ADDR_PARENT 0x38 +#define bmUSB_DEV_ADDR_HUB 0x40 + +struct UsbDevice { + EpInfo *epinfo; // endpoint info pointer + UsbDeviceAddress address; + uint8_t epcount; // number of endpoints + bool lowspeed; // indicates if a device is the low speed one + // uint8_t devclass; // device class +} __attribute__((packed)); + +class AddressPool { +public: + virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0; + virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0; + virtual void FreeAddress(uint8_t addr) = 0; +}; + +typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); + +#define ADDR_ERROR_INVALID_INDEX 0xFF +#define ADDR_ERROR_INVALID_ADDRESS 0xFF + +template +class AddressPoolImpl : public AddressPool { + EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device + + uint8_t hubCounter; // hub counter is kept + // in order to avoid hub address duplication + + UsbDevice thePool[MAX_DEVICES_ALLOWED]; + + // Initializes address pool entry + + void InitEntry(uint8_t index) { + thePool[index].address.devAddress = 0; + thePool[index].epcount = 1; + thePool[index].lowspeed = 0; + thePool[index].epinfo = &dev0ep; + }; + + // Returns thePool index for a given address + + uint8_t FindAddressIndex(uint8_t address = 0) { + for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) { + if(thePool[i].address.devAddress == address) + return i; + } + return 0; + }; + + // Returns thePool child index for a given parent + + uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) { + for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) { + if(thePool[i].address.bmParent == addr.bmAddress) + return i; + } + return 0; + }; + + // Frees address entry specified by index parameter + + void FreeAddressByIndex(uint8_t index) { + // Zero field is reserved and should not be affected + if(index == 0) + return; + + UsbDeviceAddress uda = thePool[index].address; + // If a hub was switched off all port addresses should be freed + if(uda.bmHub == 1) { + for(uint8_t i = 1; (i = FindChildIndex(uda, i));) + FreeAddressByIndex(i); + + // If the hub had the last allocated address, hubCounter should be decremented + if(hubCounter == uda.bmAddress) + hubCounter--; + } + InitEntry(index); + } + + // Initializes the whole address pool at once + + void InitAllAddresses() { + for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) + InitEntry(i); + + hubCounter = 0; + }; + +public: + + AddressPoolImpl() : hubCounter(0) { + // Zero address is reserved + InitEntry(0); + + thePool[0].address.devAddress = 0; + thePool[0].epinfo = &dev0ep; + dev0ep.epAddr = 0; + dev0ep.maxPktSize = 8; + dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0 + dev0ep.bmNakPower = USB_NAK_MAX_POWER; + + InitAllAddresses(); + }; + + // Returns a pointer to a specified address entry + + virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) { + if(!addr) + return thePool; + + uint8_t index = FindAddressIndex(addr); + + return (!index) ? NULL : thePool + index; + }; + + // Performs an operation specified by pfunc for each addressed device + + void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { + if(!pfunc) + return; + + for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) + if(thePool[i].address.devAddress) + pfunc(thePool + i); + }; + + // Allocates new address + + virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) { + /* if (parent != 0 && port == 0) + USB_HOST_SERIAL.println("PRT:0"); */ + UsbDeviceAddress _parent; + _parent.devAddress = parent; + if(_parent.bmReserved || port > 7) + //if(parent > 127 || port > 7) + return 0; + + if(is_hub && hubCounter == 7) + return 0; + + // finds first empty address entry starting from one + uint8_t index = FindAddressIndex(0); + + if(!index) // if empty entry is not found + return 0; + + if(_parent.devAddress == 0) { + if(is_hub) { + thePool[index].address.devAddress = 0x41; + hubCounter++; + } else + thePool[index].address.devAddress = 1; + + return thePool[index].address.devAddress; + } + + UsbDeviceAddress addr; + addr.devAddress = 0; // Ensure all bits are zero + addr.bmParent = _parent.bmAddress; + if(is_hub) { + addr.bmHub = 1; + addr.bmAddress = ++hubCounter; + } else { + addr.bmHub = 0; + addr.bmAddress = port; + } + thePool[index].address = addr; + /* + USB_HOST_SERIAL.print("Addr:"); + USB_HOST_SERIAL.print(addr.bmHub, HEX); + USB_HOST_SERIAL.print("."); + USB_HOST_SERIAL.print(addr.bmParent, HEX); + USB_HOST_SERIAL.print("."); + USB_HOST_SERIAL.println(addr.bmAddress, HEX); + */ + return thePool[index].address.devAddress; + }; + + // Empties pool entry + + virtual void FreeAddress(uint8_t addr) { + // if the root hub is disconnected all the addresses should be initialized + if(addr == 0x41) { + InitAllAddresses(); + return; + } + uint8_t index = FindAddressIndex(addr); + FreeAddressByIndex(index); + }; + + // Returns number of hubs attached + // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs. + //uint8_t GetNumHubs() + //{ + // return hubCounter; + //}; + //uint8_t GetNumDevices() + //{ + // uint8_t counter = 0; + + // for (uint8_t i=1; i +class TPin { + // BOOST_STATIC_ASSERT(PIN < PORT::Width); +public: + typedef PORT Port; + + enum { + Number = PIN + }; + + static void Set() { + PORT::Set(1 << PIN); + } + + static void Set(uint8_t val) { + if(val) + Set(); + else Clear(); + } + + static void SetDir(uint8_t val) { + if(val) + SetDirWrite(); + else SetDirRead(); + } + + static void Clear() { + PORT::Clear(1 << PIN); + } + + static void Toggle() { + PORT::Toggle(1 << PIN); + } + + static void SetDirRead() { + PORT::DirClear(1 << PIN); + } + + static void SetDirWrite() { + PORT::DirSet(1 << PIN); + } + + static uint8_t IsSet() { + return PORT::PinRead() & (uint8_t)(1 << PIN); + } + + static void WaiteForSet() { + while(IsSet() == 0) { + } + } + + static void WaiteForClear() { + while(IsSet()) { + } + } +}; //class TPin... + +// this class represents one bit in TCCR port. +// used to set/clear TCCRx bits +// It is fully static. + +template +class TCom { + // BOOST_STATIC_ASSERT(PIN < PORT::Width); +public: + typedef TCCR Tccr; + + enum { + Com = COM + }; + + static void Set() { + TCCR::Set(1 << COM); + } + + static void Clear() { + TCCR::Clear(1 << COM); + } + + static void Toggle() { + TCCR::Toggle(1 << COM); + } +}; //class TCom... + +//Short pin definitions +#ifdef USE_PORTA +typedef TPin Pa0; +typedef TPin Pa1; +typedef TPin Pa2; +typedef TPin Pa3; +typedef TPin Pa4; +typedef TPin Pa5; +typedef TPin Pa6; +typedef TPin Pa7; +#endif + +#ifdef USE_PORTB +typedef TPin Pb0; +typedef TPin Pb1; +typedef TPin Pb2; +typedef TPin Pb3; +typedef TPin Pb4; +typedef TPin Pb5; +typedef TPin Pb6; +typedef TPin Pb7; +#endif + +#ifdef USE_PORTC +typedef TPin Pc0; +typedef TPin Pc1; +typedef TPin Pc2; +typedef TPin Pc3; +typedef TPin Pc4; +typedef TPin Pc5; +typedef TPin Pc6; +typedef TPin Pc7; +#endif + +#ifdef USE_PORTD +typedef TPin Pd0; +typedef TPin Pd1; +typedef TPin Pd2; +typedef TPin Pd3; +typedef TPin Pd4; +typedef TPin Pd5; +typedef TPin Pd6; +typedef TPin Pd7; +#endif + +#ifdef USE_PORTE +typedef TPin Pe0; +typedef TPin Pe1; +typedef TPin Pe2; +typedef TPin Pe3; +typedef TPin Pe4; +typedef TPin Pe5; +typedef TPin Pe6; +typedef TPin Pe7; +#endif + +#ifdef USE_PORTF +typedef TPin Pf0; +typedef TPin Pf1; +typedef TPin Pf2; +typedef TPin Pf3; +typedef TPin Pf4; +typedef TPin Pf5; +typedef TPin Pf6; +typedef TPin Pf7; +#endif + +#ifdef USE_PORTG +typedef TPin Pg0; +typedef TPin Pg1; +typedef TPin Pg2; +typedef TPin Pg3; +typedef TPin Pg4; +typedef TPin Pg5; +typedef TPin Pg6; +typedef TPin Pg7; +#endif + +#ifdef USE_PORTH +typedef TPin Ph0; +typedef TPin Ph1; +typedef TPin Ph2; +typedef TPin Ph3; +typedef TPin Ph4; +typedef TPin Ph5; +typedef TPin Ph6; +typedef TPin Ph7; +#endif + +#ifdef USE_PORTJ +typedef TPin Pj0; +typedef TPin Pj1; +typedef TPin Pj2; +typedef TPin Pj3; +typedef TPin Pj4; +typedef TPin Pj5; +typedef TPin Pj6; +typedef TPin Pj7; +#endif + +#ifdef USE_PORTK +typedef TPin Pk0; +typedef TPin Pk1; +typedef TPin Pk2; +typedef TPin Pk3; +typedef TPin Pk4; +typedef TPin Pk5; +typedef TPin Pk6; +typedef TPin Pk7; +#endif + +#ifdef USE_PORTL +typedef TPin Pl0; +typedef TPin Pl1; +typedef TPin Pl2; +typedef TPin Pl3; +typedef TPin Pl4; +typedef TPin Pl5; +typedef TPin Pl6; +typedef TPin Pl7; +#endif + +#ifdef USE_PORTQ +typedef TPin Pq0; +typedef TPin Pq1; +typedef TPin Pq2; +typedef TPin Pq3; +typedef TPin Pq4; +typedef TPin Pq5; +typedef TPin Pq6; +typedef TPin Pq7; +#endif + +#ifdef USE_PORTR +typedef TPin Pr0; +typedef TPin Pr1; +typedef TPin Pr2; +typedef TPin Pr3; +typedef TPin Pr4; +typedef TPin Pr5; +typedef TPin Pr6; +typedef TPin Pr7; +#endif + +#ifdef USE_TCCR0A +typedef TCom Tc0a; //P6 +typedef TCom Tc0b; //P5 +#endif + +#ifdef USE_TCCR1A +typedef TCom Tc1a; //P9 +typedef TCom Tc1b; //P10 +#endif + +#ifdef USE_TCCR2A +typedef TCom Tc2a; //P11 +typedef TCom Tc2b; //P3 +#endif + +template +class Tp_Tc { +public: + + static void SetDir(uint8_t val) { + if(val) + SetDirWrite(); + else SetDirRead(); + } + + static void SetDirRead() { + Tp_pin::SetDirRead(); //set pin direction + Tc_bit::Clear(); //disconnect pin from PWM + } + + static void SetDirWrite() { + Tp_pin::SetDirWrite(); + Tc_bit::Clear(); + } +}; + +/* pin definitions for cases where it's necessary to clear compare output mode bits */ + +//typedef Tp_Tc P3; //Arduino pin 3 +//typedef Tp_Tc P5; //Arduino pin 5 +//typedef Tp_Tc P6; //Arduino pin 6 +//typedef Tp_Tc P9; //Arduino pin 9 +//typedef Tp_Tc P10; //Arduino pin 10 +//typedef Tp_Tc P11; //Arduino pin 11 + +/* Arduino pin definitions */ +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +// "Mega" Arduino pin numbers + +#define P0 Pe0 +#define P1 Pe1 +#define P2 Pe4 +#define P3 Pe5 +#define P4 Pg5 +#define P5 Pe3 +#define P6 Ph3 +#define P7 Ph4 + +#define P8 Ph5 +#define P9 Ph6 +//#define P10 Pb4 //Pb4 - Regular Arduino +#define P10 Pb0 //Pb0 - Einsy Board +#define P11 Pb5 +#define P12 Pb6 +#define P13 Pb7 + +#define P14 Pj1 +#define P15 Pj0 +#define P16 Ph1 +#define P17 Ph0 +#define P18 Pd3 +#define P19 Pd2 +#define P20 Pd1 +#define P21 Pd0 + +#define P22 Pa0 +#define P23 Pa1 +#define P24 Pa2 +#define P25 Pa3 +#define P26 Pa4 +#define P27 Pa5 +#define P28 Pa6 +#define P29 Pa7 +#define P30 Pc7 +#define P31 Pc6 +#define P32 Pc5 +#define P33 Pc4 +#define P34 Pc3 +#define P35 Pc2 +#define P36 Pc1 +#define P37 Pc0 + +#define P38 Pd7 +#define P39 Pg2 +#define P40 Pg1 +#define P41 Pg0 +#define P42 Pl7 +#define P43 Pl6 +#define P44 Pl5 +#define P45 Pl4 +#define P46 Pl3 +#define P47 Pl2 +#define P48 Pl1 +#define P49 Pl0 +#define P50 Pb3 +#define P51 Pb2 +#define P52 Pb1 +// #define P53 Pb0 + +#ifdef BOARD_MEGA_ADK // These pins are not broken out on the Arduino ADK +#define P54 Pe6 // INT on Arduino ADK +#define P55 Pj2 // MAX_RESET on Arduino ADK +#endif + +// "Mega" pin numbers + +#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +// "Classic" Arduino pin numbers + +#define P0 Pd0 +#define P1 Pd1 +#define P2 Pd2 +#define P3 Pd3 +#define P4 Pd4 +#define P5 Pd5 +#define P6 Pd6 +#define P7 Pd7 + +#define P8 Pb0 +#define P9 Pb1 +#define P10 Pb2 +#define P11 Pb3 +#define P12 Pb4 +#define P13 Pb5 + +#define P14 Pc0 +#define P15 Pc1 +#define P16 Pc2 +#define P17 Pc3 +#define P18 Pc4 +#define P19 Pc5 + +// "Classic" Arduino pin numbers + +#elif defined(CORE_TEENSY) && defined(__AVR_ATmega32U4__) +// Teensy 2.0 pin numbers +// http://www.pjrc.com/teensy/pinout.html +#define P0 Pb0 +#define P1 Pb1 +#define P2 Pb2 +#define P3 Pb3 +#define P4 Pb7 +#define P5 Pd0 +#define P6 Pd1 +#define P7 Pd2 +#define P8 Pd3 +#define P9 Pc6 +#define P10 Pc7 +#define P11 Pd6 +#define P12 Pd7 +#define P13 Pb4 +#define P14 Pb5 +#define P15 Pb6 +#define P16 Pf7 +#define P17 Pf6 +#define P18 Pf5 +#define P19 Pf4 +#define P20 Pf1 +#define P21 Pf0 +#define P22 Pd4 +#define P23 Pd5 +#define P24 Pe6 +// Teensy 2.0 + +#elif defined(__AVR_ATmega32U4__) +// Arduino Leonardo pin numbers + +#define P0 Pd2 // D0 - PD2 +#define P1 Pd3 // D1 - PD3 +#define P2 Pd1 // D2 - PD1 +#define P3 Pd0 // D3 - PD0 +#define P4 Pd4 // D4 - PD4 +#define P5 Pc6 // D5 - PC6 +#define P6 Pd7 // D6 - PD7 +#define P7 Pe6 // D7 - PE6 + +#define P8 Pb4 // D8 - PB4 +#define P9 Pb5 // D9 - PB5 +#define P10 Pb6 // D10 - PB6 +#define P11 Pb7 // D11 - PB7 +#define P12 Pd6 // D12 - PD6 +#define P13 Pc7 // D13 - PC7 + +#define P14 Pb3 // D14 - MISO - PB3 +#define P15 Pb1 // D15 - SCK - PB1 +#define P16 Pb2 // D16 - MOSI - PB2 +#define P17 Pb0 // D17 - SS - PB0 + +#define P18 Pf7 // D18 - A0 - PF7 +#define P19 Pf6 // D19 - A1 - PF6 +#define P20 Pf5 // D20 - A2 - PF5 +#define P21 Pf4 // D21 - A3 - PF4 +#define P22 Pf1 // D22 - A4 - PF1 +#define P23 Pf0 // D23 - A5 - PF0 + +#define P24 Pd4 // D24 / D4 - A6 - PD4 +#define P25 Pd7 // D25 / D6 - A7 - PD7 +#define P26 Pb4 // D26 / D8 - A8 - PB4 +#define P27 Pb5 // D27 / D9 - A9 - PB5 +#define P28 Pb6 // D28 / D10 - A10 - PB6 +#define P29 Pd6 // D29 / D12 - A11 - PD6 + +// Arduino Leonardo pin numbers + +#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) +// Teensy++ 1.0 and 2.0 pin numbers +// http://www.pjrc.com/teensy/pinout.html +#define P0 Pd0 +#define P1 Pd1 +#define P2 Pd2 +#define P3 Pd3 +#define P4 Pd4 +#define P5 Pd5 +#define P6 Pd6 +#define P7 Pd7 +#define P8 Pe0 +#define P9 Pe1 +#define P10 Pc0 +#define P11 Pc1 +#define P12 Pc2 +#define P13 Pc3 +#define P14 Pc4 +#define P15 Pc5 +#define P16 Pc6 +#define P17 Pc7 +#define P18 Pe6 +#define P19 Pe7 +#define P20 Pb0 +#define P21 Pb1 +#define P22 Pb2 +#define P23 Pb3 +#define P24 Pb4 +#define P25 Pb5 +#define P26 Pb6 +#define P27 Pb7 +#define P28 Pa0 +#define P29 Pa1 +#define P30 Pa2 +#define P31 Pa3 +#define P32 Pa4 +#define P33 Pa5 +#define P34 Pa6 +#define P35 Pa7 +#define P36 Pe4 +#define P37 Pe5 +#define P38 Pf0 +#define P39 Pf1 +#define P40 Pf2 +#define P41 Pf3 +#define P42 Pf4 +#define P43 Pf5 +#define P44 Pf6 +#define P45 Pf7 +// Teensy++ 1.0 and 2.0 + +#elif defined(ARDUINO_AVR_BALANDUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__)) +// Balanduino pin numbers +// http://balanduino.net/ +#define P0 Pd0 /* 0 - PD0 */ +#define P1 Pd1 /* 1 - PD1 */ + +#if BALANDUINO_REVISION < 13 + #define P2 Pb2 /* 2 - PB2 */ + #define P3 Pd6 /* 3 - PD6 */ + #define P4 Pd7 /* 4 - PD7 */ + #define P5 Pb3 /* 5 - PB3 */ +#else + #define P2 Pd2 /* 2 - PD2 */ + #define P3 Pd3 /* 3 - PD3 */ + #define P4 Pd6 /* 4 - PD6 */ + #define P5 Pd7 /* 5 - PD7 */ +#endif + +#define P6 Pb4 /* 6 - PB4 */ +#define P7 Pa0 /* 7 - PA0 */ +#define P8 Pa1 /* 8 - PA1 */ +#define P9 Pa2 /* 9 - PA2 */ +#define P10 Pa3 /* 10 - PA3 */ +#define P11 Pa4 /* 11 - PA4 */ +#define P12 Pa5 /* 12 - PA5 */ +#define P13 Pc1 /* 13 - PC1 */ +#define P14 Pc0 /* 14 - PC0 */ + +#if BALANDUINO_REVISION < 13 + #define P15 Pd2 /* 15 - PD2 */ + #define P16 Pd3 /* 16 - PD3 */ +#else + #define P15 Pb2 /* 15 - PB2 */ + #define P16 Pb3 /* 16 - PB2 */ +#endif + +#define P17 Pd4 /* 17 - PD4 */ +#define P18 Pd5 /* 18 - PD5 */ +#define P19 Pc2 /* 19 - PC2 */ +#define P20 Pc3 /* 20 - PC3 */ +#define P21 Pc4 /* 21 - PC4 */ +#define P22 Pc5 /* 22 - PC5 */ +#define P23 Pc6 /* 23 - PC6 */ +#define P24 Pc7 /* 24 - PC7 */ +#define P25 Pb0 /* 25 - PB0 */ +#define P26 Pb1 /* 26 - PB1 */ +#define P27 Pb5 /* 27 - PB5 */ +#define P28 Pb6 /* 28 - PB6 */ +#define P29 Pb7 /* 29 - PB7 */ +#define P30 Pa6 /* 30 - PA6 */ +#define P31 Pa7 /* 31 - PA7 */ +// Balanduino + +#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) +// Sanguino pin numbers +// Homepage: http://sanguino.cc/hardware +// Hardware add-on: https://github.com/Lauszus/Sanguino +#define P0 Pb0 +#define P1 Pb1 +#define P2 Pb2 +#define P3 Pb3 +#define P4 Pb4 +#define P5 Pb5 +#define P6 Pb6 +#define P7 Pb7 +#define P8 Pd0 +#define P9 Pd1 +#define P10 Pd2 +#define P11 Pd3 +#define P12 Pd4 +#define P13 Pd5 +#define P14 Pd6 +#define P15 Pd7 +#define P16 Pc0 +#define P17 Pc1 +#define P18 Pc2 +#define P19 Pc3 +#define P20 Pc4 +#define P21 Pc5 +#define P22 Pc6 +#define P23 Pc7 +#define P24 Pa0 +#define P25 Pa1 +#define P26 Pa2 +#define P27 Pa3 +#define P28 Pa4 +#define P29 Pa5 +#define P30 Pa6 +#define P31 Pa7 +// Sanguino + +#else +#error "Please define board in avrpins.h" + +#endif // Arduino pin definitions + +#endif // __AVR__ + +#if defined(__arm__) + +// pointers are 32 bits on ARM +#define pgm_read_pointer(p) pgm_read_dword(p) + +#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) + +#include "core_pins.h" +#include "avr_emulation.h" + +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint8_t *)GPIO_BITBAND_ADDR((reg), (bit))) + +#define MAKE_PIN(className, baseReg, pinNum, configReg) \ +class className { \ +public: \ + static void Set() { \ + *GPIO_BITBAND_PTR(baseReg, pinNum) = 1; \ + } \ + static void Clear() { \ + *GPIO_BITBAND_PTR(baseReg, pinNum) = 0; \ + } \ + static void SetDirRead() { \ + configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ + *(GPIO_BITBAND_PTR(baseReg, pinNum) + 640) = 0; \ + } \ + static void SetDirWrite() { \ + configReg = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); \ + *(GPIO_BITBAND_PTR(baseReg, pinNum) + 640) = 1; \ + } \ + static uint8_t IsSet() { \ + return *(GPIO_BITBAND_PTR(baseReg, pinNum) + 512); \ + } \ +}; + +MAKE_PIN(P0, CORE_PIN0_PORTREG, CORE_PIN0_BIT, CORE_PIN0_CONFIG); +MAKE_PIN(P1, CORE_PIN1_PORTREG, CORE_PIN1_BIT, CORE_PIN1_CONFIG); +MAKE_PIN(P2, CORE_PIN2_PORTREG, CORE_PIN2_BIT, CORE_PIN2_CONFIG); +MAKE_PIN(P3, CORE_PIN3_PORTREG, CORE_PIN3_BIT, CORE_PIN3_CONFIG); +MAKE_PIN(P4, CORE_PIN4_PORTREG, CORE_PIN4_BIT, CORE_PIN4_CONFIG); +MAKE_PIN(P5, CORE_PIN5_PORTREG, CORE_PIN5_BIT, CORE_PIN5_CONFIG); +MAKE_PIN(P6, CORE_PIN6_PORTREG, CORE_PIN6_BIT, CORE_PIN6_CONFIG); +MAKE_PIN(P7, CORE_PIN7_PORTREG, CORE_PIN7_BIT, CORE_PIN7_CONFIG); +MAKE_PIN(P8, CORE_PIN8_PORTREG, CORE_PIN8_BIT, CORE_PIN8_CONFIG); +MAKE_PIN(P9, CORE_PIN9_PORTREG, CORE_PIN9_BIT, CORE_PIN9_CONFIG); +MAKE_PIN(P10, CORE_PIN10_PORTREG, CORE_PIN10_BIT, CORE_PIN10_CONFIG); +MAKE_PIN(P11, CORE_PIN11_PORTREG, CORE_PIN11_BIT, CORE_PIN11_CONFIG); +MAKE_PIN(P12, CORE_PIN12_PORTREG, CORE_PIN12_BIT, CORE_PIN12_CONFIG); +MAKE_PIN(P13, CORE_PIN13_PORTREG, CORE_PIN13_BIT, CORE_PIN13_CONFIG); +MAKE_PIN(P14, CORE_PIN14_PORTREG, CORE_PIN14_BIT, CORE_PIN14_CONFIG); +MAKE_PIN(P15, CORE_PIN15_PORTREG, CORE_PIN15_BIT, CORE_PIN15_CONFIG); +MAKE_PIN(P16, CORE_PIN16_PORTREG, CORE_PIN16_BIT, CORE_PIN16_CONFIG); +MAKE_PIN(P17, CORE_PIN17_PORTREG, CORE_PIN17_BIT, CORE_PIN17_CONFIG); +MAKE_PIN(P18, CORE_PIN18_PORTREG, CORE_PIN18_BIT, CORE_PIN18_CONFIG); +MAKE_PIN(P19, CORE_PIN19_PORTREG, CORE_PIN19_BIT, CORE_PIN19_CONFIG); +MAKE_PIN(P20, CORE_PIN20_PORTREG, CORE_PIN20_BIT, CORE_PIN20_CONFIG); +MAKE_PIN(P21, CORE_PIN21_PORTREG, CORE_PIN21_BIT, CORE_PIN21_CONFIG); +MAKE_PIN(P22, CORE_PIN22_PORTREG, CORE_PIN22_BIT, CORE_PIN22_CONFIG); +MAKE_PIN(P23, CORE_PIN23_PORTREG, CORE_PIN23_BIT, CORE_PIN23_CONFIG); +MAKE_PIN(P24, CORE_PIN24_PORTREG, CORE_PIN24_BIT, CORE_PIN24_CONFIG); +MAKE_PIN(P25, CORE_PIN25_PORTREG, CORE_PIN25_BIT, CORE_PIN25_CONFIG); +MAKE_PIN(P26, CORE_PIN26_PORTREG, CORE_PIN26_BIT, CORE_PIN26_CONFIG); +MAKE_PIN(P27, CORE_PIN27_PORTREG, CORE_PIN27_BIT, CORE_PIN27_CONFIG); +MAKE_PIN(P28, CORE_PIN28_PORTREG, CORE_PIN28_BIT, CORE_PIN28_CONFIG); +MAKE_PIN(P29, CORE_PIN29_PORTREG, CORE_PIN29_BIT, CORE_PIN29_CONFIG); +MAKE_PIN(P30, CORE_PIN30_PORTREG, CORE_PIN30_BIT, CORE_PIN30_CONFIG); +MAKE_PIN(P31, CORE_PIN31_PORTREG, CORE_PIN31_BIT, CORE_PIN31_CONFIG); +MAKE_PIN(P32, CORE_PIN32_PORTREG, CORE_PIN32_BIT, CORE_PIN32_CONFIG); +MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); + +#undef MAKE_PIN + +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + +// SetDirRead: +// Disable interrupts +// Disable the pull up resistor +// Set to INPUT +// Enable PIO + +// SetDirWrite: +// Disable interrupts +// Disable the pull up resistor +// Set to OUTPUT +// Enable PIO + +#define MAKE_PIN(className, pio, pinMask) \ +class className { \ +public: \ + static void Set() { \ + pio->PIO_SODR = pinMask; \ + } \ + static void Clear() { \ + pio->PIO_CODR = pinMask; \ + } \ + static void SetDirRead() { \ + pio->PIO_IDR = pinMask ; \ + pio->PIO_PUDR = pinMask; \ + pio->PIO_ODR = pinMask; \ + pio->PIO_PER = pinMask; \ + } \ + static void SetDirWrite() { \ + pio->PIO_IDR = pinMask ; \ + pio->PIO_PUDR = pinMask; \ + pio->PIO_OER = pinMask; \ + pio->PIO_PER = pinMask; \ + } \ + static uint8_t IsSet() { \ + return pio->PIO_PDSR & pinMask; \ + } \ +}; + +// See: http://arduino.cc/en/Hacking/PinMappingSAM3X and variant.cpp + +MAKE_PIN(P0, PIOA, PIO_PA8); +MAKE_PIN(P1, PIOA, PIO_PA9); +MAKE_PIN(P2, PIOB, PIO_PB25); +MAKE_PIN(P3, PIOC, PIO_PC28); +MAKE_PIN(P4, PIOC, PIO_PC26); +MAKE_PIN(P5, PIOC, PIO_PC25); +MAKE_PIN(P6, PIOC, PIO_PC24); +MAKE_PIN(P7, PIOC, PIO_PC23); +MAKE_PIN(P8, PIOC, PIO_PC22); +MAKE_PIN(P9, PIOC, PIO_PC21); +MAKE_PIN(P10, PIOC, PIO_PC29); +MAKE_PIN(P11, PIOD, PIO_PD7); +MAKE_PIN(P12, PIOD, PIO_PD8); +MAKE_PIN(P13, PIOB, PIO_PB27); +MAKE_PIN(P14, PIOD, PIO_PD4); +MAKE_PIN(P15, PIOD, PIO_PD5); +MAKE_PIN(P16, PIOA, PIO_PA13); +MAKE_PIN(P17, PIOA, PIO_PA12); +MAKE_PIN(P18, PIOA, PIO_PA11); +MAKE_PIN(P19, PIOA, PIO_PA10); +MAKE_PIN(P20, PIOB, PIO_PB12); +MAKE_PIN(P21, PIOB, PIO_PB13); +MAKE_PIN(P22, PIOB, PIO_PB26); +MAKE_PIN(P23, PIOA, PIO_PA14); +MAKE_PIN(P24, PIOA, PIO_PA15); +MAKE_PIN(P25, PIOD, PIO_PD0); +MAKE_PIN(P26, PIOD, PIO_PD1); +MAKE_PIN(P27, PIOD, PIO_PD2); +MAKE_PIN(P28, PIOD, PIO_PD3); +MAKE_PIN(P29, PIOD, PIO_PD6); +MAKE_PIN(P30, PIOD, PIO_PD9); +MAKE_PIN(P31, PIOA, PIO_PA7); +MAKE_PIN(P32, PIOD, PIO_PD10); +MAKE_PIN(P33, PIOC, PIO_PC1); +MAKE_PIN(P34, PIOC, PIO_PC2); +MAKE_PIN(P35, PIOC, PIO_PC3); +MAKE_PIN(P36, PIOC, PIO_PC4); +MAKE_PIN(P37, PIOC, PIO_PC5); +MAKE_PIN(P38, PIOC, PIO_PC6); +MAKE_PIN(P39, PIOC, PIO_PC7); +MAKE_PIN(P40, PIOC, PIO_PC8); +MAKE_PIN(P41, PIOC, PIO_PC9); +MAKE_PIN(P42, PIOA, PIO_PA19); +MAKE_PIN(P43, PIOA, PIO_PA20); +MAKE_PIN(P44, PIOC, PIO_PC19); +MAKE_PIN(P45, PIOC, PIO_PC18); +MAKE_PIN(P46, PIOC, PIO_PC17); +MAKE_PIN(P47, PIOC, PIO_PC16); +MAKE_PIN(P48, PIOC, PIO_PC15); +MAKE_PIN(P49, PIOC, PIO_PC14); +MAKE_PIN(P50, PIOC, PIO_PC13); +MAKE_PIN(P51, PIOC, PIO_PC12); +MAKE_PIN(P52, PIOB, PIO_PB21); +MAKE_PIN(P53, PIOB, PIO_PB14); +MAKE_PIN(P54, PIOA, PIO_PA16); +MAKE_PIN(P55, PIOA, PIO_PA24); +MAKE_PIN(P56, PIOA, PIO_PA23); +MAKE_PIN(P57, PIOA, PIO_PA22); +MAKE_PIN(P58, PIOA, PIO_PA6); +MAKE_PIN(P59, PIOA, PIO_PA4); +MAKE_PIN(P60, PIOA, PIO_PA3); +MAKE_PIN(P61, PIOA, PIO_PA2); +MAKE_PIN(P62, PIOB, PIO_PB17); +MAKE_PIN(P63, PIOB, PIO_PB18); +MAKE_PIN(P64, PIOB, PIO_PB19); +MAKE_PIN(P65, PIOB, PIO_PB20); +MAKE_PIN(P66, PIOB, PIO_PB15); +MAKE_PIN(P67, PIOB, PIO_PB16); +MAKE_PIN(P68, PIOA, PIO_PA1); +MAKE_PIN(P69, PIOA, PIO_PA0); +MAKE_PIN(P70, PIOA, PIO_PA17); +MAKE_PIN(P71, PIOA, PIO_PA18); +MAKE_PIN(P72, PIOC, PIO_PC30); +MAKE_PIN(P73, PIOA, PIO_PA21); +MAKE_PIN(P74, PIOA, PIO_PA25); // MISO +MAKE_PIN(P75, PIOA, PIO_PA26); // MOSI +MAKE_PIN(P76, PIOA, PIO_PA27); // CLK +MAKE_PIN(P77, PIOA, PIO_PA28); +MAKE_PIN(P78, PIOB, PIO_PB23); // Unconnected + +#undef MAKE_PIN + +#elif defined(RBL_NRF51822) + +#define MAKE_PIN(className, pin) \ +class className { \ +public: \ + static void Set() { \ + nrf_gpio_pin_set(pin); \ + } \ + static void Clear() { \ + nrf_gpio_pin_clear(pin); \ + } \ + static void SetDirRead() { \ + nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL); \ + } \ + static void SetDirWrite() { \ + nrf_gpio_cfg_output(pin); \ + } \ + static uint8_t IsSet() { \ + return (uint8_t)nrf_gpio_pin_read(pin); \ + } \ +}; + +// See: pin_transform.c in RBL nRF51822 SDK +MAKE_PIN(P0, Pin_nRF51822_to_Arduino(D0)); +MAKE_PIN(P1, Pin_nRF51822_to_Arduino(D1)); +MAKE_PIN(P2, Pin_nRF51822_to_Arduino(D2)); +MAKE_PIN(P3, Pin_nRF51822_to_Arduino(D3)); +MAKE_PIN(P4, Pin_nRF51822_to_Arduino(D4)); +MAKE_PIN(P5, Pin_nRF51822_to_Arduino(D5)); +MAKE_PIN(P6, Pin_nRF51822_to_Arduino(D6)); +MAKE_PIN(P7, Pin_nRF51822_to_Arduino(D7)); +MAKE_PIN(P8, Pin_nRF51822_to_Arduino(D8)); +MAKE_PIN(P9, Pin_nRF51822_to_Arduino(D9)); // INT +MAKE_PIN(P10, Pin_nRF51822_to_Arduino(D10)); // SS +MAKE_PIN(P11, Pin_nRF51822_to_Arduino(D11)); +MAKE_PIN(P12, Pin_nRF51822_to_Arduino(D12)); +MAKE_PIN(P13, Pin_nRF51822_to_Arduino(D13)); +MAKE_PIN(P14, Pin_nRF51822_to_Arduino(D14)); +MAKE_PIN(P15, Pin_nRF51822_to_Arduino(D15)); +MAKE_PIN(P17, Pin_nRF51822_to_Arduino(D17)); // MISO +MAKE_PIN(P18, Pin_nRF51822_to_Arduino(D18)); // MOSI +MAKE_PIN(P16, Pin_nRF51822_to_Arduino(D16)); // CLK +MAKE_PIN(P19, Pin_nRF51822_to_Arduino(D19)); +MAKE_PIN(P20, Pin_nRF51822_to_Arduino(D20)); +MAKE_PIN(P21, Pin_nRF51822_to_Arduino(D21)); +MAKE_PIN(P22, Pin_nRF51822_to_Arduino(D22)); +MAKE_PIN(P23, Pin_nRF51822_to_Arduino(D23)); +MAKE_PIN(P24, Pin_nRF51822_to_Arduino(D24)); + +#undef MAKE_PIN + + +#else +#error "Please define board in avrpins.h" + +#endif + +#endif // __arm__ + +#endif //_avrpins_h_ diff --git a/Marlin/usb-flashdrive/lib/confdescparser.h b/Marlin/usb-flashdrive/lib/confdescparser.h new file mode 100644 index 000000000..f02dfb1e5 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/confdescparser.h @@ -0,0 +1,217 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__) +#error "Never include confdescparser.h directly; include Usb.h instead" +#else + +#define __CONFDESCPARSER_H__ + +class UsbConfigXtracter { +public: + //virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0; + //virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0; + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0; +}; + +#define CP_MASK_COMPARE_CLASS 1 +#define CP_MASK_COMPARE_SUBCLASS 2 +#define CP_MASK_COMPARE_PROTOCOL 4 +#define CP_MASK_COMPARE_ALL 7 + +// Configuration Descriptor Parser Class Template + +template +class ConfigDescParser : public USBReadParser { + UsbConfigXtracter *theXtractor; + MultiValueBuffer theBuffer; + MultiByteValueParser valParser; + ByteSkipper theSkipper; + uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/]; + + uint8_t stateParseDescr; // ParseDescriptor state + + uint8_t dscrLen; // Descriptor length + uint8_t dscrType; // Descriptor type + + bool isGoodInterface; // Apropriate interface flag + uint8_t confValue; // Configuration value + uint8_t protoValue; // Protocol value + uint8_t ifaceNumber; // Interface number + uint8_t ifaceAltSet; // Interface alternate settings + + bool UseOr; + bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn); + void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); + +public: + + void SetOR(void) { + UseOr = true; + } + ConfigDescParser(UsbConfigXtracter *xtractor); + virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); +}; + +template +ConfigDescParser::ConfigDescParser(UsbConfigXtracter *xtractor) : +theXtractor(xtractor), +stateParseDescr(0), +dscrLen(0), +dscrType(0), +UseOr(false) { + theBuffer.pValue = varBuffer; + valParser.Initialize(&theBuffer); + theSkipper.Initialize(&theBuffer); +}; + +template +void ConfigDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) { + uint16_t cntdn = (uint16_t)len; + uint8_t *p = (uint8_t*)pbuf; + + while(cntdn) + if(!ParseDescriptor(&p, &cntdn)) + return; +} + +/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and + compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ +template +bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) { + USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast(varBuffer); + USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast(varBuffer); + switch(stateParseDescr) { + case 0: + theBuffer.valueSize = 2; + valParser.Initialize(&theBuffer); + stateParseDescr = 1; + case 1: + if(!valParser.Parse(pp, pcntdn)) + return false; + dscrLen = *((uint8_t*)theBuffer.pValue); + dscrType = *((uint8_t*)theBuffer.pValue + 1); + stateParseDescr = 2; + case 2: + // This is a sort of hack. Assuming that two bytes are all ready in the buffer + // the pointer is positioned two bytes ahead in order for the rest of descriptor + // to be read right after the size and the type fields. + // This should be used carefully. varBuffer should be used directly to handle data + // in the buffer. + theBuffer.pValue = varBuffer + 2; + stateParseDescr = 3; + case 3: + switch(dscrType) { + case USB_DESCRIPTOR_INTERFACE: + isGoodInterface = false; + case USB_DESCRIPTOR_CONFIGURATION: + theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2; + break; + case USB_DESCRIPTOR_ENDPOINT: + theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2; + break; + case HID_DESCRIPTOR_HID: + theBuffer.valueSize = dscrLen - 2; + break; + } + valParser.Initialize(&theBuffer); + stateParseDescr = 4; + case 4: + switch(dscrType) { + case USB_DESCRIPTOR_CONFIGURATION: + if(!valParser.Parse(pp, pcntdn)) + return false; + confValue = ucd->bConfigurationValue; + break; + case USB_DESCRIPTOR_INTERFACE: + if(!valParser.Parse(pp, pcntdn)) + return false; + if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID) + break; + if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID) + break; + if(UseOr) { + if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol))) + break; + } else { + if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID) + break; + } + isGoodInterface = true; + ifaceNumber = uid->bInterfaceNumber; + ifaceAltSet = uid->bAlternateSetting; + protoValue = uid->bInterfaceProtocol; + break; + case USB_DESCRIPTOR_ENDPOINT: + if(!valParser.Parse(pp, pcntdn)) + return false; + if(isGoodInterface) + if(theXtractor) + theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer); + break; + //case HID_DESCRIPTOR_HID: + // if (!valParser.Parse(pp, pcntdn)) + // return false; + // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); + // break; + default: + if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2)) + return false; + } + theBuffer.pValue = varBuffer; + stateParseDescr = 0; + } + return true; +} + +template +void ConfigDescParser::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { + Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80); + Notify(PSTR("bDescLength:\t\t"), 0x80); + PrintHex (pDesc->bLength, 0x80); + + Notify(PSTR("\r\nbDescriptorType:\t"), 0x80); + PrintHex (pDesc->bDescriptorType, 0x80); + + Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80); + PrintHex (pDesc->bcdHID, 0x80); + + Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80); + PrintHex (pDesc->bCountryCode, 0x80); + + Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80); + PrintHex (pDesc->bNumDescriptors, 0x80); + + //Notify(PSTR("\r\nbDescrType:\t\t")); + //PrintHex(pDesc->bDescrType); + // + //Notify(PSTR("\r\nwDescriptorLength:\t")); + //PrintHex(pDesc->wDescriptorLength); + + for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) { + HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType); + + Notify(PSTR("\r\nbDescrType:\t\t"), 0x80); + PrintHex (pLT[i].bDescrType, 0x80); + + Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80); + PrintHex (pLT[i].wDescriptorLength, 0x80); + } + Notify(PSTR("\r\n"), 0x80); +} + + +#endif // __CONFDESCPARSER_H__ diff --git a/Marlin/usb-flashdrive/lib/gpl2.txt b/Marlin/usb-flashdrive/lib/gpl2.txt new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/Marlin/usb-flashdrive/lib/gpl2.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Marlin/usb-flashdrive/lib/keywords.txt b/Marlin/usb-flashdrive/lib/keywords.txt new file mode 100644 index 000000000..c7bd007cc --- /dev/null +++ b/Marlin/usb-flashdrive/lib/keywords.txt @@ -0,0 +1,361 @@ +#################################################### +# Syntax Coloring Map For USB Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +USB KEYWORD1 +USBHub KEYWORD1 + +#################################################### +# Syntax Coloring Map For BTD (Bluetooth) Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +BTD KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### +Task KEYWORD2 + +#################################################### +# Syntax Coloring Map For PS3/PS4 Bluetooth/USB Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +PS3BT KEYWORD1 +PS3USB KEYWORD1 +PS4BT KEYWORD1 +PS4USB KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### +setBdaddr KEYWORD2 +getBdaddr KEYWORD2 +setMoveBdaddr KEYWORD2 +getMoveBdaddr KEYWORD2 +getMoveCalibration KEYWORD2 + +getButtonPress KEYWORD2 +getButtonClick KEYWORD2 +getAnalogButton KEYWORD2 +getAnalogHat KEYWORD2 +getSensor KEYWORD2 +getAngle KEYWORD2 +get9DOFValues KEYWORD2 +getStatus KEYWORD2 +printStatusString KEYWORD2 +getTemperature KEYWORD2 +disconnect KEYWORD2 + +setAllOff KEYWORD2 +setRumbleOff KEYWORD2 +setRumbleOn KEYWORD2 +setLedOff KEYWORD2 +setLedOn KEYWORD2 +setLedToggle KEYWORD2 +setLedFlash KEYWORD2 +moveSetBulb KEYWORD2 +moveSetRumble KEYWORD2 + +attachOnInit KEYWORD2 + +PS3Connected KEYWORD2 +PS3MoveConnected KEYWORD2 +PS3NavigationConnected KEYWORD2 + +isReady KEYWORD2 +watingForConnection KEYWORD2 + +isTouching KEYWORD2 +getX KEYWORD2 +getY KEYWORD2 +getTouchCounter KEYWORD2 + +getUsbStatus KEYWORD2 +getAudioStatus KEYWORD2 +getMicStatus KEYWORD2 + +#################################################### +# Constants and enums (LITERAL1) +#################################################### +OFF LITERAL1 +LED1 LITERAL1 +LED2 LITERAL1 +LED3 LITERAL1 +LED4 LITERAL1 +LED5 LITERAL1 +LED6 LITERAL1 +LED7 LITERAL1 +LED8 LITERAL1 +LED9 LITERAL1 +LED10 LITERAL1 + +Red LITERAL1 +Green LITERAL1 +Blue LITERAL1 +Yellow LITERAL1 +Lightblue LITERAL1 +Purble LITERAL1 +White LITERAL1 +Off LITERAL1 + +SELECT LITERAL1 +L3 LITERAL1 +R3 LITERAL1 +START LITERAL1 +UP LITERAL1 +RIGHT LITERAL1 +DOWN LITERAL1 +LEFT LITERAL1 +L2 LITERAL1 +R2 LITERAL1 +L1 LITERAL1 +R1 LITERAL1 +TRIANGLE LITERAL1 +CIRCLE LITERAL1 +CROSS LITERAL1 +SQUARE LITERAL1 +PS LITERAL1 +MOVE LITERAL1 +T LITERAL1 + +SHARE LITERAL1 +OPTIONS LITERAL1 +TOUCHPAD LITERAL1 + +LeftHatX LITERAL1 +LeftHatY LITERAL1 +RightHatX LITERAL1 +RightHatY LITERAL1 + +aX LITERAL1 +aY LITERAL1 +aZ LITERAL1 +gX LITERAL1 +gY LITERAL1 +gZ LITERAL1 +aXmove LITERAL1 +aYmove LITERAL1 +aZmove LITERAL1 +gXmove LITERAL1 +gYmove LITERAL1 +gZmove LITERAL1 +tempMove LITERAL1 +mXmove LITERAL1 +mZmove LITERAL1 +mYmove LITERAL1 + +Pitch LITERAL1 +Roll LITERAL1 + +Plugged LITERAL1 +Unplugged LITERAL1 +Charging LITERAL1 +NotCharging LITERAL1 +Shutdown LITERAL1 +Dying LITERAL1 +Low LITERAL1 +High LITERAL1 +Full LITERAL1 +MoveCharging LITERAL1 +MoveNotCharging LITERAL1 +MoveShutdown LITERAL1 +MoveDying LITERAL1 +MoveLow LITERAL1 +MoveHigh LITERAL1 +MoveFull LITERAL1 +CableRumble LITERAL1 +Cable LITERAL1 +BluetoothRumble LITERAL1 +Bluetooth LITERAL1 + +RumbleHigh LITERAL1 +RumbleLow LITERAL1 + +#################################################### +# Syntax Coloring Map For Xbox 360 Libraries +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +XBOXUSB KEYWORD1 +XBOXOLD KEYWORD1 +XBOXRECV KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### + +setLedRaw KEYWORD2 +setLedBlink KEYWORD2 +setLedMode KEYWORD2 +getBatteryLevel KEYWORD2 +buttonChanged KEYWORD2 + +XboxReceiverConnected KEYWORD2 +Xbox360Connected KEYWORD2 + +#################################################### +# Constants and enums (LITERAL1) +#################################################### + +ALL LITERAL1 + +ROTATING LITERAL1 +FASTBLINK LITERAL1 +SLOWBLINK LITERAL1 +ALTERNATING LITERAL1 + +BACK LITERAL1 + +XBOX LITERAL1 +SYNC LITERAL1 + +BLACK LITERAL1 +WHITE LITERAL1 + +A LITERAL1 +B LITERAL1 +X LITERAL1 +Y LITERAL1 + +#################################################### +# Syntax Coloring Map For RFCOMM/SPP Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +SPP KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### + +connected KEYWORD2 +discard KEYWORD2 + +#################################################### +# Syntax Coloring Map For Wiimote Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +WII KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### + +wiimoteConnected KEYWORD2 +nunchuckConnected KEYWORD2 +motionPlusConnected KEYWORD2 +wiiUProControllerConnected KEYWORD2 +setRumbleToggle KEYWORD2 +getPitch KEYWORD2 +getRoll KEYWORD2 +getYaw KEYWORD2 +getWiimotePitch KEYWORD2 +getWiimoteRoll KEYWORD2 +getNunchuckPitch KEYWORD2 +getNunchuckRoll KEYWORD2 +PAIR KEYWORD2 +statusRequest KEYWORD2 +getBatteryLevel KEYWORD2 +getWiiState KEYWORD2 + +#################################################### +# Constants and enums (LITERAL1) +#################################################### + +PLUS LITERAL1 +MINUS LITERAL1 +ONE LITERAL1 +TWO LITERAL1 +HOME LITERAL1 +Z LITERAL1 +C LITERAL1 +L LITERAL1 +R LITERAL1 +ZL LITERAL1 +ZR LITERAL1 +HatX LITERAL1 +HatY LITERAL1 + +#################################################### +# Methods and Functions for the IR Camera +#################################################### + +IRinitialize KEYWORD2 +isIRCameraEnabled KEYWORD2 +getIRx1 KEYWORD2 +getIRy1 KEYWORD2 +getIRs1 KEYWORD2 +getIRx2 KEYWORD2 +getIRy2 KEYWORD2 +getIRs2 KEYWORD2 +getIRx3 KEYWORD2 +getIRy3 KEYWORD2 +getIRs3 KEYWORD2 +getIRx4 KEYWORD2 +getIRy4 KEYWORD2 +getIRs4 KEYWORD2 + +#################################################### +# Syntax Coloring Map For BTHID Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +BTHID KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### +SetReportParser KEYWORD2 +setProtocolMode KEYWORD2 + +#################################################### +# Syntax Coloring Map For PS Buzz Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +PSBuzz KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### + +setLedOnAll KEYWORD2 +setLedOffAll KEYWORD2 + +#################################################### +# Constants and enums (LITERAL1) +#################################################### + +RED LITERAL1 +YELLOW LITERAL1 +GREEN LITERAL1 +ORANGE LITERAL1 +BLUE LITERAL1 \ No newline at end of file diff --git a/Marlin/usb-flashdrive/lib/library.json b/Marlin/usb-flashdrive/lib/library.json new file mode 100644 index 000000000..6f7c5753b --- /dev/null +++ b/Marlin/usb-flashdrive/lib/library.json @@ -0,0 +1,46 @@ +{ + "name": "USB-Host-Shield-20", + "keywords": "usb, host, ftdi, adk, acm, pl2303, hid, bluetooth, spp, ps3, ps4, buzz, xbox, wii, mass storage", + "description": "Revision 2.0 of MAX3421E-based USB Host Shield Library", + "authors": + [ + { + "name": "Oleg Mazurov", + "email": "mazurov@circuitsathome.com", + "url": "http://www.circuitsathome.com", + "maintainer": true + }, + { + "name": "Alexei Glushchenko", + "email": "alex-gl@mail.ru" + }, + { + "name": "Kristian Lauszus", + "email": "kristianl@tkjelectronics.com", + "url": "http://tkjelectronics.com", + "maintainer": true + }, + { + "name": "Andrew Kroll", + "email": "xxxajk@gmail.com", + "maintainer": true + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/felis/USB_Host_Shield_2.0.git" + }, + "examples": + [ + "examples/*/*.ino", + "examples/*/*/*.ino" + ], + "frameworks": "arduino", + "platforms": + [ + "atmelavr", + "teensy", + "atmelsam" + ] +} diff --git a/Marlin/usb-flashdrive/lib/macros.h b/Marlin/usb-flashdrive/lib/macros.h new file mode 100644 index 000000000..514768308 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/macros.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(MACROS_H) +#error "Never include macros.h directly; include Usb.h instead" +#else +#define MACROS_H + +//////////////////////////////////////////////////////////////////////////////// +// HANDY MACROS +//////////////////////////////////////////////////////////////////////////////// + +#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h))) +#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h))) +#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el) +#define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el); + +#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) +#ifndef __BYTE_GRABBING_DEFINED__ +#define __BYTE_GRABBING_DEFINED__ 1 +#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN +// Note: Use this if your compiler generates horrible assembler! +#define BGRAB0(__usi__) (((uint8_t *)&(__usi__))[0]) +#define BGRAB1(__usi__) (((uint8_t *)&(__usi__))[1]) +#define BGRAB2(__usi__) (((uint8_t *)&(__usi__))[2]) +#define BGRAB3(__usi__) (((uint8_t *)&(__usi__))[3]) +#define BGRAB4(__usi__) (((uint8_t *)&(__usi__))[4]) +#define BGRAB5(__usi__) (((uint8_t *)&(__usi__))[5]) +#define BGRAB6(__usi__) (((uint8_t *)&(__usi__))[6]) +#define BGRAB7(__usi__) (((uint8_t *)&(__usi__))[7]) +#else +// Note: The cast alone to uint8_t is actually enough. +// GCC throws out the "& 0xff", and the size is no different. +// Some compilers need it. +#define BGRAB0(__usi__) ((uint8_t)((__usi__) & 0xff )) +#define BGRAB1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xff)) +#define BGRAB2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xff)) +#define BGRAB3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xff)) +#define BGRAB4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xff)) +#define BGRAB5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xff)) +#define BGRAB6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xff)) +#define BGRAB7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xff)) +#endif +#define BOVER1(__usi__) ((uint16_t)(__usi__) << 8) +#define BOVER2(__usi__) ((uint32_t)(__usi__) << 16) +#define BOVER3(__usi__) ((uint32_t)(__usi__) << 24) +#define BOVER4(__usi__) ((uint64_t)(__usi__) << 32) +#define BOVER5(__usi__) ((uint64_t)(__usi__) << 40) +#define BOVER6(__usi__) ((uint64_t)(__usi__) << 48) +#define BOVER7(__usi__) ((uint64_t)(__usi__) << 56) + +// These are the smallest and fastest ways I have found so far in pure C/C++. +#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__))) +#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__))) +#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__))) +#endif + +/* + * Debug macros: Strings are stored in progmem (flash) instead of RAM. + */ +#define USBTRACE(s) (Notify(PSTR(s), 0x80)) +#define USBTRACE1(s,l) (Notify(PSTR(s), l)) +#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80)) +#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l)) + + +#endif /* MACROS_H */ + diff --git a/Marlin/usb-flashdrive/lib/masstorage.cpp b/Marlin/usb-flashdrive/lib/masstorage.cpp new file mode 100644 index 000000000..3aea5dcff --- /dev/null +++ b/Marlin/usb-flashdrive/lib/masstorage.cpp @@ -0,0 +1,1270 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#include "masstorage.h" + +const uint8_t BulkOnly::epDataInIndex = 1; +const uint8_t BulkOnly::epDataOutIndex = 2; +const uint8_t BulkOnly::epInterruptInIndex = 3; + +//////////////////////////////////////////////////////////////////////////////// + +// Interface code + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Get the capacity of the media + * + * @param lun Logical Unit Number + * @return media capacity + */ +uint32_t BulkOnly::GetCapacity(uint8_t lun) { + if(LUNOk[lun]) + return CurrentCapacity[lun]; + return 0LU; +} + +/** + * Get the sector (block) size used on the media + * + * @param lun Logical Unit Number + * @return media sector size + */ +uint16_t BulkOnly::GetSectorSize(uint8_t lun) { + if(LUNOk[lun]) + return CurrentSectorSize[lun]; + return 0U; +} + +/** + * Test if LUN is ready for use + * + * @param lun Logical Unit Number + * @return true if LUN is ready for use + */ +bool BulkOnly::LUNIsGood(uint8_t lun) { + return LUNOk[lun]; +} + +/** + * Test if LUN is write protected + * + * @param lun Logical Unit Number + * @return cached status of write protect switch + */ +boolean BulkOnly::WriteProtected(uint8_t lun) { + return WriteOk[lun]; +} + +/** + * Wrap and execute a SCSI CDB with length of 6 + * + * @param cdb CDB to execute + * @param buf_size Size of expected transaction + * @param buf Buffer + * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT + * @return + */ +uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { + // promote buf_size to 32bits. + CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); + //SetCurLUN(cdb->LUN); + return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); +} + +/** + * Wrap and execute a SCSI CDB with length of 10 + * + * @param cdb CDB to execute + * @param buf_size Size of expected transaction + * @param buf Buffer + * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT + * @return + */ +uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { + // promote buf_size to 32bits. + CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); + //SetCurLUN(cdb->LUN); + return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); +} + +/** + * Lock or Unlock the tray or door on device. + * Caution: Some devices with buggy firmware will lock up. + * + * @param lun Logical Unit Number + * @param lock 1 to lock, 0 to unlock + * @return + */ +uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) { + Notify(PSTR("\r\nLockMedia\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock); + return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN); +} + +/** + * Media control, for spindle motor and media tray or door. + * This includes CDROM, TAPE and anything with a media loader. + * + * @param lun Logical Unit Number + * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media + * @return 0 on success + */ +uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { + Notify(PSTR("\r\nMediaCTL\r\n"), 0x80); + Notify(PSTR("-----------------\r\n"), 0x80); + + uint8_t rcode = MASS_ERR_UNIT_NOT_READY; + if(bAddress) { + CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0); + rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT); + } else { + SetCurLUN(lun); + } + return rcode; +} + +/** + * Read data from media + * + * @param lun Logical Unit Number + * @param addr LBA address on media to read + * @param bsize size of a block (we should probably use the cached size) + * @param blocks how many blocks to read + * @param buf memory that is able to hold the requested data + * @return 0 on success + */ +uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) { + if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; + Notify(PSTR("\r\nRead LUN:\t"), 0x80); + D_PrintHex (lun, 0x90); + Notify(PSTR("\r\nLBA:\t\t"), 0x90); + D_PrintHex (addr, 0x90); + Notify(PSTR("\r\nblocks:\t\t"), 0x90); + D_PrintHex (blocks, 0x90); + Notify(PSTR("\r\nblock size:\t"), 0x90); + D_PrintHex (bsize, 0x90); + Notify(PSTR("\r\n---------\r\n"), 0x80); + CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr); + +again: + uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN); + + if(er == MASS_ERR_STALL) { + MediaCTL(lun, 1); + DELAY(150); + if(!TestUnitReady(lun)) goto again; + } + return er; +} + +/** + * Write data to media + * + * @param lun Logical Unit Number + * @param addr LBA address on media to write + * @param bsize size of a block (we should probably use the cached size) + * @param blocks how many blocks to write + * @param buf memory that contains the data to write + * @return 0 on success + */ +uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) { + if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; + if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED; + Notify(PSTR("\r\nWrite LUN:\t"), 0x80); + D_PrintHex (lun, 0x90); + Notify(PSTR("\r\nLBA:\t\t"), 0x90); + D_PrintHex (addr, 0x90); + Notify(PSTR("\r\nblocks:\t\t"), 0x90); + D_PrintHex (blocks, 0x90); + Notify(PSTR("\r\nblock size:\t"), 0x90); + D_PrintHex (bsize, 0x90); + Notify(PSTR("\r\n---------\r\n"), 0x80); + CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr); + +again: + uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT); + + if(er == MASS_ERR_WRITE_STALL) { + MediaCTL(lun, 1); + DELAY(150); + if(!TestUnitReady(lun)) goto again; + } + return er; +} + +// End of user functions, the remaining code below is driver internals. +// Only developer serviceable parts below! + +//////////////////////////////////////////////////////////////////////////////// + +// Main driver code + +//////////////////////////////////////////////////////////////////////////////// + +BulkOnly::BulkOnly(USB *p) : +pUsb(p), +bAddress(0), +bIface(0), +bNumEP(1), +qNextPollTime(0), +bPollEnable(false), +//dCBWTag(0), +bLastUsbError(0) { + ClearAllEP(); + dCBWTag = 0; + if(pUsb) + pUsb->RegisterDeviceClass(this); +} + +/** + * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success + * We need to standardize either the rcode, or change the API to return values + * so a signal that additional actions are required can be produced. + * Some of these codes do exist already. + * + * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance. + * Doing so would save some program memory when using multiple drivers. + * + * @param parent USB address of parent + * @param port address of port on parent + * @param lowspeed true if device is low speed + * @return + */ +uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { + + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast(buf); + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + USBTRACE("MS ConfigureDevice\r\n"); + ClearAllEP(); + AddressPool &addrPool = pUsb->GetAddressPool(); + + + if(bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + if(!p) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if(!p->epinfo) { + USBTRACE("epinfo\r\n"); + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + // Get device descriptor + rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if(rcode) { + goto FailGetDevDescr; + } + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + if(!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + // Extract Max Packet Size from the device descriptor + epInfo[0].maxPktSize = udd->bMaxPacketSize0; + // Steal and abuse from epInfo structure to save on memory. + epInfo[1].epAddr = udd->bNumConfigurations; + // + return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; + +FailGetDevDescr: +#ifdef DEBUG_USB_HOST + NotifyFailGetDevDescr(rcode); +#endif + rcode = USB_ERROR_FailGetDevDescr; + + Release(); + return rcode; +}; + +/** + * + * @param parent (not used) + * @param port (not used) + * @param lowspeed true if device is low speed + * @return 0 for success + */ +uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { + uint8_t rcode; + uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations + epInfo[1].epAddr = 0; + USBTRACE("MS Init\r\n"); + + AddressPool &addrPool = pUsb->GetAddressPool(); + UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + // Assign new address to the device + DELAY(2000); + rcode = pUsb->setAddr(0, 0, bAddress); + + if(rcode) { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; + USBTRACE2("setAddr:", rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if(rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for(uint8_t i = 0; i < num_of_conf; i++) { + ConfigDescParser< USB_CLASS_MASS_STORAGE, + MASS_SUBCLASS_SCSI, + MASS_PROTO_BBB, + CP_MASK_COMPARE_CLASS | + CP_MASK_COMPARE_SUBCLASS | + CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); + + if(rcode) + goto FailGetConfDescr; + + if(bNumEP > 1) + break; + } + + if(bNumEP < 3) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if(rcode) + goto FailSetConfDescr; + + //Linux does a 1sec delay after this. + DELAY(1000); + + rcode = GetMaxLUN(&bMaxLUN); + if(rcode) + goto FailGetMaxLUN; + + if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1; + ErrorMessage (PSTR("MaxLUN"), bMaxLUN); + + DELAY(1000); // Delay a bit for slow firmware. + + for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { + InquiryResponse response; + rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); + if(rcode) { + ErrorMessage (PSTR("Inquiry"), rcode); + } else { +#if 0 + printf("LUN %i `", lun); + uint8_t *buf = response.VendorID; + for(int i = 0; i < 28; i++) printf("%c", buf[i]); + printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier); + printf("Device type %2.2X ", response.DeviceType); + printf("RMB %1.1X ", response.Removable); + printf("SSCS %1.1X ", response.SCCS); + uint8_t sv = response.Version; + printf("SCSI version %2.2X\r\nDevice conforms to ", sv); + switch(sv) { + case 0: + printf("No specific"); + break; + case 1: + printf("ANSI X3.131-1986 (ANSI 1)"); + break; + case 2: + printf("ANSI X3.131-1994 (ANSI 2)"); + break; + case 3: + printf("ANSI INCITS 301-1997 (SPC)"); + break; + case 4: + printf("ANSI INCITS 351-2001 (SPC-2)"); + break; + case 5: + printf("ANSI INCITS 408-2005 (SPC-4)"); + break; + case 6: + printf("T10/1731-D (SPC-4)"); + break; + default: + printf("unknown"); + } + printf(" standards.\r\n"); +#endif + uint8_t tries = 0xf0; + while((rcode = TestUnitReady(lun))) { + if(rcode == 0x08) break; // break on no media, this is OK to do. + // try to lock media and spin up + if(tries < 14) { + LockMedia(lun, 1); + MediaCTL(lun, 1); // I actually have a USB stick that needs this! + } else DELAY(2 * (tries + 1)); + tries++; + if(!tries) break; + } + if(!rcode) { + DELAY(1000); + LUNOk[lun] = CheckLUN(lun); + if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun); + } + } + } + + + CheckMedia(); + + rcode = OnInit(); + + if(rcode) + goto FailOnInit; + +#ifdef DEBUG_USB_HOST + USBTRACE("MS configured\r\n\r\n"); +#endif + + bPollEnable = true; + + //USBTRACE("Poll enabled\r\n"); + return 0; + +FailSetConfDescr: +#ifdef DEBUG_USB_HOST + NotifyFailSetConfDescr(); + goto Fail; +#endif + +FailOnInit: +#ifdef DEBUG_USB_HOST + USBTRACE("OnInit:"); + goto Fail; +#endif + +FailGetMaxLUN: +#ifdef DEBUG_USB_HOST + USBTRACE("GetMaxLUN:"); + goto Fail; +#endif + + //#ifdef DEBUG_USB_HOST + //FailInvalidSectorSize: + // USBTRACE("Sector Size is NOT VALID: "); + // goto Fail; + //#endif + +FailSetDevTblEntry: +#ifdef DEBUG_USB_HOST + NotifyFailSetDevTblEntry(); + goto Fail; +#endif + +FailGetConfDescr: +#ifdef DEBUG_USB_HOST + NotifyFailGetConfDescr(); +#endif + +#ifdef DEBUG_USB_HOST +Fail: + NotifyFail(rcode); +#endif + Release(); + return rcode; +} + +/** + * For driver use only. + * + * @param conf + * @param iface + * @param alt + * @param proto + * @param pep + */ +void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR * pep) { + ErrorMessage (PSTR("Conf.Val"), conf); + ErrorMessage (PSTR("Iface Num"), iface); + ErrorMessage (PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + +#if 1 + if((pep->bmAttributes & 0x02) == 2) { + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + + PrintEndpointDescriptor(pep); + + } +#else + if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP++; + + PrintEndpointDescriptor(pep); +#endif +} + +/** + * For driver use only. + * + * @return + */ +uint8_t BulkOnly::Release() { + ClearAllEP(); + pUsb->GetAddressPool().FreeAddress(bAddress); + return 0; +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @return true if LUN is ready for use. + */ +boolean BulkOnly::CheckLUN(uint8_t lun) { + uint8_t rcode; + Capacity capacity; + for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0; + + rcode = ReadCapacity10(lun, (uint8_t*)capacity.data); + if(rcode) { + //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode); + return false; + } + ErrorMessage (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun); + for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++) + D_PrintHex (capacity.data[i], 0x80); + Notify(PSTR("\r\n\r\n"), 0x80); + // Only 512/1024/2048/4096 are valid values! + uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]); + if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) { + return false; + } + // Store capacity information. + CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF); + + CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1; + if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) { + // Buggy firmware will report 0xffffffff or 0 for no media + if(CurrentCapacity[lun]) + ErrorMessage (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun); + return false; + } + DELAY(20); + Page3F(lun); + if(!TestUnitReady(lun)) return true; + return false; +} + +/** + * For driver use only. + * + * Scan for media change on all LUNs + */ +void BulkOnly::CheckMedia() { + for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { + if(TestUnitReady(lun)) { + LUNOk[lun] = false; + continue; + } + if(!LUNOk[lun]) + LUNOk[lun] = CheckLUN(lun); + } +#if 0 + printf("}}}}}}}}}}}}}}}}STATUS "); + for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { + if(LUNOk[lun]) + printf("#"); + else printf("."); + } + printf("\r\n"); +#endif + qNextPollTime = millis() + 2000; +} + +/** + * For driver use only. + * + * @return + */ +uint8_t BulkOnly::Poll() { + //uint8_t rcode = 0; + + if(!bPollEnable) + return 0; + + if((long)(millis() - qNextPollTime) >= 0L) { + CheckMedia(); + } + //rcode = 0; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + + +// SCSI code + + +//////////////////////////////////////////////////////////////////////////////// + +/** + * For driver use only. + * + * @param plun + * @return + */ +uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) { + uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL); + + if(ret == hrSTALL) + *plun = 0; + + return 0; +} + +/** + * For driver use only. Used during Driver Init + * + * @param lun Logical Unit Number + * @param bsize + * @param buf + * @return + */ +uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { + Notify(PSTR("\r\nInquiry\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0); + uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN); + + return rc; +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @return + */ +uint8_t BulkOnly::TestUnitReady(uint8_t lun) { + //SetCurLUN(lun); + if(!bAddress) + return MASS_ERR_UNIT_NOT_READY; + + Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80); + Notify(PSTR("-----------------\r\n"), 0x80); + + CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0); + return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN); + +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @param pc + * @param page + * @param subpage + * @param len + * @param pbuf + * @return + */ +uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) { + Notify(PSTR("\r\rModeSense\r\n"), 0x80); + Notify(PSTR("------------\r\n"), 0x80); + + CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0); + return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN); +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @param bsize + * @param buf + * @return + */ +uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) { + Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); + Notify(PSTR("---------------\r\n"), 0x80); + + CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun); + return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN); +} + +/** + * For driver use only. + * + * Page 3F contains write protect status. + * + * @param lun Logical Unit Number to test. + * @return Write protect switch status. + */ +uint8_t BulkOnly::Page3F(uint8_t lun) { + uint8_t buf[192]; + for(int i = 0; i < 192; i++) { + buf[i] = 0x00; + } + WriteOk[lun] = true; +#if SKIP_WRITE_PROTECT + return 0; +#else // SKIP_WRITE_PROTECT + uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf); + if(!rc) { + WriteOk[lun] = ((buf[2] & 0x80) == 0); + Notify(PSTR("Mode Sense: "), 0x80); + for(int i = 0; i < 4; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); + } + return rc; +#endif // SKIP_WRITE_PROTECT +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @param size + * @param buf + * @return + */ +uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) { + Notify(PSTR("\r\nRequestSense\r\n"), 0x80); + Notify(PSTR("----------------\r\n"), 0x80); + + CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0); + CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN); + //SetCurLUN(lun); + return Transaction(&cbw, size, buf); +} + + +//////////////////////////////////////////////////////////////////////////////// + + +// USB code + + +//////////////////////////////////////////////////////////////////////////////// + +/** + * For driver use only. + * + * @param index + * @return + */ +uint8_t BulkOnly::ClearEpHalt(uint8_t index) { + if(index == 0) + return 0; + + uint8_t ret = 0; + + while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01)) + DELAY(6); + + if(ret) { + ErrorMessage (PSTR("ClearEpHalt"), ret); + ErrorMessage (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr)); + return ret; + } + epInfo[index].bmSndToggle = 0; + epInfo[index].bmRcvToggle = 0; + // epAttribs = 0; + return 0; +} + +/** + * For driver use only. + * + */ +void BulkOnly::Reset() { + while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) DELAY(6); +} + +/** + * For driver use only. + * + * @return 0 if successful + */ +uint8_t BulkOnly::ResetRecovery() { + Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); + Notify(PSTR("-----------------\r\n"), 0x80); + + DELAY(6); + Reset(); + DELAY(6); + ClearEpHalt(epDataInIndex); + DELAY(6); + bLastUsbError = ClearEpHalt(epDataOutIndex); + DELAY(6); + return bLastUsbError; +} + +/** + * For driver use only. + * + * Clear all EP data and clear all LUN status + */ +void BulkOnly::ClearAllEP() { + for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + + epInfo[i].bmNakPower = USB_NAK_DEFAULT; + } + + for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) { + LUNOk[i] = false; + WriteOk[i] = false; + CurrentCapacity[i] = 0lu; + CurrentSectorSize[i] = 0; + } + + bIface = 0; + bNumEP = 1; + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + bLastUsbError = 0; + bMaxLUN = 0; + bTheLUN = 0; +} + +/** + * For driver use only. + * + * @param pcsw + * @param pcbw + * @return + */ +bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) { + if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) { + Notify(PSTR("CSW:Sig error\r\n"), 0x80); + return false; + } + if(pcsw->dCSWTag != pcbw->dCBWTag) { + Notify(PSTR("CSW:Wrong tag\r\n"), 0x80); + return false; + } + return true; +} + +/** + * For driver use only. + * + * @param error + * @param index + * @return + */ +uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { + uint8_t count = 3; + + bLastUsbError = error; + //if (error) + //ClearEpHalt(index); + while(error && count) { + if(error != hrSUCCESS) { + ErrorMessage (PSTR("USB Error"), error); + ErrorMessage (PSTR("Index"), index); + } + switch(error) { + // case hrWRONGPID: + case hrSUCCESS: + return MASS_ERR_SUCCESS; + case hrBUSY: + // SIE is busy, just hang out and try again. + return MASS_ERR_UNIT_BUSY; + case hrTIMEOUT: + case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; + case hrSTALL: + if(index == 0) + return MASS_ERR_STALL; + ClearEpHalt(index); + if(index != epDataInIndex) + return MASS_ERR_WRITE_STALL; + return MASS_ERR_STALL; + + case hrNAK: + if(index == 0) + return MASS_ERR_UNIT_BUSY; + return MASS_ERR_UNIT_BUSY; + + case hrTOGERR: + // Handle a very super rare corner case, where toggles become de-synched. + // I have only ran into one device that has this firmware bug, and this is + // the only clean way to get back into sync with the buggy device firmware. + // --AJK + if(bAddress && bConfNum) { + error = pUsb->setConf(bAddress, 0, bConfNum); + + if(error) + break; + } + return MASS_ERR_SUCCESS; + default: + ErrorMessage (PSTR("\r\nUSB"), error); + return MASS_ERR_GENERAL_USB_ERROR; + } + count--; + } // while + + return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); +} + +#if MS_WANT_PARSER + +uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) { + return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0); +} +#endif + +/** + * For driver use only. + * + * @param pcbw + * @param buf_size + * @param buf + * @param flags + * @return + */ +uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf +#if MS_WANT_PARSER + , uint8_t flags +#endif + ) { + +#if MS_WANT_PARSER + uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; + printf("Transfersize %i\r\n", bytes); + DELAY(1000); + + boolean callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; +#else + uint16_t bytes = buf_size; +#endif + boolean write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; + uint8_t ret = 0; + uint8_t usberr; + CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles. + SetCurLUN(pcbw->bmCBWLUN); + ErrorMessage (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); + + while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) DELAY(1); + + ret = HandleUsbError(usberr, epDataOutIndex); + //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); + if(ret) { + ErrorMessage (PSTR("============================ CBW"), ret); + } else { + if(bytes) { + if(!write) { +#if MS_WANT_PARSER + if(callback) { + uint8_t rbuf[bytes]; + while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) DELAY(1); + if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); + } else { +#endif + while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) DELAY(1); +#if MS_WANT_PARSER + + } +#endif + ret = HandleUsbError(usberr, epDataInIndex); + } else { + while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) DELAY(1); + ret = HandleUsbError(usberr, epDataOutIndex); + } + if(ret) { + ErrorMessage (PSTR("============================ DAT"), ret); + } + } + } + + { + bytes = sizeof (CommandStatusWrapper); + int tries = 2; + while(tries--) { + while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) DELAY(1); + if(!usberr) break; + ClearEpHalt(epDataInIndex); + if(tries) ResetRecovery(); + } + if(!ret) { + Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); + Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); + } else { + // Throw away csw, IT IS NOT OF ANY USE. + ResetRecovery(); + return ret; + } + ret = HandleUsbError(usberr, epDataInIndex); + if(ret) { + ErrorMessage (PSTR("============================ CSW"), ret); + } + if(usberr == hrSUCCESS) { + if(IsValidCSW(&csw, pcbw)) { + //ErrorMessage (PSTR("CSW.dCBWTag"), csw.dCSWTag); + //ErrorMessage (PSTR("bCSWStatus"), csw.bCSWStatus); + //ErrorMessage (PSTR("dCSWDataResidue"), csw.dCSWDataResidue); + Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); + return csw.bCSWStatus; + } else { + // NOTE! Sometimes this is caused by the reported residue being wrong. + // Get a different device. It isn't compliant, and should have never passed Q&A. + // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter. + // Other devices that exhibit this behavior exist in the wild too. + // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk + Notify(PSTR("Invalid CSW\r\n"), 0x80); + ResetRecovery(); + //return MASS_ERR_SUCCESS; + return MASS_ERR_INVALID_CSW; + } + } + } + return ret; +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @return + */ +uint8_t BulkOnly::SetCurLUN(uint8_t lun) { + if(lun > bMaxLUN) + return MASS_ERR_INVALID_LUN; + bTheLUN = lun; + return MASS_ERR_SUCCESS; +}; + +/** + * For driver use only. + * + * @param status + * @return + */ +uint8_t BulkOnly::HandleSCSIError(uint8_t status) { + uint8_t ret = 0; + + switch(status) { + case 0: return MASS_ERR_SUCCESS; + + case 2: + ErrorMessage (PSTR("Phase Error"), status); + ErrorMessage (PSTR("LUN"), bTheLUN); + ResetRecovery(); + return MASS_ERR_GENERAL_SCSI_ERROR; + + case 1: + ErrorMessage (PSTR("SCSI Error"), status); + ErrorMessage (PSTR("LUN"), bTheLUN); + RequestSenseResponce rsp; + + ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); + + if(ret) { + return MASS_ERR_GENERAL_SCSI_ERROR; + } + ErrorMessage (PSTR("Response Code"), rsp.bResponseCode); + if(rsp.bResponseCode & 0x80) { + Notify(PSTR("Information field: "), 0x80); + for(int i = 0; i < 4; i++) { + D_PrintHex (rsp.CmdSpecificInformation[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); + } + ErrorMessage (PSTR("Sense Key"), rsp.bmSenseKey); + ErrorMessage (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); + ErrorMessage (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); + // warning, this is not testing ASQ, only SK and ASC. + switch(rsp.bmSenseKey) { + case SCSI_S_UNIT_ATTENTION: + switch(rsp.bAdditionalSenseCode) { + case SCSI_ASC_MEDIA_CHANGED: + return MASS_ERR_MEDIA_CHANGED; + default: + return MASS_ERR_UNIT_NOT_READY; + } + case SCSI_S_NOT_READY: + switch(rsp.bAdditionalSenseCode) { + case SCSI_ASC_MEDIUM_NOT_PRESENT: + return MASS_ERR_NO_MEDIA; + default: + return MASS_ERR_UNIT_NOT_READY; + } + case SCSI_S_ILLEGAL_REQUEST: + switch(rsp.bAdditionalSenseCode) { + case SCSI_ASC_LBA_OUT_OF_RANGE: + return MASS_ERR_BAD_LBA; + default: + return MASS_ERR_CMD_NOT_SUPPORTED; + } + default: + return MASS_ERR_GENERAL_SCSI_ERROR; + } + + // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later. + // case 0x05/0x14: we stalled out + // case 0x15/0x16: we naked out. + default: + ErrorMessage (PSTR("Gen SCSI Err"), status); + ErrorMessage (PSTR("LUN"), bTheLUN); + return status; + } // switch +} + + +//////////////////////////////////////////////////////////////////////////////// + + +// Debugging code + + +//////////////////////////////////////////////////////////////////////////////// + +/** + * + * @param ep_ptr + */ +void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) { + Notify(PSTR("Endpoint descriptor:"), 0x80); + Notify(PSTR("\r\nLength:\t\t"), 0x80); + D_PrintHex (ep_ptr->bLength, 0x80); + Notify(PSTR("\r\nType:\t\t"), 0x80); + D_PrintHex (ep_ptr->bDescriptorType, 0x80); + Notify(PSTR("\r\nAddress:\t"), 0x80); + D_PrintHex (ep_ptr->bEndpointAddress, 0x80); + Notify(PSTR("\r\nAttributes:\t"), 0x80); + D_PrintHex (ep_ptr->bmAttributes, 0x80); + Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); + D_PrintHex (ep_ptr->wMaxPacketSize, 0x80); + Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); + D_PrintHex (ep_ptr->bInterval, 0x80); + Notify(PSTR("\r\n"), 0x80); +} + + +//////////////////////////////////////////////////////////////////////////////// + + +// misc/to kill/to-do + + +//////////////////////////////////////////////////////////////////////////////// + +/* We won't be needing this... */ +uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser * prs) { +#if MS_WANT_PARSER + if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; + Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); + Notify(PSTR("---------\r\n"), 0x80); + + CommandBlockWrapper cbw = CommandBlockWrapper(); + + cbw.dCBWSignature = MASS_CBW_SIGNATURE; + cbw.dCBWTag = ++dCBWTag; + cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); + cbw.bmCBWFlags = MASS_CMD_DIR_IN, + cbw.bmCBWLUN = lun; + cbw.bmCBWCBLength = 10; + + cbw.CBWCB[0] = SCSI_CMD_READ_10; + cbw.CBWCB[8] = blocks; + cbw.CBWCB[2] = ((addr >> 24) & 0xff); + cbw.CBWCB[3] = ((addr >> 16) & 0xff); + cbw.CBWCB[4] = ((addr >> 8) & 0xff); + cbw.CBWCB[5] = (addr & 0xff); + + return HandleSCSIError(Transaction(&cbw, bsize, prs, 1)); +#else + return MASS_ERR_NOT_IMPLEMENTED; +#endif +} diff --git a/Marlin/usb-flashdrive/lib/masstorage.h b/Marlin/usb-flashdrive/lib/masstorage.h new file mode 100644 index 000000000..10c4d7288 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/masstorage.h @@ -0,0 +1,571 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(__MASSTORAGE_H__) +#define __MASSTORAGE_H__ + +// Cruft removal, makes driver smaller, faster. +#ifndef MS_WANT_PARSER +#define MS_WANT_PARSER 0 +#endif + +#include "Usb.h" + +#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE + +// Mass Storage Subclass Constants +#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use +#define MASS_SUBCLASS_RBC 0x01 +#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI) +#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157 +#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB +#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i +#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set +#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI +#define MASS_SUBCLASS_IEEE1667 0x08 + +// Mass Storage Class Protocols +#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt) +#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt) +#define MASS_PROTO_OBSOLETE 0x02 +#define MASS_PROTO_BBB 0x50 // Bulk Only Transport +#define MASS_PROTO_UAS 0x62 + +// Request Codes +#define MASS_REQ_ADSC 0x00 +#define MASS_REQ_GET 0xFC +#define MASS_REQ_PUT 0xFD +#define MASS_REQ_GET_MAX_LUN 0xFE +#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset + +#define MASS_CBW_SIGNATURE 0x43425355 +#define MASS_CSW_SIGNATURE 0x53425355 + +#define MASS_CMD_DIR_OUT 0 // (0 << 7) +#define MASS_CMD_DIR_IN 0x80 //(1 << 7) + +/* + * Reference documents from T10 (http://www.t10.org) + * SCSI Primary Commands - 3 (SPC-3) + * SCSI Block Commands - 2 (SBC-2) + * Multi-Media Commands - 5 (MMC-5) + */ + +/* Group 1 commands (CDB's here are should all be 6-bytes) */ +#define SCSI_CMD_TEST_UNIT_READY 0x00 +#define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_FORMAT_UNIT 0x04 +#define SCSI_CMD_READ_6 0x08 +#define SCSI_CMD_WRITE_6 0x0A +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_MODE_SELECT_6 0x15 +#define SCSI_CMD_MODE_SENSE_6 0x1A +#define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_PREVENT_REMOVAL 0x1E +/* Group 2 Commands (CDB's here are 10-bytes) */ +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 +#define SCSI_CMD_READ_CAPACITY_10 0x25 +#define SCSI_CMD_READ_10 0x28 +#define SCSI_CMD_WRITE_10 0x2A +#define SCSI_CMD_SEEK_10 0x2B +#define SCSI_CMD_ERASE_10 0x2C +#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2E +#define SCSI_CMD_VERIFY_10 0x2F +#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35 +#define SCSI_CMD_WRITE_BUFFER 0x3B +#define SCSI_CMD_READ_BUFFER 0x3C +#define SCSI_CMD_READ_SUBCHANNEL 0x42 +#define SCSI_CMD_READ_TOC 0x43 +#define SCSI_CMD_READ_HEADER 0x44 +#define SCSI_CMD_PLAY_AUDIO_10 0x45 +#define SCSI_CMD_GET_CONFIGURATION 0x46 +#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 +#define SCSI_CMD_PLAY_AUDIO_TI 0x48 +#define SCSI_CMD_PLAY_TRACK_REL_10 0x49 +#define SCSI_CMD_GET_EVENT_STATUS 0x4A +#define SCSI_CMD_PAUSE_RESUME 0x4B +#define SCSI_CMD_READ_DISC_INFORMATION 0x51 +#define SCSI_CMD_READ_TRACK_INFORMATION 0x52 +#define SCSI_CMD_RESERVE_TRACK 0x53 +#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 +#define SCSI_CMD_MODE_SELECT_10 0x55 +#define SCSI_CMD_REPAIR_TRACK 0x58 +#define SCSI_CMD_MODE_SENSE_10 0x5A +#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5B +#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5C +#define SCSI_CMD_SEND_CUE_SHEET 0x5D +/* Group 5 Commands (CDB's here are 12-bytes) */ +#define SCSI_CMD_REPORT_LUNS 0xA0 +#define SCSI_CMD_BLANK 0xA1 +#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2 +#define SCSI_CMD_SEND_KEY 0xA3 +#define SCSI_CMD_REPORT_KEY 0xA4 +#define SCSI_CMD_PLAY_AUDIO_12 0xA5 +#define SCSI_CMD_LOAD_UNLOAD 0xA6 +#define SCSI_CMD_SET_READ_AHEAD 0xA7 +#define SCSI_CMD_READ_12 0xA8 +#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9 +#define SCSI_CMD_WRITE_12 0xAA +#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xAB +#define SCSI_CMD_GET_PERFORMANCE 0xAC +#define SCSI_CMD_READ_DVD_STRUCTURE 0xAD +#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5 +#define SCSI_CMD_SET_STREAMING 0xB6 +#define SCSI_CMD_READ_MSF 0xB9 +#define SCSI_CMD_SET_SPEED 0xBB +#define SCSI_CMD_MECHANISM_STATUS 0xBD +#define SCSI_CMD_READ_CD 0xBE +#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBF +/* Vendor-unique Commands, included for completeness */ +#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4 /* SONY unique */ +#define SCSI_CMD_PLAYBACK_CONTROL 0xC9 /* SONY unique */ +#define SCSI_CMD_READ_CDDA 0xD8 /* Vendor unique */ +#define SCSI_CMD_READ_CDXA 0xDB /* Vendor unique */ +#define SCSI_CMD_READ_ALL_SUBCODES 0xDF /* Vendor unique */ + +/* SCSI error codes */ +#define SCSI_S_NOT_READY 0x02 +#define SCSI_S_MEDIUM_ERROR 0x03 +#define SCSI_S_ILLEGAL_REQUEST 0x05 +#define SCSI_S_UNIT_ATTENTION 0x06 +#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21 +#define SCSI_ASC_MEDIA_CHANGED 0x28 +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A + +/* USB error codes */ +#define MASS_ERR_SUCCESS 0x00 +#define MASS_ERR_PHASE_ERROR 0x02 +#define MASS_ERR_UNIT_NOT_READY 0x03 +#define MASS_ERR_UNIT_BUSY 0x04 +#define MASS_ERR_STALL 0x05 +#define MASS_ERR_CMD_NOT_SUPPORTED 0x06 +#define MASS_ERR_INVALID_CSW 0x07 +#define MASS_ERR_NO_MEDIA 0x08 +#define MASS_ERR_BAD_LBA 0x09 +#define MASS_ERR_MEDIA_CHANGED 0x0A +#define MASS_ERR_DEVICE_DISCONNECTED 0x11 +#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error +#define MASS_ERR_INVALID_LUN 0x13 +#define MASS_ERR_WRITE_STALL 0x14 +#define MASS_ERR_READ_NAKS 0x15 +#define MASS_ERR_WRITE_NAKS 0x16 +#define MASS_ERR_WRITE_PROTECTED 0x17 +#define MASS_ERR_NOT_IMPLEMENTED 0xFD +#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE +#define MASS_ERR_GENERAL_USB_ERROR 0xFF +#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes + +#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved +#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked +#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked + +#define MASS_MAX_ENDPOINTS 3 + +struct Capacity { + uint8_t data[8]; + //uint32_t dwBlockAddress; + //uint32_t dwBlockLength; +} __attribute__((packed)); + +struct BASICCDB { + uint8_t Opcode; + + unsigned unused : 5; + unsigned LUN : 3; + + uint8_t info[12]; +} __attribute__((packed)); + +typedef BASICCDB BASICCDB_t; + +struct CDB6 { + uint8_t Opcode; + + unsigned LBAMSB : 5; + unsigned LUN : 3; + + uint8_t LBAHB; + uint8_t LBALB; + uint8_t AllocationLength; + uint8_t Control; + +public: + + CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) : + Opcode(_Opcode), LBAMSB(BGRAB2(LBA) & 0x1f), LUN(_LUN), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)), + AllocationLength(_AllocationLength), Control(_Control) { + } + + CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) : + Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0), + AllocationLength(_AllocationLength), Control(_Control) { + } +} __attribute__((packed)); + +typedef CDB6 CDB6_t; + +struct CDB10 { + uint8_t Opcode; + + unsigned Service_Action : 5; + unsigned LUN : 3; + + uint8_t LBA_L_M_MB; + uint8_t LBA_L_M_LB; + uint8_t LBA_L_L_MB; + uint8_t LBA_L_L_LB; + + uint8_t Misc2; + + uint8_t ALC_MB; + uint8_t ALC_LB; + + uint8_t Control; +public: + + CDB10(uint8_t _Opcode, uint8_t _LUN) : + Opcode(_Opcode), Service_Action(0), LUN(_LUN), + LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0), + Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) { + } + + CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) : + Opcode(_Opcode), Service_Action(0), LUN(_LUN), + LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)), + Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) { + } +} __attribute__((packed)); + +typedef CDB10 CDB10_t; + +struct CDB12 { + uint8_t Opcode; + + unsigned Service_Action : 5; + unsigned Misc : 3; + + uint8_t LBA_L_M_LB; + uint8_t LBA_L_L_MB; + uint8_t LBA_L_L_LB; + + uint8_t ALC_M_LB; + uint8_t ALC_L_MB; + uint8_t ALC_L_LB; + uint8_t Control; +} __attribute__((packed)); + +typedef CDB12 CDB12_t; + +struct CDB_LBA32_16 { + uint8_t Opcode; + + unsigned Service_Action : 5; + unsigned Misc : 3; + + uint8_t LBA_L_M_MB; + uint8_t LBA_L_M_LB; + uint8_t LBA_L_L_MB; + uint8_t LBA_L_L_LB; + + uint8_t A_M_M_MB; + uint8_t A_M_M_LB; + uint8_t A_M_L_MB; + uint8_t A_M_L_LB; + + uint8_t ALC_M_MB; + uint8_t ALC_M_LB; + uint8_t ALC_L_MB; + uint8_t ALC_L_LB; + + uint8_t Misc2; + uint8_t Control; +} __attribute__((packed)); + +struct CDB_LBA64_16 { + uint8_t Opcode; + uint8_t Misc; + + uint8_t LBA_M_M_MB; + uint8_t LBA_M_M_LB; + uint8_t LBA_M_L_MB; + uint8_t LBA_M_L_LB; + + uint8_t LBA_L_M_MB; + uint8_t LBA_L_M_LB; + uint8_t LBA_L_L_MB; + uint8_t LBA_L_L_LB; + + uint8_t ALC_M_MB; + uint8_t ALC_M_LB; + uint8_t ALC_L_MB; + uint8_t ALC_L_LB; + + uint8_t Misc2; + uint8_t Control; +} __attribute__((packed)); + +struct InquiryResponse { + uint8_t DeviceType : 5; + uint8_t PeripheralQualifier : 3; + + unsigned Reserved : 7; + unsigned Removable : 1; + + uint8_t Version; + + unsigned ResponseDataFormat : 4; + unsigned HISUP : 1; + unsigned NormACA : 1; + unsigned TrmTsk : 1; + unsigned AERC : 1; + + uint8_t AdditionalLength; + //uint8_t Reserved3[2]; + + unsigned PROTECT : 1; + unsigned Res : 2; + unsigned ThreePC : 1; + unsigned TPGS : 2; + unsigned ACC : 1; + unsigned SCCS : 1; + + unsigned ADDR16 : 1; + unsigned R1 : 1; + unsigned R2 : 1; + unsigned MCHNGR : 1; + unsigned MULTIP : 1; + unsigned VS : 1; + unsigned ENCSERV : 1; + unsigned BQUE : 1; + + unsigned SoftReset : 1; + unsigned CmdQue : 1; + unsigned Reserved4 : 1; + unsigned Linked : 1; + unsigned Sync : 1; + unsigned WideBus16Bit : 1; + unsigned WideBus32Bit : 1; + unsigned RelAddr : 1; + + uint8_t VendorID[8]; + uint8_t ProductID[16]; + uint8_t RevisionID[4]; +} __attribute__((packed)); + +struct CommandBlockWrapperBase { + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; +public: + + CommandBlockWrapperBase() { + } + + CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) : + dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) { + } +} __attribute__((packed)); + +struct CommandBlockWrapper : public CommandBlockWrapperBase { + + struct { + uint8_t bmCBWLUN : 4; + uint8_t bmReserved1 : 4; + }; + + struct { + uint8_t bmCBWCBLength : 4; + uint8_t bmReserved2 : 4; + }; + + uint8_t CBWCB[16]; + +public: + // All zeroed. + + CommandBlockWrapper() : + CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) { + for(int i = 0; i < 16; i++) CBWCB[i] = 0; + } + + // Generic Wrap, CDB zeroed. + + CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) : + CommandBlockWrapperBase(tag, xflen, flgs), + bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) { + for(int i = 0; i < 16; i++) CBWCB[i] = 0; + // Type punning can cause optimization problems and bugs. + // Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this. + //(((BASICCDB_t *) CBWCB)->LUN) = cmd; + BASICCDB_t *x = reinterpret_cast(CBWCB); + x->LUN = cmd; + } + + // Wrap for CDB of 6 + + CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) : + CommandBlockWrapperBase(tag, xflen, dir), + bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) { + memcpy(&CBWCB, cdb, 6); + } + // Wrap for CDB of 10 + + CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) : + CommandBlockWrapperBase(tag, xflen, dir), + bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) { + memcpy(&CBWCB, cdb, 10); + } +} __attribute__((packed)); + +struct CommandStatusWrapper { + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} __attribute__((packed)); + +struct RequestSenseResponce { + uint8_t bResponseCode; + uint8_t bSegmentNumber; + + uint8_t bmSenseKey : 4; + uint8_t bmReserved : 1; + uint8_t bmILI : 1; + uint8_t bmEOM : 1; + uint8_t bmFileMark : 1; + + uint8_t Information[4]; + uint8_t bAdditionalLength; + uint8_t CmdSpecificInformation[4]; + uint8_t bAdditionalSenseCode; + uint8_t bAdditionalSenseQualifier; + uint8_t bFieldReplaceableUnitCode; + uint8_t SenseKeySpecific[3]; +} __attribute__((packed)); + +class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter { +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + USB *pUsb; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bIface; // interface value + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + EpInfo epInfo[MASS_MAX_ENDPOINTS]; + + uint32_t dCBWTag; // Tag + //uint32_t dCBWDataTransferLength; // Data Transfer Length + uint8_t bLastUsbError; // Last USB error + uint8_t bMaxLUN; // Max LUN + uint8_t bTheLUN; // Active LUN + uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors + uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits + bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes. + bool WriteOk[MASS_MAX_SUPPORTED_LUN]; + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + + + // Additional Initialization Method for Subclasses + + virtual uint8_t OnInit() { + return 0; + }; +public: + BulkOnly(USB *p); + + uint8_t GetLastUsbError() { + return bLastUsbError; + }; + + uint8_t GetbMaxLUN() { + return bMaxLUN; // Max LUN + } + + uint8_t GetbTheLUN() { + return bTheLUN; // Active LUN + } + + boolean WriteProtected(uint8_t lun); + uint8_t MediaCTL(uint8_t lun, uint8_t ctl); + uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf); + uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs); + uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf); + uint8_t LockMedia(uint8_t lun, uint8_t lock); + + bool LUNIsGood(uint8_t lun); + uint32_t GetCapacity(uint8_t lun); + uint16_t GetSectorSize(uint8_t lun); + + // USBDeviceConfig implementation + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed); + + virtual uint8_t Release(); + virtual uint8_t Poll(); + + virtual uint8_t GetAddress() { + return bAddress; + }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); + + virtual boolean DEVCLASSOK(uint8_t klass) { + return (klass == USB_CLASS_MASS_STORAGE); + } + + uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); + uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); + +private: + uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf); + uint8_t TestUnitReady(uint8_t lun); + uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf); + uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf); + uint8_t GetMaxLUN(uint8_t *max_lun); + uint8_t SetCurLUN(uint8_t lun); + void Reset(); + uint8_t ResetRecovery(); + uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf); + void ClearAllEP(); + void CheckMedia(); + boolean CheckLUN(uint8_t lun); + uint8_t Page3F(uint8_t lun); + bool IsValidCBW(uint8_t size, uint8_t *pcbw); + bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw); + + bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw); + + uint8_t ClearEpHalt(uint8_t index); +#if MS_WANT_PARSER + uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags); +#endif + uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf); + uint8_t HandleUsbError(uint8_t error, uint8_t index); + uint8_t HandleSCSIError(uint8_t status); + +}; + +#endif // __MASSTORAGE_H__ diff --git a/Marlin/usb-flashdrive/lib/max3421e.h b/Marlin/usb-flashdrive/lib/max3421e.h new file mode 100644 index 000000000..a386f4b5d --- /dev/null +++ b/Marlin/usb-flashdrive/lib/max3421e.h @@ -0,0 +1,233 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(_usb_h_) || defined(_max3421e_h_) +#error "Never include max3421e.h directly; include Usb.h instead" +#else + +#define _max3421e_h_ + +/* MAX3421E register/bit names and bitmasks */ + +/* Arduino pin definitions */ +/* pin numbers to port numbers */ + + +//#define MAX_INT 9 // Duemielanove + +//#define MAX_GPX 8 + +#define SE0 0 +#define SE1 1 +#define FSHOST 2 +#define LSHOST 3 + +/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */ +// +// MAX3421E Registers in HOST mode. +// +#define rRCVFIFO 0x08 //1<<3 +#define rSNDFIFO 0x10 //2<<3 +#define rSUDFIFO 0x20 //4<<3 +#define rRCVBC 0x30 //6<<3 +#define rSNDBC 0x38 //7<<3 + +#define rUSBIRQ 0x68 //13<<3 +/* USBIRQ Bits */ +#define bmVBUSIRQ 0x40 //b6 +#define bmNOVBUSIRQ 0x20 //b5 +#define bmOSCOKIRQ 0x01 //b0 + +#define rUSBIEN 0x70 //14<<3 +/* USBIEN Bits */ +#define bmVBUSIE 0x40 //b6 +#define bmNOVBUSIE 0x20 //b5 +#define bmOSCOKIE 0x01 //b0 + +#define rUSBCTL 0x78 //15<<3 +/* USBCTL Bits */ +#define bmCHIPRES 0x20 //b5 +#define bmPWRDOWN 0x10 //b4 + +#define rCPUCTL 0x80 //16<<3 +/* CPUCTL Bits */ +#define bmPUSLEWID1 0x80 //b7 +#define bmPULSEWID0 0x40 //b6 +#define bmIE 0x01 //b0 + +#define rPINCTL 0x88 //17<<3 +/* PINCTL Bits */ +#define bmFDUPSPI 0x10 //b4 +#define bmINTLEVEL 0x08 //b3 +#define bmPOSINT 0x04 //b2 +#define bmGPXB 0x02 //b1 +#define bmGPXA 0x01 //b0 +// GPX pin selections +#define GPX_OPERATE 0x00 +#define GPX_VBDET 0x01 +#define GPX_BUSACT 0x02 +#define GPX_SOF 0x03 + +#define rREVISION 0x90 //18<<3 + +#define rIOPINS1 0xa0 //20<<3 + +/* IOPINS1 Bits */ +#define bmGPOUT0 0x01 +#define bmGPOUT1 0x02 +#define bmGPOUT2 0x04 +#define bmGPOUT3 0x08 +#define bmGPIN0 0x10 +#define bmGPIN1 0x20 +#define bmGPIN2 0x40 +#define bmGPIN3 0x80 + +#define rIOPINS2 0xa8 //21<<3 +/* IOPINS2 Bits */ +#define bmGPOUT4 0x01 +#define bmGPOUT5 0x02 +#define bmGPOUT6 0x04 +#define bmGPOUT7 0x08 +#define bmGPIN4 0x10 +#define bmGPIN5 0x20 +#define bmGPIN6 0x40 +#define bmGPIN7 0x80 + +#define rGPINIRQ 0xb0 //22<<3 +/* GPINIRQ Bits */ +#define bmGPINIRQ0 0x01 +#define bmGPINIRQ1 0x02 +#define bmGPINIRQ2 0x04 +#define bmGPINIRQ3 0x08 +#define bmGPINIRQ4 0x10 +#define bmGPINIRQ5 0x20 +#define bmGPINIRQ6 0x40 +#define bmGPINIRQ7 0x80 + +#define rGPINIEN 0xb8 //23<<3 +/* GPINIEN Bits */ +#define bmGPINIEN0 0x01 +#define bmGPINIEN1 0x02 +#define bmGPINIEN2 0x04 +#define bmGPINIEN3 0x08 +#define bmGPINIEN4 0x10 +#define bmGPINIEN5 0x20 +#define bmGPINIEN6 0x40 +#define bmGPINIEN7 0x80 + +#define rGPINPOL 0xc0 //24<<3 +/* GPINPOL Bits */ +#define bmGPINPOL0 0x01 +#define bmGPINPOL1 0x02 +#define bmGPINPOL2 0x04 +#define bmGPINPOL3 0x08 +#define bmGPINPOL4 0x10 +#define bmGPINPOL5 0x20 +#define bmGPINPOL6 0x40 +#define bmGPINPOL7 0x80 + +#define rHIRQ 0xc8 //25<<3 +/* HIRQ Bits */ +#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume +#define bmRWUIRQ 0x02 +#define bmRCVDAVIRQ 0x04 +#define bmSNDBAVIRQ 0x08 +#define bmSUSDNIRQ 0x10 +#define bmCONDETIRQ 0x20 +#define bmFRAMEIRQ 0x40 +#define bmHXFRDNIRQ 0x80 + +#define rHIEN 0xd0 //26<<3 + +/* HIEN Bits */ +#define bmBUSEVENTIE 0x01 +#define bmRWUIE 0x02 +#define bmRCVDAVIE 0x04 +#define bmSNDBAVIE 0x08 +#define bmSUSDNIE 0x10 +#define bmCONDETIE 0x20 +#define bmFRAMEIE 0x40 +#define bmHXFRDNIE 0x80 + +#define rMODE 0xd8 //27<<3 + +/* MODE Bits */ +#define bmHOST 0x01 +#define bmLOWSPEED 0x02 +#define bmHUBPRE 0x04 +#define bmSOFKAENAB 0x08 +#define bmSEPIRQ 0x10 +#define bmDELAYISO 0x20 +#define bmDMPULLDN 0x40 +#define bmDPPULLDN 0x80 + +#define rPERADDR 0xe0 //28<<3 + +#define rHCTL 0xe8 //29<<3 +/* HCTL Bits */ +#define bmBUSRST 0x01 +#define bmFRMRST 0x02 +#define bmSAMPLEBUS 0x04 +#define bmSIGRSM 0x08 +#define bmRCVTOG0 0x10 +#define bmRCVTOG1 0x20 +#define bmSNDTOG0 0x40 +#define bmSNDTOG1 0x80 + +#define rHXFR 0xf0 //30<<3 +/* Host transfer token values for writing the HXFR register (R30) */ +/* OR this bit field with the endpoint number in bits 3:0 */ +#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1 +#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0 +#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0 +#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0 +#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 +#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0 +#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0 + +#define rHRSL 0xf8 //31<<3 + +/* HRSL Bits */ +#define bmRCVTOGRD 0x10 +#define bmSNDTOGRD 0x20 +#define bmKSTATUS 0x40 +#define bmJSTATUS 0x80 +#define bmSE0 0x00 //SE0 - disconnect state +#define bmSE1 0xc0 //SE1 - illegal state + +/* Host error result codes, the 4 LSB's in the HRSL register */ +#define hrSUCCESS 0x00 +#define hrBUSY 0x01 +#define hrBADREQ 0x02 +#define hrUNDEF 0x03 +#define hrNAK 0x04 +#define hrSTALL 0x05 +#define hrTOGERR 0x06 +#define hrWRONGPID 0x07 +#define hrBADBC 0x08 +#define hrPIDERR 0x09 +#define hrPKTERR 0x0A +#define hrCRCERR 0x0B +#define hrKERR 0x0C +#define hrJERR 0x0D +#define hrTIMEOUT 0x0E +#define hrBABBLE 0x0F + +#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB) +#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB) + + +#endif //_max3421e_h_ diff --git a/Marlin/usb-flashdrive/lib/message.cpp b/Marlin/usb-flashdrive/lib/message.cpp new file mode 100644 index 000000000..bdcdd1833 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/message.cpp @@ -0,0 +1,116 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#include "Usb.h" +// 0x80 is the default (i.e. trace) to turn off set this global to something lower. +// this allows for 126 other debugging levels. +// TO-DO: Allow assignment to a different serial port by software +int UsbDEBUGlvl = 0x80; + +void E_Notifyc(char c, int lvl) { + if(UsbDEBUGlvl < lvl) return; +#if defined(ARDUINO) && ARDUINO >=100 + USB_HOST_SERIAL.print(c); +#else + USB_HOST_SERIAL.print(c, BYTE); +#endif + //USB_HOST_SERIAL.flush(); +} + +void E_Notify(char const * msg, int lvl) { + if(UsbDEBUGlvl < lvl) return; + if(!msg) return; + char c; + + while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl); +} + +void E_NotifyStr(char const * msg, int lvl) { + if(UsbDEBUGlvl < lvl) return; + if(!msg) return; + char c; + + while((c = *msg++)) E_Notifyc(c, lvl); +} + +void E_Notify(uint8_t b, int lvl) { + if(UsbDEBUGlvl < lvl) return; +#if defined(ARDUINO) && ARDUINO >=100 + USB_HOST_SERIAL.print(b); +#else + USB_HOST_SERIAL.print(b, DEC); +#endif + //USB_HOST_SERIAL.flush(); +} + +void E_Notify(double d, int lvl) { + if(UsbDEBUGlvl < lvl) return; + USB_HOST_SERIAL.print(d); + //USB_HOST_SERIAL.flush(); +} + +#ifdef DEBUG_USB_HOST + +void NotifyFailGetDevDescr(void) { + Notify(PSTR("\r\ngetDevDescr "), 0x80); +} + +void NotifyFailSetDevTblEntry(void) { + Notify(PSTR("\r\nsetDevTblEn "), 0x80); +} + +void NotifyFailGetConfDescr(void) { + Notify(PSTR("\r\ngetConf "), 0x80); +} + +void NotifyFailSetConfDescr(void) { + Notify(PSTR("\r\nsetConf "), 0x80); +} + +void NotifyFailGetDevDescr(uint8_t reason) { + NotifyFailGetDevDescr(); + NotifyFail(reason); +} + +void NotifyFailSetDevTblEntry(uint8_t reason) { + NotifyFailSetDevTblEntry(); + NotifyFail(reason); + +} + +void NotifyFailGetConfDescr(uint8_t reason) { + NotifyFailGetConfDescr(); + NotifyFail(reason); +} + +void NotifyFailSetConfDescr(uint8_t reason) { + NotifyFailSetConfDescr(); + NotifyFail(reason); +} + +void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) { + Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); + D_PrintHex (VID, 0x80); + Notify(PSTR(" PID: "), 0x80); + D_PrintHex (PID, 0x80); +} + +void NotifyFail(uint8_t rcode) { + D_PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); +} +#endif diff --git a/Marlin/usb-flashdrive/lib/message.h b/Marlin/usb-flashdrive/lib/message.h new file mode 100644 index 000000000..c26628e7f --- /dev/null +++ b/Marlin/usb-flashdrive/lib/message.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#if !defined(_usb_h_) || defined(__MESSAGE_H__) +#error "Never include message.h directly; include Usb.h instead" +#else +#define __MESSAGE_H__ + +extern int UsbDEBUGlvl; + +void E_Notify(char const * msg, int lvl); +void E_Notify(uint8_t b, int lvl); +void E_NotifyStr(char const * msg, int lvl); +void E_Notifyc(char c, int lvl); + +#ifdef DEBUG_USB_HOST +#define Notify E_Notify +#define NotifyStr E_NotifyStr +#define Notifyc E_Notifyc +void NotifyFailGetDevDescr(uint8_t reason); +void NotifyFailSetDevTblEntry(uint8_t reason); +void NotifyFailGetConfDescr(uint8_t reason); +void NotifyFailSetConfDescr(uint8_t reason); +void NotifyFailGetDevDescr(void); +void NotifyFailSetDevTblEntry(void); +void NotifyFailGetConfDescr(void); +void NotifyFailSetConfDescr(void); +void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID); +void NotifyFail(uint8_t rcode); +#else +#define Notify(...) ((void)0) +#define NotifyStr(...) ((void)0) +#define Notifyc(...) ((void)0) +#define NotifyFailGetDevDescr(...) ((void)0) +#define NotifyFailSetDevTblEntry(...) ((void)0) +#define NotifyFailGetConfDescr(...) ((void)0) +#define NotifyFailGetDevDescr(...) ((void)0) +#define NotifyFailSetDevTblEntry(...) ((void)0) +#define NotifyFailGetConfDescr(...) ((void)0) +#define NotifyFailSetConfDescr(...) ((void)0) +#define NotifyFailUnknownDevice(...) ((void)0) +#define NotifyFail(...) ((void)0) +#endif + +template +void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) { +#ifdef DEBUG_USB_HOST + Notify(msg, level); + Notify(PSTR(": "), level); + D_PrintHex (rcode, level); + Notify(PSTR("\r\n"), level); +#endif +} + +template +void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) { +#ifdef DEBUG_USB_HOST + Notify(msg, 0x80); + Notify(PSTR(": "), 0x80); + D_PrintHex (rcode, 0x80); + Notify(PSTR("\r\n"), 0x80); +#endif +} + +#endif // __MESSAGE_H__ diff --git a/Marlin/usb-flashdrive/lib/parsetools.cpp b/Marlin/usb-flashdrive/lib/parsetools.cpp new file mode 100644 index 000000000..74a861059 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/parsetools.cpp @@ -0,0 +1,67 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#include "Usb.h" + +bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) { + if(!pBuf) { + Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80); + return false; + } + for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++) + pBuf[valueSize - countDown] = (**pp); + + if(countDown) + return false; + + countDown = valueSize; + return true; +} + +bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) { + switch(nStage) { + case 0: + pBuf->valueSize = lenSize; + theParser.Initialize(pBuf); + nStage = 1; + + case 1: + if(!theParser.Parse(pp, pcntdn)) + return false; + + arLen = 0; + arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue)); + arLenCntdn = arLen; + nStage = 2; + + case 2: + pBuf->valueSize = valSize; + theParser.Initialize(pBuf); + nStage = 3; + + case 3: + for(; arLenCntdn; arLenCntdn--) { + if(!theParser.Parse(pp, pcntdn)) + return false; + + if(pf) + pf(pBuf, (arLen - arLenCntdn), me); + } + + nStage = 0; + } + return true; +} diff --git a/Marlin/usb-flashdrive/lib/parsetools.h b/Marlin/usb-flashdrive/lib/parsetools.h new file mode 100644 index 000000000..66e9531c3 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/parsetools.h @@ -0,0 +1,140 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(__PARSETOOLS_H__) +#error "Never include parsetools.h directly; include Usb.h instead" +#else +#define __PARSETOOLS_H__ + +struct MultiValueBuffer { + uint8_t valueSize; + void *pValue; +} __attribute__((packed)); + +class MultiByteValueParser { + uint8_t * pBuf; + uint8_t countDown; + uint8_t valueSize; + +public: + + MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) { + }; + + const uint8_t* GetBuffer() { + return pBuf; + }; + + void Initialize(MultiValueBuffer * const pbuf) { + pBuf = (uint8_t*)pbuf->pValue; + countDown = valueSize = pbuf->valueSize; + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn); +}; + +class ByteSkipper { + uint8_t *pBuf; + uint8_t nStage; + uint16_t countDown; + +public: + + ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) { + }; + + void Initialize(MultiValueBuffer *pbuf) { + pBuf = (uint8_t*)pbuf->pValue; + countDown = 0; + }; + + bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) { + switch(nStage) { + case 0: + countDown = bytes_to_skip; + nStage++; + case 1: + for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--); + + if(!countDown) + nStage = 0; + }; + return (!countDown); + }; +}; + +// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser +typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me); + +class PTPListParser { +public: + + enum ParseMode { + modeArray, modeRange/*, modeEnum*/ + }; + +private: + uint8_t nStage; + uint8_t enStage; + + uint32_t arLen; + uint32_t arLenCntdn; + + uint8_t lenSize; // size of the array length field in bytes + uint8_t valSize; // size of the array element in bytes + + MultiValueBuffer *pBuf; + + // The only parser for both size and array element parsing + MultiByteValueParser theParser; + + uint8_t /*ParseMode*/ prsMode; + +public: + + PTPListParser() : + nStage(0), + enStage(0), + arLen(0), + arLenCntdn(0), + lenSize(0), + valSize(0), + pBuf(NULL), + prsMode(modeArray) { + }; + + void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) { + pBuf = p; + lenSize = len_size; + valSize = val_size; + prsMode = mode; + + if(prsMode == modeRange) { + arLenCntdn = arLen = 3; + nStage = 2; + } else { + arLenCntdn = arLen = 0; + nStage = 0; + } + enStage = 0; + theParser.Initialize(p); + }; + + bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL); +}; + +#endif // __PARSETOOLS_H__ diff --git a/Marlin/usb-flashdrive/lib/printhex.h b/Marlin/usb-flashdrive/lib/printhex.h new file mode 100644 index 000000000..66c15a183 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/printhex.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(__PRINTHEX_H__) +#error "Never include printhex.h directly; include Usb.h instead" +#else +#define __PRINTHEX_H__ + +void E_Notifyc(char c, int lvl); + +template +void PrintHex(T val, int lvl) { + int num_nibbles = sizeof (T) * 2; + + do { + char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if(v > 57) v += 7; + E_Notifyc(v, lvl); + } while(--num_nibbles); +} + +template +void PrintBin(T val, int lvl) { + for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1) + if(val & mask) + E_Notifyc('1', lvl); + else + E_Notifyc('0', lvl); +} + +template +void SerialPrintHex(T val) { + int num_nibbles = sizeof (T) * 2; + + do { + char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if(v > 57) v += 7; + USB_HOST_SERIAL.print(v); + } while(--num_nibbles); +} + +/*template +void PrintHex2(Print *prn, T val) { + T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2)); + + while(mask > 1) { + if(val < mask) + prn->print("0"); + + mask >>= 4; + } + prn->print((T)val, HEX); +}*/ + +template void D_PrintHex(T val, int lvl) { +#ifdef DEBUG_USB_HOST + PrintHex (val, lvl); +#endif +} + +template +void D_PrintBin(T val, int lvl) { +#ifdef DEBUG_USB_HOST + PrintBin (val, lvl); +#endif +} + + + +#endif // __PRINTHEX_H__ diff --git a/Marlin/usb-flashdrive/lib/settings.h b/Marlin/usb-flashdrive/lib/settings.h new file mode 100644 index 000000000..83bea95be --- /dev/null +++ b/Marlin/usb-flashdrive/lib/settings.h @@ -0,0 +1,143 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#ifndef USB_HOST_SHIELD_SETTINGS_H +#define USB_HOST_SHIELD_SETTINGS_H +#include "macros.h" +//////////////////////////////////////////////////////////////////////////////// +/* Added by Bill Greiman to speed up mass storage initialization with USB + * flash drives and simple USB hard drives. + * Disable this by defining DELAY(x) to be delay(x). + */ +#define DELAY(x) if((x) < 200)delay(x) +/* Almost all USB flash drives and simple USB hard drives fail the write + * protect test and add 20 - 30 seconds to USB init. Set SKIP_WRITE_PROTECT + * to nonzero to skip the test and assume the drive is writable. + */ +#define SKIP_WRITE_PROTECT 1 +//////////////////////////////////////////////////////////////////////////////// +// DEBUGGING +//////////////////////////////////////////////////////////////////////////////// + +/* Set this to 1 to activate serial debugging */ +#define ENABLE_UHS_DEBUGGING 0 + +/* This can be used to select which serial port to use for debugging if + * multiple serial ports are available. + * For example Serial3. + */ +#ifndef USB_HOST_SERIAL +#define USB_HOST_SERIAL Serial +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Manual board activation +//////////////////////////////////////////////////////////////////////////////// + +/* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */ +#define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually + +/* Set this to 1 if you are using a Black Widdow */ +#define USE_UHS_BLACK_WIDDOW 0 + +/* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */ +#define USE_XMEM_SPI_LOCK 0 + +//////////////////////////////////////////////////////////////////////////////// +// MASS STORAGE +//////////////////////////////////////////////////////////////////////////////// +// <<<<<<<<<<<<<<<< IMPORTANT >>>>>>>>>>>>>>> +// Set this to 1 to support single LUN devices, and save RAM. -- I.E. thumb drives. +// Each LUN needs ~13 bytes to be able to track the state of each unit. +#ifndef MASS_MAX_SUPPORTED_LUN +#define MASS_MAX_SUPPORTED_LUN 1 ///// 8 WHG +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Set to 1 to use the faster spi4teensy3 driver. +//////////////////////////////////////////////////////////////////////////////// +#ifndef USE_SPI4TEENSY3 +#define USE_SPI4TEENSY3 1 +#endif + +//////////////////////////////////////////////////////////////////////////////// +// AUTOMATIC Settings +//////////////////////////////////////////////////////////////////////////////// + +// No user serviceable parts below this line. +// DO NOT change anything below here unless you are a developer! + +#if defined(ARDUINO) && ARDUINO >=100 +#include +#else +#include +#include +#include +#include +#define F(str) (str) +#endif + +#if defined(__GNUC__) && defined(__AVR__) +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif +#if GCC_VERSION < 40602 // Test for GCC < 4.6.2 +#ifdef PROGMEM +#undef PROGMEM +#define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734#c4 +#ifdef PSTR +#undef PSTR +#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) // Copied from pgmspace.h in avr-libc source +#endif +#endif +#endif +#endif + +#if !defined(DEBUG_USB_HOST) && ENABLE_UHS_DEBUGGING +#define DEBUG_USB_HOST +#endif + +// To use some other locking (e.g. freertos), +// define XMEM_ACQUIRE_SPI and XMEM_RELEASE_SPI to point to your lock and unlock. +// NOTE: NO argument is passed. You have to do this within your routine for +// whatever you are using to lock and unlock. +#if !defined(XMEM_ACQUIRE_SPI) +#if USE_XMEM_SPI_LOCK || defined(USE_MULTIPLE_APP_API) +#include +#else +#define XMEM_ACQUIRE_SPI() (void(0)) +#define XMEM_RELEASE_SPI() (void(0)) +#endif +#endif + +#if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP) +#include +#else +#define EXT_RAM 0 +#endif + +#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) +#define USING_SPI4TEENSY3 USE_SPI4TEENSY3 +#else +#define USING_SPI4TEENSY3 0 +#endif + +#if (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) +#include // Use the Arduino SPI library for the Arduino Due and RedBearLab nRF51822 +#endif + +#endif /* SETTINGS_H */ diff --git a/Marlin/usb-flashdrive/lib/usb_ch9.h b/Marlin/usb-flashdrive/lib/usb_ch9.h new file mode 100644 index 000000000..aded2152c --- /dev/null +++ b/Marlin/usb-flashdrive/lib/usb_ch9.h @@ -0,0 +1,166 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + +#if !defined(_usb_h_) || defined(_ch9_h_) +#error "Never include usb_ch9.h directly; include Usb.h instead" +#else + +/* USB chapter 9 structures */ +#define _ch9_h_ + +/* Misc.USB constants */ +#define DEV_DESCR_LEN 18 //device descriptor length +#define CONF_DESCR_LEN 9 //configuration descriptor length +#define INTR_DESCR_LEN 9 //interface descriptor length +#define EP_DESCR_LEN 7 //endpoint descriptor length + +/* Standard Device Requests */ + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +/* Setup Data Constants */ + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +/* USB descriptors */ + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +#define HID_DESCRIPTOR_HID 0x21 + + + +/* OTG SET FEATURE Constants */ +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +/* USB Endpoint Transfer Types */ +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. +#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes + + +/* Standard Feature Selectors for CLEAR_FEATURE Requests */ +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + +/* descriptor data structures */ + +/* Device descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} __attribute__((packed)) USB_DEVICE_DESCRIPTOR; + +/* Configuration descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR; + +/* Interface descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR; + +/* Endpoint descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR; + +/* HID descriptor */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; // HID class specification release + uint8_t bCountryCode; + uint8_t bNumDescriptors; // Number of additional class specific descriptors + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) USB_HID_DESCRIPTOR; + +typedef struct { + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE; + +#endif // _ch9_h_ diff --git a/Marlin/usb-flashdrive/lib/usbhost.h b/Marlin/usb-flashdrive/lib/usbhost.h new file mode 100644 index 000000000..c19d63e56 --- /dev/null +++ b/Marlin/usb-flashdrive/lib/usbhost.h @@ -0,0 +1,462 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +/* MAX3421E-based USB Host Library header file */ + + +#if !defined(_usb_h_) || defined(_USBHOST_H_) +#error "Never include usbhost.h directly; include Usb.h instead" +#else +#define _USBHOST_H_ + +#if USING_SPI4TEENSY3 +#include +#include +#endif + + +/* SPI initialization */ +template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi { +public: +#if USING_SPI4TEENSY3 + static void init() { + // spi4teensy3 inits everything for us, except /SS + // CLK, MOSI and MISO are hard coded for now. + // spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0 + spi4teensy3::init(); // full speed, cpol 0, cpha 0 + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + } +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + static void init() { + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + SPI.begin(); + SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz + } +#elif defined(RBL_NRF51822) + static void init() { + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + SPI.begin(); + // SPI.setFrequency(SPI_FREQUENCY_8M); + } +#else + static void init() { + //uint8_t tmp; + SPI_CLK::SetDirWrite(); + SPI_MOSI::SetDirWrite(); + SPI_MISO::SetDirRead(); + SPI_SS::SetDirWrite(); + /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ + SPCR = 0x50; + SPSR = 0x01; // 0x01 + /**/ + //tmp = SPSR; + //tmp = SPDR; + } +#endif +}; + +/* SPI pin definitions. see avrpins.h */ +#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi; +#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; +#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) +typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; +#elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) +typedef SPi< P13, P11, P12, P10 > spi; +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) +typedef SPi< P76, P75, P74, P10 > spi; +#elif defined(RBL_NRF51822) +typedef SPi< P16, P18, P17, P10 > spi; +#else +#error "No SPI entry in usbhost.h" +#endif + +typedef enum { + vbus_on = 0, + vbus_off = GPX_VBDET +} VBUS_t; + +template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ { + static uint8_t vbusState; + +public: + MAX3421e(); + void regWr(uint8_t reg, uint8_t data); + uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p); + void gpioWr(uint8_t data); + uint8_t regRd(uint8_t reg); + uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p); + uint8_t gpioRd(); + uint16_t reset(); + int8_t Init(); + int8_t Init(int mseconds); + + void vbusPower(VBUS_t state) { + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state)); + } + + uint8_t getVbusState(void) { + return vbusState; + }; + void busprobe(); + uint8_t GpxHandler(); + uint8_t IntHandler(); + uint8_t Task(); +}; + +template< typename SPI_SS, typename INTR > + uint8_t MAX3421e< SPI_SS, INTR >::vbusState = 0; + +/* constructor */ +template< typename SPI_SS, typename INTR > +MAX3421e< SPI_SS, INTR >::MAX3421e() { + // Leaving ADK hardware setup in here, for now. This really belongs with the other parts. +#ifdef BOARD_MEGA_ADK + // For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH + P55::SetDirWrite(); + P55::Set(); +#endif +}; + +/* write single byte into MAX3421 register */ +template< typename SPI_SS, typename INTR > +void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { + XMEM_ACQUIRE_SPI(); + SPI_SS::Clear(); +#if USING_SPI4TEENSY3 + uint8_t c[2]; + c[0] = reg | 0x02; + c[1] = data; + spi4teensy3::send(c, 2); +#elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) + SPI.transfer(reg | 0x02); + SPI.transfer(data); +#else + SPDR = (reg | 0x02); + while(!(SPSR & (1 << SPIF))); + SPDR = data; + while(!(SPSR & (1 << SPIF))); +#endif + SPI_SS::Set(); + XMEM_RELEASE_SPI(); + return; +}; +/* multiple-byte write */ + +/* returns a pointer to memory position after last written */ +template< typename SPI_SS, typename INTR > +uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + XMEM_ACQUIRE_SPI(); + SPI_SS::Clear(); +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg | 0x02); + spi4teensy3::send(data_p, nbytes); + data_p += nbytes; +#elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) + SPI.transfer(reg | 0x02); + while(nbytes) { + SPI.transfer(*data_p); + nbytes--; + data_p++; // advance data pointer + } +#else + SPDR = (reg | 0x02); //set WR bit and send register number + while(nbytes) { + while(!(SPSR & (1 << SPIF))); //check if previous byte was sent + SPDR = (*data_p); // send next data byte + nbytes--; + data_p++; // advance data pointer + } + while(!(SPSR & (1 << SPIF))); +#endif + SPI_SS::Set(); + XMEM_RELEASE_SPI(); + return ( data_p); +} +/* GPIO write */ +/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */ + +/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */ +template< typename SPI_SS, typename INTR > +void MAX3421e< SPI_SS, INTR >::gpioWr(uint8_t data) { + regWr(rIOPINS1, data); + data >>= 4; + regWr(rIOPINS2, data); + return; +} + +/* single host register read */ +template< typename SPI_SS, typename INTR > +uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { + XMEM_ACQUIRE_SPI(); + SPI_SS::Clear(); +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg); + uint8_t rv = spi4teensy3::receive(); + SPI_SS::Set(); +#elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) + SPI.transfer(reg); + uint8_t rv = SPI.transfer(0); + SPI_SS::Set(); +#else + SPDR = reg; + while(!(SPSR & (1 << SPIF))); + SPDR = 0; //send empty byte + while(!(SPSR & (1 << SPIF))); + SPI_SS::Set(); + uint8_t rv = SPDR; +#endif + XMEM_RELEASE_SPI(); + return (rv); +} +/* multiple-byte register read */ + +/* returns a pointer to a memory position after last read */ +template< typename SPI_SS, typename INTR > +uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + XMEM_ACQUIRE_SPI(); + SPI_SS::Clear(); +#if USING_SPI4TEENSY3 + spi4teensy3::send(reg); + spi4teensy3::receive(data_p, nbytes); + data_p += nbytes; +#elif (defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(RBL_NRF51822) + SPI.transfer(reg); + while(nbytes) { + *data_p++ = SPI.transfer(0); + nbytes--; + } +#else + SPDR = reg; + while(!(SPSR & (1 << SPIF))); //wait + while(nbytes) { + SPDR = 0; //send empty byte + nbytes--; + while(!(SPSR & (1 << SPIF))); +#if 0 + { + *data_p = SPDR; + printf("%2.2x ", *data_p); + } + data_p++; + } + printf("\r\n"); +#else + *data_p++ = SPDR; + } +#endif +#endif + SPI_SS::Set(); + XMEM_RELEASE_SPI(); + return ( data_p); +} +/* GPIO read. See gpioWr for explanation */ + +/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ +template< typename SPI_SS, typename INTR > +uint8_t MAX3421e< SPI_SS, INTR >::gpioRd() { + uint8_t gpin = 0; + gpin = regRd(rIOPINS2); //pins 4-7 + gpin &= 0xf0; //clean lower nibble + gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation. + return ( gpin); +} + +/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset + or zero if PLL haven't stabilized in 65535 cycles */ +template< typename SPI_SS, typename INTR > +uint16_t MAX3421e< SPI_SS, INTR >::reset() { + uint16_t i = 0; + regWr(rUSBCTL, bmCHIPRES); + regWr(rUSBCTL, 0x00); + while(++i) { + if((regRd(rUSBIRQ) & bmOSCOKIRQ)) { + break; + } + } + return ( i); +} + +/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ +template< typename SPI_SS, typename INTR > +int8_t MAX3421e< SPI_SS, INTR >::Init() { + XMEM_ACQUIRE_SPI(); + // Moved here. + // you really should not init hardware in the constructor when it involves locks. + // Also avoids the vbus flicker issue confusing some devices. + /* pin and peripheral setup */ + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + spi::init(); + INTR::SetDirRead(); + XMEM_RELEASE_SPI(); + /* MAX3421E - full-duplex SPI, level interrupt */ + // GPX pin on. Moved here, otherwise we flicker the vbus. + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); + + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time + return ( -1); + } + + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host + + regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection + + /* check if device is connected */ + regWr(rHCTL, bmSAMPLEBUS); // sample USB bus + while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish + + busprobe(); //check if anything is connected + + regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt + regWr(rCPUCTL, 0x01); //enable interrupt pin + + return ( 0); +} + +/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ +template< typename SPI_SS, typename INTR > +int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) { + XMEM_ACQUIRE_SPI(); + // Moved here. + // you really should not init hardware in the constructor when it involves locks. + // Also avoids the vbus flicker issue confusing some devices. + /* pin and peripheral setup */ + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + spi::init(); + INTR::SetDirRead(); + XMEM_RELEASE_SPI(); + /* MAX3421E - full-duplex SPI, level interrupt, vbus off */ + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET)); + + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time + return ( -1); + } + + // Delay a minimum of 1 second to ensure any capacitors are drained. + // 1 second is required to make sure we do not smoke a Microdrive! + if(mseconds < 1000) mseconds = 1000; + delay(mseconds); + + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host + + regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection + + /* check if device is connected */ + regWr(rHCTL, bmSAMPLEBUS); // sample USB bus + while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish + + busprobe(); //check if anything is connected + + regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt + regWr(rCPUCTL, 0x01); //enable interrupt pin + + // GPX pin on. This is done here so that busprobe will fail if we have a switch connected. + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); + + return ( 0); +} + +/* probe bus to determine device presence and speed and switch host to this speed */ +template< typename SPI_SS, typename INTR > +void MAX3421e< SPI_SS, INTR >::busprobe() { + uint8_t bus_sample; + bus_sample = regRd(rHRSL); //Get J,K status + bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte + switch(bus_sample) { //start full-speed or low-speed host + case( bmJSTATUS): + if((regRd(rMODE) & bmLOWSPEED) == 0) { + regWr(rMODE, MODE_FS_HOST); //start full-speed host + vbusState = FSHOST; + } else { + regWr(rMODE, MODE_LS_HOST); //start low-speed host + vbusState = LSHOST; + } + break; + case( bmKSTATUS): + if((regRd(rMODE) & bmLOWSPEED) == 0) { + regWr(rMODE, MODE_LS_HOST); //start low-speed host + vbusState = LSHOST; + } else { + regWr(rMODE, MODE_FS_HOST); //start full-speed host + vbusState = FSHOST; + } + break; + case( bmSE1): //illegal state + vbusState = SE1; + break; + case( bmSE0): //disconnected state + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ); + vbusState = SE0; + break; + }//end switch( bus_sample ) +} + +/* MAX3421 state change task and interrupt handler */ +template< typename SPI_SS, typename INTR > +uint8_t MAX3421e< SPI_SS, INTR >::Task(void) { + uint8_t rcode = 0; + uint8_t pinvalue; + //USB_HOST_SERIAL.print("Vbus state: "); + //USB_HOST_SERIAL.println( vbusState, HEX ); + pinvalue = INTR::IsSet(); //Read(); + //pinvalue = digitalRead( MAX_INT ); + if(pinvalue == 0) { + rcode = IntHandler(); + } + // pinvalue = digitalRead( MAX_GPX ); + // if( pinvalue == LOW ) { + // GpxHandler(); + // } + // usbSM(); //USB state machine + return ( rcode); +} + +template< typename SPI_SS, typename INTR > +uint8_t MAX3421e< SPI_SS, INTR >::IntHandler() { + uint8_t HIRQ; + uint8_t HIRQ_sendback = 0x00; + HIRQ = regRd(rHIRQ); //determine interrupt source + //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler + // HIRQ_sendback |= bmFRAMEIRQ; + //}//end FRAMEIRQ handling + if(HIRQ & bmCONDETIRQ) { + busprobe(); + HIRQ_sendback |= bmCONDETIRQ; + } + /* End HIRQ interrupts handling, clear serviced IRQs */ + regWr(rHIRQ, HIRQ_sendback); + return ( HIRQ_sendback); +} +//template< typename SPI_SS, typename INTR > +//uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler() +//{ +// uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register +//// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload +//// vbusPwr( OFF ); //attempt powercycle +//// delay( 1000 ); +//// vbusPwr( ON ); +//// regWr( rGPINIRQ, bmGPINIRQ7 ); +//// } +// return( GPINIRQ ); +//} + +#endif //_USBHOST_H_