diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 3963d8c7d..dcc8539ba 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -138,7 +138,7 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { Ion::LED::updateColorWithPlugAndCharge(); } if (event == Ion::Events::USBEnumeration) { - if (Ion::USB::isPlugged()) { + if (Ion::USB::isPlugged() && GlobalPreferences::sharedGlobalPreferences()->getDfuLevel() != 3) { App::Snapshot * activeSnapshot = (s_activeApp == nullptr ? appSnapshotAtIndex(0) : s_activeApp->snapshot()); /* Just after a software update, the battery timer does not have time to * fire before the calculator enters DFU mode. As the DFU mode blocks the @@ -147,7 +147,9 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { * pictogram. */ updateBatteryState(); if (switchTo(usbConnectedAppSnapshot())) { - Ion::USB::DFU(); + Ion::USB::DFU(true, GlobalPreferences::sharedGlobalPreferences()->dfuStatus(), GlobalPreferences::sharedGlobalPreferences()->getDfuLevel()); + GlobalPreferences::sharedGlobalPreferences()->dfuResetStep(); + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(false); // Update LED when exiting DFU mode Ion::LED::updateColorWithPlugAndCharge(); bool switched = switchTo(activeSnapshot); diff --git a/apps/global_preferences.h b/apps/global_preferences.h index 641e48792..5345bd21c 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -30,6 +30,15 @@ public: void setTempExamMode(ExamMode examMode); bool showPopUp() const { return m_showPopUp; } void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; } + bool dfuStatus() const { return m_dfuUnlocked; } + void setDfuStatus(bool status) { m_dfuUnlocked=status; } + int dfuCurrentStep() const { return m_dfuStep; } + void dfuIncreaseStep() { m_dfuStep++; } + void dfuResetStep() { m_dfuStep = 0; } + int getDfuLevel() const { return m_dfuProtectLevel; } + void setDfuLevel(int level) { m_dfuProtectLevel = level; } + bool showDfuDeacAlert() const { return m_showDeacAlert; } + void setDfuDeacAlert(bool value) { m_showDeacAlert = value; } bool autocomplete() const { return m_autoComplete; } void setAutocomplete(bool autocomple) { m_autoComplete = autocomple; } int brightnessLevel() const { return m_brightnessLevel; } @@ -37,6 +46,7 @@ public: const KDFont * font() const { return m_font; } void setFont(const KDFont * font) { m_font = font; } constexpr static int NumberOfBrightnessStates = 15; + constexpr static int DfuUnlockStep = 3; private: static_assert(I18n::NumberOfLanguages > 0, "I18n::NumberOfLanguages is not superior to 0"); // There should already have been an error when processing an empty EPSILON_I18N flag static_assert(I18n::NumberOfCountries > 0, "I18n::NumberOfCountries is not superior to 0"); // There should already have been an error when processing an empty EPSILON_COUNTRIES flag @@ -46,6 +56,10 @@ private: m_examMode(ExamMode::Unknown), m_tempExamMode(ExamMode::Standard), m_showPopUp(true), + m_dfuUnlocked(false), + m_dfuStep(0), + m_dfuProtectLevel(0), + m_showDeacAlert(true), m_autoComplete(true), m_brightnessLevel(Ion::Backlight::MaxBrightness), m_font(KDFont::LargeFont) {} @@ -56,6 +70,10 @@ private: mutable ExamMode m_examMode; mutable ExamMode m_tempExamMode; bool m_showPopUp; + bool m_dfuUnlocked; + int m_dfuStep; + int m_dfuProtectLevel; // 0: default; 1: OmegaMode; 2: Paranoid; 3: Paranoid++ + bool m_showDeacAlert; bool m_autoComplete; int m_brightnessLevel; const KDFont * m_font; diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index a0fc91420..5b9d53782 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -2,3 +2,5 @@ Apps = "Anwendungen" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Diese Anwendung ist im" ForbidenAppInExamMode2 = "Prüfungsmodus nicht erlaubt." +DfuWarning1 = "DFU-Schutzwarnung" +DfuWarning2 = "Mehr Informationen: bit.ly/upsiDfu" diff --git a/apps/home/base.en.i18n b/apps/home/base.en.i18n index 3468cca66..81e3e0914 100644 --- a/apps/home/base.en.i18n +++ b/apps/home/base.en.i18n @@ -2,3 +2,5 @@ Apps = "Applications" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "This application is" ForbidenAppInExamMode2 = "forbidden in exam mode" +DfuWarning1 = "DFU Protection Warning" +DfuWarning2 = "More informations: bit.ly/upsiDfu" diff --git a/apps/home/base.es.i18n b/apps/home/base.es.i18n index 3c262497c..12bcd7288 100644 --- a/apps/home/base.es.i18n +++ b/apps/home/base.es.i18n @@ -2,3 +2,5 @@ Apps = "Aplicaciones" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Esta aplicación está prohibida" ForbidenAppInExamMode2 = "en el modo de examen" +DfuWarning1 = "Advertencia de protección DFU" +DfuWarning2 = "Más información: bit.ly/upsiDfu" diff --git a/apps/home/base.fr.i18n b/apps/home/base.fr.i18n index 4b4ab02dd..aba1412ef 100644 --- a/apps/home/base.fr.i18n +++ b/apps/home/base.fr.i18n @@ -2,3 +2,5 @@ Apps = "Applications" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Cette application n'est" ForbidenAppInExamMode2 = "pas autorisée en mode examen." +DfuWarning1 = "Alerte protection DFU" +DfuWarning2 = "Plus d'infos: bit.ly/upsiDfu" diff --git a/apps/home/base.hu.i18n b/apps/home/base.hu.i18n index d526193eb..2bcc9fd6e 100644 --- a/apps/home/base.hu.i18n +++ b/apps/home/base.hu.i18n @@ -2,3 +2,5 @@ Apps = "Alkalmazások" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Ez az alkalmazás" ForbidenAppInExamMode2 = "tilos vizsga módban" +DfuWarning1 = "DFU védelmi figyelmeztetés" +DfuWarning2 = "További információk: bit.ly/upsiDfu" diff --git a/apps/home/base.it.i18n b/apps/home/base.it.i18n index 4bd26ced3..09ae09d43 100644 --- a/apps/home/base.it.i18n +++ b/apps/home/base.it.i18n @@ -2,3 +2,5 @@ Apps = "Applicazioni" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Questa applicazione è" ForbidenAppInExamMode2 = "proibita nella modalità d'esame" +DfuWarning1 = "Avviso protezione DFU" +DfuWarning2 = "Più informazioni: bit.ly/upsiDfu" diff --git a/apps/home/base.nl.i18n b/apps/home/base.nl.i18n index 496e8d6a3..9037187aa 100644 --- a/apps/home/base.nl.i18n +++ b/apps/home/base.nl.i18n @@ -2,3 +2,5 @@ Apps = "Applicaties" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Deze applicatie is" ForbidenAppInExamMode2 = "uitgesloten in examenstand" +DfuWarning1 = "DFU-beveiligingswaarschuwing" +DfuWarning2 = "Meer informatie: bit.ly/upsiDfu" diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n index 6c074aa86..bf1e307e4 100644 --- a/apps/home/base.pt.i18n +++ b/apps/home/base.pt.i18n @@ -2,3 +2,5 @@ Apps = "Aplicações" AppsCapital = "UPSILON" ForbidenAppInExamMode1 = "Esta aplicação é" ForbidenAppInExamMode2 = "proibida no Modo de Exame" +DfuWarning1 = "Aviso de proteção DFU" +DfuWarning2 = "Mais informações: bit.ly/upsiDfu" diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index df725f10f..8f02cc5b8 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -87,9 +87,33 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc } bool Controller::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Six) { + GlobalPreferences::sharedGlobalPreferences()->dfuIncreaseStep(); + if (GlobalPreferences::sharedGlobalPreferences()->dfuCurrentStep() >= GlobalPreferences::DfuUnlockStep && !GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + Ion::LED::setColor(KDColorPurple); + Ion::LED::setBlinking(500, 0.5f); + } + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(true); + App::app()->displayWarning(I18n::Message::DfuWarning1, I18n::Message::DfuWarning2); + return true; + } else if (GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + Ion::LED::setColor(KDColorBlack); + } + GlobalPreferences::sharedGlobalPreferences()->dfuResetStep(); + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(false); + } + } if (event == Ion::Events::OK || event == Ion::Events::EXE) { AppsContainer * container = AppsContainer::sharedAppsContainer(); + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + Ion::LED::setColor(KDColorBlack); + } + GlobalPreferences::sharedGlobalPreferences()->dfuResetStep(); + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(false); + int index = selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1; #ifdef HOME_DISPLAY_EXTERNALS if (index >= container->numberOfApps()) { diff --git a/apps/on_boarding/logo_icon.png b/apps/on_boarding/logo_icon.png index 0dc9c6174..bfec4d823 100644 Binary files a/apps/on_boarding/logo_icon.png and b/apps/on_boarding/logo_icon.png differ diff --git a/apps/settings/Makefile b/apps/settings/Makefile index e0598ec4e..ec6684d1a 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -25,6 +25,8 @@ app_settings_src = $(addprefix apps/settings/,\ sub_menu/contributors_controller.cpp \ sub_menu/math_options_controller.cpp \ sub_menu/selectable_view_with_messages.cpp \ + sub_menu/usb_info_controller.cpp \ + sub_menu/usb_protection_level_controller.cpp \ ) SFLAGS += -DOMEGA_STATE="$(OMEGA_STATE)" diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 01145af4e..e28bab689 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -15,6 +15,8 @@ constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMess constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; constexpr SettingsMessageTree s_modelDateTimeChildren[3] = {SettingsMessageTree(I18n::Message::ActivateClock), SettingsMessageTree(I18n::Message::Date), SettingsMessageTree(I18n::Message::Time)}; constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::Message::SymbolMultiplicationCross),SettingsMessageTree(I18n::Message::SymbolMultiplicationMiddleDot),SettingsMessageTree(I18n::Message::SymbolMultiplicationStar),SettingsMessageTree(I18n::Message::SymbolMultiplicationAutoSymbol)}; +constexpr SettingsMessageTree s_usbLevelSelector[3] = {SettingsMessageTree(I18n::Message::USBDefaultLevel), SettingsMessageTree(I18n::Message::USBLowLevel), SettingsMessageTree(I18n::Message::USBParanoidLevel)}; // , SettingsMessageTree(I18n::Message::USBMegaParanoidLevel) +constexpr SettingsMessageTree s_usbSteps[2] = {SettingsMessageTree(I18n::Message::USBProtection), SettingsMessageTree(I18n::Message::USBLevelProtect, s_usbLevelSelector)}; constexpr SettingsMessageTree s_symbolFunctionChildren[3] = {SettingsMessageTree(I18n::Message::SymbolDefaultFunction), SettingsMessageTree(I18n::Message::SymbolArgDefaultFunction), SettingsMessageTree(I18n::Message::SymbolArgFunction)}; constexpr SettingsMessageTree s_modelMathOptionsChildren[6] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren), SettingsMessageTree(I18n::Message::SymbolFunction, s_symbolFunctionChildren), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren)}; constexpr SettingsMessageTree s_accessibilityChildren[6] = {SettingsMessageTree(I18n::Message::AccessibilityInvertColors), SettingsMessageTree(I18n::Message::AccessibilityMagnify),SettingsMessageTree(I18n::Message::AccessibilityGamma),SettingsMessageTree(I18n::Message::AccessibilityGammaRed),SettingsMessageTree(I18n::Message::AccessibilityGammaGreen),SettingsMessageTree(I18n::Message::AccessibilityGammaBlue)}; @@ -41,7 +43,8 @@ MainController::MainController(Responder * parentResponder, InputEventHandlerDel m_codeOptionsController(this), m_examModeController(this), m_aboutController(this), - m_preferencesController(this) + m_preferencesController(this), + m_usbInfoController(this) { for (int i = 0; i < k_numberOfSimpleChevronCells; i++) { m_cells[i].setMessageFont(KDFont::LargeFont); @@ -111,6 +114,8 @@ bool MainController::handleEvent(Ion::Events::Event event) { subController = &m_dateTimeController; } else if (title == I18n::Message::MathOptions) { subController = &m_mathOptionsController; + } else if (title == I18n::Message::UsbSetting) { + subController = &m_usbInfoController; } else if (title == I18n::Message::CodeApp) { subController = &m_codeOptionsController; } else { diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index c254fb8d1..2d7cec4b1 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -12,6 +12,7 @@ #include "sub_menu/localization_controller.h" #include "sub_menu/math_options_controller.h" #include "sub_menu/preferences_controller.h" +#include "sub_menu/usb_info_controller.h" namespace Settings { @@ -28,6 +29,8 @@ extern const Shared::SettingsMessageTree s_modelDateTimeChildren[3]; extern const Shared::SettingsMessageTree s_accessibilityChildren[6]; extern const Shared::SettingsMessageTree s_contributorsChildren[23]; extern const Shared::SettingsMessageTree s_modelAboutChildren[9]; +extern const Shared::SettingsMessageTree s_usbLevelSelector[3]; +extern const Shared::SettingsMessageTree s_usbSteps[2]; extern const Shared::SettingsMessageTree s_model; class MainController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource { @@ -76,6 +79,7 @@ private: ExamModeController m_examModeController; AboutController m_aboutController; PreferencesController m_preferencesController; + UsbInfoController m_usbInfoController; }; } diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index 1b5f88143..7c4f4acf3 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -18,6 +18,7 @@ constexpr SettingsMessageTree s_modelMenu[] = #endif SettingsMessageTree(I18n::Message::BetaPopUp), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren), + SettingsMessageTree(I18n::Message::UsbSetting, s_usbSteps), SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren)}; constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu); diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index e3e129051..95c0b571e 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -1,28 +1,30 @@ -#include "main_controller.h" -#include "../exam_mode_configuration.h" #include +#include "../exam_mode_configuration.h" +#include "main_controller.h" + using namespace Shared; namespace Settings { constexpr SettingsMessageTree s_modelMenu[] = - {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren), - SettingsMessageTree(I18n::Message::Brightness), - SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren), - SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::Country), - SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren), + {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren), + SettingsMessageTree(I18n::Message::Brightness), + SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren), + SettingsMessageTree(I18n::Message::Language), + SettingsMessageTree(I18n::Message::Country), + SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren), #ifdef HAS_CODE - SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren), + SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren), #endif - SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren), - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)}; + SettingsMessageTree(I18n::Message::UsbSetting, s_usbSteps), + SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren), + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)}; constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu); I18n::Message MainController::promptMessage() const { - return I18n::Message::Default; + return I18n::Message::Default; } -} +} // namespace Settings diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index acbb08d46..148f5c16d 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -18,6 +18,7 @@ constexpr SettingsMessageTree s_modelMenu[] = #endif SettingsMessageTree(I18n::Message::UpdatePopUp), SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren), + SettingsMessageTree(I18n::Message::UsbSetting, s_usbSteps), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)}; constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu); diff --git a/apps/settings/sub_menu/usb_info_controller.cpp b/apps/settings/sub_menu/usb_info_controller.cpp new file mode 100644 index 000000000..f31bd3f82 --- /dev/null +++ b/apps/settings/sub_menu/usb_info_controller.cpp @@ -0,0 +1,134 @@ +#include "usb_info_controller.h" + +#include +#include +#include +#include +#include + +#include + +#include "../../apps_container.h" +#include "../../global_preferences.h" + +using namespace Poincare; +using namespace Shared; + +namespace Settings { + +UsbInfoController::UsbInfoController(Responder *parentResponder) : GenericSubController(parentResponder), + m_usbprotectlevel(this), + m_dfuLevel(KDFont::LargeFont, KDFont::SmallFont), + m_contentView(&m_selectableTableView) { + for (int i = 0; i < k_maxSwitchCells; i++) { + m_switchCells[i].setMessageFont(KDFont::LargeFont); + //Ancien code au cas ou on souhaite ajouter d'autres éléments dans le menu + // m_cell[i].setMessageFont(KDFont::LargeFont); + // m_cell[i].setAccessoryFont(KDFont::SmallFont); + // m_cell[i].setAccessoryTextColor(Palette::SecondaryText); + } +} + +bool UsbInfoController::handleEvent(Ion::Events::Event event) { + if ((Ion::Events::OK == event || Ion::Events::EXE == event) && selectedRow() == 0) { + if(GlobalPreferences::sharedGlobalPreferences()->showDfuDeacAlert()){ + GlobalPreferences::sharedGlobalPreferences()->setDfuDeacAlert(false); + Container::activeApp()->displayWarning(I18n::Message::USBDeacAlert1, I18n::Message::USBDeacAlert2); + return true; + } + if (!GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + Ion::LED::setColor(KDColorPurple); + Ion::LED::setBlinking(500, 0.5f); + } + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(true); + Container::activeApp()->displayWarning(I18n::Message::DfuWarning1, I18n::Message::DfuWarning2); + } else { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + Ion::LED::setColor(KDColorBlack); + } + GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(false); + } + m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()); + AppsContainer::sharedAppsContainer()->redrawWindow(true); + return true; + } + + if (GlobalPreferences::sharedGlobalPreferences()->dfuStatus() && event != Ion::Events::USBPlug && event != Ion::Events::USBEnumeration) { + Container::activeApp()->displayWarning(I18n::Message::UsbSetting, I18n::Message::USBSettingDeact); + return true; + } + + if ((Ion::Events::OK == event || Ion::Events::EXE == event) && selectedRow() == 1) { + GenericSubController *subController = &m_usbprotectlevel; + subController->setMessageTreeModel(m_messageTreeModel->childAtIndex(1)); + StackViewController *stack = stackController(); + m_lastSelect = selectedRow(); + stack->push(subController); + return true; + } + GlobalPreferences::sharedGlobalPreferences()->setDfuDeacAlert(true); + return GenericSubController::handleEvent(event); +} + +HighlightCell *UsbInfoController::reusableCell(int index, int type) { + assert(type == 2 || type == 1); + if (type == 2) { + assert(index >= 0 && index < k_maxSwitchCells); + return &m_switchCells[index]; + } + return &m_dfuLevel; +} + +int UsbInfoController::reusableCellCount(int type) { + assert(type == 2 || type == 1); + if (type == 2) { + return k_maxSwitchCells; + } + return 1; +} + +void UsbInfoController::willDisplayCellForIndex(HighlightCell *cell, int index) { + GenericSubController::willDisplayCellForIndex(cell, index); + + if (index == 0) { + MessageTableCellWithSwitch *myCell = (MessageTableCellWithSwitch *)cell; + SwitchView *mySwitch = (SwitchView *)myCell->accessoryView(); + mySwitch->setState(!GlobalPreferences::sharedGlobalPreferences()->dfuStatus()); + } else if (index == 1) { + MessageTableCellWithChevronAndMessage *mcell = (MessageTableCellWithChevronAndMessage *)cell; + int currentLevel = GlobalPreferences::sharedGlobalPreferences()->getDfuLevel(); + if (currentLevel == 0) { + // mcell->setSubtitle(I18n::Message::USBDefaultLevel); + mcell->setSubtitle(I18n::Message::USBDefaultLevelDesc); + } else if (currentLevel == 1) { + // mcell->setSubtitle(I18n::Message::USBLowLevel); + mcell->setSubtitle(I18n::Message::USBLowLevelDesc); + } else if (currentLevel == 2) { + // mcell->setSubtitle(I18n::Message::USBParanoidLevel); + mcell->setSubtitle(I18n::Message::USBParanoidLevelDesc); + } else { + // mcell->setSubtitle(I18n::Message::USBMegaParanoidLevel); + mcell->setSubtitle(I18n::Message::USBMegaParanoidLevelDesc); + } + } +} + +int UsbInfoController::typeAtLocation(int i, int j) { + switch (j) { + case 0: + return 2; + default: + return 1; + } +} + +void UsbInfoController::didEnterResponderChain(Responder *previousFirstResponder) { + m_contentView.reload(); + + if (numberOfInfoLines() > 0) { + I18n::Message infoMessages[] = {I18n::Message::USBE16_expl1, I18n::Message::USBE16_expl2, I18n::Message::USBE16_expl3}; + m_contentView.setMessages(infoMessages, numberOfInfoLines()); + } +} +} diff --git a/apps/settings/sub_menu/usb_info_controller.h b/apps/settings/sub_menu/usb_info_controller.h new file mode 100644 index 000000000..1bd602883 --- /dev/null +++ b/apps/settings/sub_menu/usb_info_controller.h @@ -0,0 +1,36 @@ +#ifndef SETTINGS_USB_INFO_CONTROLLER_H +#define SETTINGS_USB_INFO_CONTROLLER_H + +#include "generic_sub_controller.h" +#include "preferences_controller.h" +#include "selectable_view_with_messages.h" +#include "usb_protection_level_controller.h" + +namespace Settings { + +class UsbInfoController : public GenericSubController { + public: + UsbInfoController(Responder* parentResponder); + View* view() override { return &m_contentView; } + bool handleEvent(Ion::Events::Event event) override; + TELEMETRY_ID("UsbInfo"); + void didEnterResponderChain(Responder* previousFirstResponder) override; + + HighlightCell* reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + void willDisplayCellForIndex(HighlightCell* cell, int index) override; + int typeAtLocation(int i, int j) override; + + private: + static constexpr int k_numberOfInfoE16MessageLines = 3; + int numberOfInfoLines() const { return k_numberOfInfoE16MessageLines; }; + static constexpr int k_maxSwitchCells = 1; + MessageTableCellWithSwitch m_switchCells[k_maxSwitchCells]; + UsbProtectionLevelController m_usbprotectlevel; + MessageTableCellWithChevronAndMessage m_dfuLevel; + SelectableViewWithMessages m_contentView; +}; + +} + +#endif diff --git a/apps/settings/sub_menu/usb_protection_level_controller.cpp b/apps/settings/sub_menu/usb_protection_level_controller.cpp new file mode 100644 index 000000000..6959b742a --- /dev/null +++ b/apps/settings/sub_menu/usb_protection_level_controller.cpp @@ -0,0 +1,77 @@ +#include "usb_protection_level_controller.h" + +#include +#include + +#include "../../apps_container.h" +#include "../../global_preferences.h" + +using namespace Poincare; +using namespace Shared; + +namespace Settings { +UsbProtectionLevelController::UsbProtectionLevelController(Responder *parentResponder) : GenericSubController(parentResponder) { + for (int i = 0; i < k_maxNumberOfCells; i++) { + m_cell[i].setMessageFont(KDFont::LargeFont); + m_cell[i].setAccessoryFont(KDFont::SmallFont); + } +} + +bool UsbProtectionLevelController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::OK || event == Ion::Events::EXE) { + for (int i = 0; i < k_maxNumberOfCells; i++) { + m_cell[i].setAccessoryText(""); + } + if (m_messageTreeModel->childAtIndex(selectedRow())->label() == I18n::Message::USBLowLevel) { + GlobalPreferences::sharedGlobalPreferences()->setDfuLevel(1); + } else if (m_messageTreeModel->childAtIndex(selectedRow())->label() == I18n::Message::USBDefaultLevel) { + GlobalPreferences::sharedGlobalPreferences()->setDfuLevel(0); + } else if (m_messageTreeModel->childAtIndex(selectedRow())->label() == I18n::Message::USBParanoidLevel) { + GlobalPreferences::sharedGlobalPreferences()->setDfuLevel(2); + } else if (m_messageTreeModel->childAtIndex(selectedRow())->label() == I18n::Message::USBMegaParanoidLevel) { + GlobalPreferences::sharedGlobalPreferences()->setDfuLevel(3); + } + + StackViewController * stack = stackController(); + stack->pop(); + return true; + } else { + return GenericSubController::handleEvent(event); + } +} + +HighlightCell *UsbProtectionLevelController::reusableCell(int index, int type) { + assert(index >= 0 && index < k_maxNumberOfCells); + return &m_cell[index]; +} + +int UsbProtectionLevelController::reusableCellCount(int type) { + return k_maxNumberOfCells; +} + +void UsbProtectionLevelController::willDisplayCellForIndex(HighlightCell *cell, int index) { + GenericSubController::willDisplayCellForIndex(cell, index); + I18n::Message childLabel = m_messageTreeModel->childAtIndex(index)->label(); + MessageTableCellWithBuffer *messageComp = (MessageTableCellWithBuffer *)cell; + + int currentLevel = GlobalPreferences::sharedGlobalPreferences()->getDfuLevel(); + + if (childLabel == I18n::Message::USBLowLevel && currentLevel == 1) { + // messageComp->setTextColor(Palette::Green); + messageComp->setAccessoryText("√"); + } else if (childLabel == I18n::Message::USBDefaultLevel && currentLevel == 0) { + // messageComp->setTextColor(Palette::Green); + messageComp->setAccessoryText("√"); + } else if (childLabel == I18n::Message::USBParanoidLevel && currentLevel == 2) { + // messageComp->setTextColor(Palette::Green); + messageComp->setAccessoryText("√"); + } else if (childLabel == I18n::Message::USBMegaParanoidLevel && currentLevel == 3) { + // messageComp->setTextColor(Palette::Green); + messageComp->setAccessoryText("√"); + } +} + +int UsbProtectionLevelController::typeAtLocation(int i, int j) { + return 0; +} +} // namespace Settings \ No newline at end of file diff --git a/apps/settings/sub_menu/usb_protection_level_controller.h b/apps/settings/sub_menu/usb_protection_level_controller.h new file mode 100644 index 000000000..bf7d23754 --- /dev/null +++ b/apps/settings/sub_menu/usb_protection_level_controller.h @@ -0,0 +1,24 @@ +#ifndef SETTINGS_USB_PROTECTION_LEVEL_CONTROLLER_H +#define SETTINGS_USB_PROTECTION_LEVEL_CONTROLLER_H + +#include "generic_sub_controller.h" +#include + +namespace Settings { + +class UsbProtectionLevelController : public GenericSubController { +public: + UsbProtectionLevelController(Responder * parentResponder); + bool handleEvent(Ion::Events::Event event) override; + HighlightCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + void willDisplayCellForIndex(HighlightCell * cell, int index) override; + int typeAtLocation(int i, int j) override; +private: + static constexpr int k_maxNumberOfCells = 3; + MessageTableCellWithBuffer m_cell[k_maxNumberOfCells]; +}; + +} + +#endif diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index 721941691..ec7a063b4 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Standard " ExamModeModeNoSym = "Kein Symbol " ExamModeModeNoSymNoText = "Kein Symbol kein Text " ExamModeModeDutch = "Niederländisch " +USBE16_expl1= "USB-Schutz schützt Ihren" +USBE16_expl2= "Taschenrechner vor" +USBE16_expl3= "unbeabsichtigter Verriegelung" +USBProtection= "USB-Schutz" +USBSettingDeact = "Bitte schalte den Schutz ein" +USBLevelProtect = "Akzeptierte Updates" +USBDefaultLevel = "Basierend auf Upsilon" +USBLowLevel = "Basierend auf Omega" +USBParanoidLevel = "Nur Python" +USBMegaParanoidLevel = "Nichts" +USBDeacAlert1 = "Ändern Sie diesen Parameter nur," +USBDeacAlert2 = "wenn Sie wissen, was Sie tun!" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index d61df44e1..cdf85677e 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Standard " ExamModeModeNoSym = "No sym " ExamModeModeNoSymNoText = "No sym no text " ExamModeModeDutch = "Dutch " +USBE16_expl1= "The USB protection protects" +USBE16_expl2= "the calculator from" +USBE16_expl3= "unintentional locking" +USBProtection= "USB Protection" +USBSettingDeact = "Please turn on the protection" +USBLevelProtect = "Updates accepted" +USBDefaultLevel = "Based on Upsilon" +USBLowLevel = "Based on Omega" +USBParanoidLevel = "Python Only" +USBMegaParanoidLevel = "None" +USBDeacAlert1 = "Change this parameter only if" +USBDeacAlert2 = "you know what you are doing !" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index e542571ed..eb21e5516 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Estándar " ExamModeModeNoSym = "Sin simbólico " ExamModeModeNoSymNoText = "Sin simbólico sin texto " ExamModeModeDutch = "Holandés " +USBE16_expl1= "La protección USB protege" +USBE16_expl2= "su calculadora del" +USBE16_expl3= "bloqueo involuntario" +USBProtection= "Protección USB" +USBSettingDeact = "Enciende la protección" +USBLevelProtect = "Actualizaciones aceptadas" +USBDefaultLevel = "Basado en Upsilon" +USBLowLevel = "Basado en Omega" +USBParanoidLevel = "Solo Python" +USBMegaParanoidLevel = "Ninguno" +USBDeacAlert1 = "¡Cambie este parámetro solo" +USBDeacAlert2 = "si sabe lo que está haciendo!" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 46b76202d..bd01041b5 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Standard " ExamModeModeNoSym = "Sans symbolique " ExamModeModeNoSymNoText = "Sans symbolique ni texte " ExamModeModeDutch = "Dutch " +USBE16_expl1= "La protection USB protège votre" +USBE16_expl2= "calculatrice contre un verrouillage" +USBE16_expl3= "non-intentionnel" +USBProtection= "Protection USB" +USBSettingDeact = "Veuillez activer la protection" +USBLevelProtect = "Mise à jour acceptées" +USBDefaultLevel = "Basées sur Upsilon" +USBLowLevel = "Basées sur Omega" +USBParanoidLevel = "Aucune" +USBMegaParanoidLevel = "Aucune" +USBDeacAlert1 = "Ne modifiez ce paramètre que" +USBDeacAlert2 = "si vous savez ce que vous faites !" diff --git a/apps/shared.hu.i18n b/apps/shared.hu.i18n index 60ba0754b..84b3c1451 100644 --- a/apps/shared.hu.i18n +++ b/apps/shared.hu.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Normál " ExamModeModeNoSym = "Szimbólikus nélkül " ExamModeModeNoSymNoText = "Szimbólikus és szöveg nélkül " ExamModeModeDutch = "Holland " +USBE16_expl1= "Az USB-védelem megvédi" +USBE16_expl2= "a számológépet a nem" +USBE16_expl3= "szándékos reteszeléstől" +USBProtection= "USB védelem" +USBSettingDeact = "Kérjük, kapcsolja be a védelmet" +USBLevelProtect = "Elfogadott frissítések" +USBDefaultLevel = "Upsilon alapján" +USBLowLevel = "Omega alapján" +USBParanoidLevel = "Csak Python" +USBMegaParanoidLevel = "Egyik sem" +USBDeacAlert1 = "Csak akkor módosítsa ezt a" +USBDeacAlert2 = "paramétert, ha tudja, mit csinál!" diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n index 3322800c8..60cd96bce 100644 --- a/apps/shared.it.i18n +++ b/apps/shared.it.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Standard " ExamModeModeNoSym = "Nessun simbolo " ExamModeModeNoSymNoText = "Nessun simbolo nessun testo " ExamModeModeDutch = "Olandese " +USBE16_expl1= "La protezione USB protegge" +USBE16_expl2= "la calcolatrice dal" +USBE16_expl3= "blocco involontario" +USBProtection= "Protezione USB" +USBSettingDeact = "Si prega di attivare la protezione" +USBLevelProtect = "Aggiornamenti accettati" +USBDefaultLevel = "Basato su Upsilon" +USBLowLevel = "A base di Omega" +USBParanoidLevel = "Solo Python" +USBMegaParanoidLevel = "Nessuno" +USBDeacAlert1 = "Cambia questo parametro solo" +USBDeacAlert2 = "se sai cosa stai facendo !" diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index b3971aa6c..6fbde69a4 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Standaard " ExamModeModeNoSym = "Geen sym " ExamModeModeNoSymNoText = "Geen sym geen tekst " ExamModeModeDutch = "Nederlands " +USBE16_expl1= "USB-beveiliging beschermt uw" +USBE16_expl2= "rekenmachine tegen" +USBE16_expl3= "onbedoelde vergrendeling" +USBProtection= "USB-beveiliging" +USBSettingDeact = "Schakel a.u.b. de bescherming in" +USBLevelProtect = "Updates geaccepteerd" +USBDefaultLevel = "Gebaseerd op Upsilon" +USBLowLevel = "Op basis van Omega" +USBParanoidLevel = "Alleen Python" +USBMegaParanoidLevel = "Geen" +USBDeacAlert1 = "Wijzig deze parameter alleen" +USBDeacAlert2 = "als u weet wat u doet!" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 39fa24c12..11f9a8b96 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -99,3 +99,15 @@ ExamModeModeStandard = "Padrão " ExamModeModeNoSym = "Sem sym " ExamModeModeNoSymNoText = "Sem sym sem texto " ExamModeModeDutch = "holandês " +USBE16_expl1= "A proteção USB protege" +USBE16_expl2= "sua calculadora contra" +USBE16_expl3= "bloqueios não intencionais" +USBProtection= "Proteção USB" +USBSettingDeact = "Por favor, ligue a proteção" +USBLevelProtect = "Atualizações aceitas" +USBDefaultLevel = "Baseado em Upsilon" +USBLowLevel = "Baseado em Ômega" +USBParanoidLevel = "Apenas Python" +USBMegaParanoidLevel = "Nenhum" +USBDeacAlert1 = "Mude este parâmetro somente" +USBDeacAlert2 = "se você souber o que está fazendo!" diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 7c42fa088..4326c16a7 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -458,6 +458,11 @@ HartreeConstant = "4.3597447222071·10^-18_J" MagneticFluxQuantum = "2.067833848·10^-15_Wb" ConductanceQuantum = "7.748091729·10^-5_S" CirculationQuantum = "3.6369475516·10^-4_m^2_s^-1" +UsbSetting = "USB" +USBDefaultLevelDesc = "L0" +USBLowLevelDesc = "L1" +USBParanoidLevelDesc = "L2" +USBMegaParanoidLevelDesc = "L3" Cndcvt_Silver = "6.30·10^7_S_m^-1" Cndcvt_Copper = "5.96·10^7_S_m^-1" Cndcvt_Gold = "4.11·10^7_S_m^-1" diff --git a/apps/usb/Makefile b/apps/usb/Makefile index 79692e351..fb8cfd2b7 100644 --- a/apps/usb/Makefile +++ b/apps/usb/Makefile @@ -1,6 +1,7 @@ app_usb_src = $(addprefix apps/usb/,\ app.cpp \ usb_connected_controller.cpp \ + usb_view.cpp \ ) apps_src += $(app_usb_src) diff --git a/apps/usb/app.cpp b/apps/usb/app.cpp index 99cdd7a6c..ad0256be1 100644 --- a/apps/usb/app.cpp +++ b/apps/usb/app.cpp @@ -27,6 +27,7 @@ App::App(Snapshot * snapshot) : } bool App::processEvent(Ion::Events::Event e) { + // Impossible de gérer mes events ici lorsqu'on active le DFU return false; } diff --git a/apps/usb/base.de.i18n b/apps/usb/base.de.i18n index 794b4d36b..0cf269f75 100644 --- a/apps/usb/base.de.i18n +++ b/apps/usb/base.de.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide." ConnectedMessage4 = "Drücken Sie die Zurück-Taste am" ConnectedMessage5 = "Taschenrechner oder Kabel abziehen," ConnectedMessage6 = "um die Verbindung zu trennen." +DfuStatus1 = "Status des Rechners:" +DfuStatusProtected = "GESCHÜTZT" +DfuStatusUnProtected = "UNGESCHÜTZT" +USBProtectionLevel0 = "Standardschutz" +USBProtectionLevel1 = "Omega Schutz" +USBProtectionLevel2 = "Systemschutz" diff --git a/apps/usb/base.en.i18n b/apps/usb/base.en.i18n index 0eb615fa2..b7411ff54 100644 --- a/apps/usb/base.en.i18n +++ b/apps/usb/base.en.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Press the BACK key of your" ConnectedMessage5 = "calculator or unplug it to" ConnectedMessage6 = "disconnect it." +DfuStatus1 = "Calculator status:" +DfuStatusProtected = "PROTECTED" +DfuStatusUnProtected = "UNPROTECTED" +USBProtectionLevel0 = "Default Protection" +USBProtectionLevel1 = "Omega Protection" +USBProtectionLevel2 = "System Protection" diff --git a/apps/usb/base.es.i18n b/apps/usb/base.es.i18n index cf9b3d7b5..0ccebf53d 100644 --- a/apps/usb/base.es.i18n +++ b/apps/usb/base.es.i18n @@ -4,4 +4,10 @@ ConnectedMessage2 = "nuestra página desde su ordenador" ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Pulse el botón RETURN de la" ConnectedMessage5 = "calculadora o desenchúfela para" -ConnectedMessage6 = "desconectarla." \ No newline at end of file +ConnectedMessage6 = "desconectarla." +DfuStatus1 = "Estado de la calculadora:" +DfuStatusProtected = "PROTEGIDO" +DfuStatusUnProtected = "DESABRIGADO" +USBProtectionLevel0 = "Protección predeterminada" +USBProtectionLevel1 = "Protección Omega" +USBProtectionLevel2 = "Protección del sistema" diff --git a/apps/usb/base.fr.i18n b/apps/usb/base.fr.i18n index 33762ca54..d1a4e9448 100644 --- a/apps/usb/base.fr.i18n +++ b/apps/usb/base.fr.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Appuyez sur la touche RETOUR" ConnectedMessage5 = "de la calculatrice ou débranchez-la" ConnectedMessage6 = "pour la déconnecter." +DfuStatus1 = "Etat de la calculatrice:" +DfuStatusProtected = "PROTÉGÉE" +DfuStatusUnProtected = "NON PROTÉGÉE" +USBProtectionLevel0 = "Default Protection" +USBProtectionLevel1 = "Omega Protection" +USBProtectionLevel2 = "System Protection" diff --git a/apps/usb/base.hu.i18n b/apps/usb/base.hu.i18n index a8a3de172..d432c76d3 100644 --- a/apps/usb/base.hu.i18n +++ b/apps/usb/base.hu.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "fel getomega.dev/ide ra." ConnectedMessage4 = "Nyomjon majd a VISSZA gombra" ConnectedMessage5 = "vagy huzza ki a kábelt azért" ConnectedMessage6 = "hogy a másolás véget érjen." +DfuStatus1 = "Számológép állapota:" +DfuStatusProtected = "VÉDETT" +DfuStatusUnProtected = "VÉDTELEN" +USBProtectionLevel0 = "Alapértelmezett védelem" +USBProtectionLevel1 = "Omega védelem" +USBProtectionLevel2 = "Rendszervédelem" diff --git a/apps/usb/base.it.i18n b/apps/usb/base.it.i18n index fdc2be0bd..2fbed5da8 100644 --- a/apps/usb/base.it.i18n +++ b/apps/usb/base.it.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Premere sul tasto INDIETRO della" ConnectedMessage5 = "calcolatrice o scollegatela per" ConnectedMessage6 = "disconnetterla." +DfuStatus1 = "Stato della calcolatrice:" +DfuStatusProtected = "PROTETTO" +DfuStatusUnProtected = "INDIFESO" +USBProtectionLevel0 = "Protezione predefinita" +USBProtectionLevel1 = "Protezione Omega" +USBProtectionLevel2 = "Protezione del sistema" diff --git a/apps/usb/base.nl.i18n b/apps/usb/base.nl.i18n index db29c1127..e05db7f3f 100644 --- a/apps/usb/base.nl.i18n +++ b/apps/usb/base.nl.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Druk op de TERUG toets van je" ConnectedMessage5 = "rekenmachine of verwijder de" ConnectedMessage6 = " kabel om hem los te koppelen." +DfuStatus1 = "Rekenmachine status:" +DfuStatusProtected = "BESCHERMD" +DfuStatusUnProtected = "NIET BESCHERMD" +USBProtectionLevel0 = "Standaardbeveiliging" +USBProtectionLevel1 = "Omega Bescherming" +USBProtectionLevel2 = "Systeembeveiliging" diff --git a/apps/usb/base.pt.i18n b/apps/usb/base.pt.i18n index 408b24db7..91dd85e3c 100644 --- a/apps/usb/base.pt.i18n +++ b/apps/usb/base.pt.i18n @@ -5,3 +5,9 @@ ConnectedMessage3 = "getomega.dev/ide" ConnectedMessage4 = "Pressione o botão RETURN na" ConnectedMessage5 = "calculadora ou desligue-a para a" ConnectedMessage6 = "desconectar." +DfuStatus1 = "Status da calculadora:" +DfuStatusProtected = "PROTEGIDO" +DfuStatusUnProtected = "DESPROTEGIDO" +USBProtectionLevel0 = "Proteção padrão" +USBProtectionLevel1 = "Proteção Ômega" +USBProtectionLevel2 = "Proteção do sistema" diff --git a/apps/usb/usb_connected_controller.cpp b/apps/usb/usb_connected_controller.cpp index 71a354c4a..deb3abff0 100644 --- a/apps/usb/usb_connected_controller.cpp +++ b/apps/usb/usb_connected_controller.cpp @@ -1,42 +1,140 @@ #include "usb_connected_controller.h" #include +#include "../global_preferences.h" -namespace USB { - -static I18n::Message sUSBConnectedMessages[] = { - I18n::Message::USBConnected, - I18n::Message::ConnectedMessage1, - I18n::Message::ConnectedMessage2, - I18n::Message::ConnectedMessage3, - I18n::Message::BlankMessage, - I18n::Message::ConnectedMessage4, - I18n::Message::ConnectedMessage5, - I18n::Message::ConnectedMessage6}; - -static KDColor sUSBConnectedFGColors[] = { - Palette::PrimaryText, - Palette::PrimaryText, - Palette::PrimaryText, - Palette::AccentText, - KDColorWhite, - Palette::PrimaryText, - Palette::PrimaryText, - Palette::PrimaryText}; - -static KDColor sUSBConnectedBGColors[] = { - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard, - Palette::BackgroundHard}; - -USBConnectedController::USBConnectedController() : - ViewController(nullptr), - m_messageView(sUSBConnectedMessages, sUSBConnectedFGColors, sUSBConnectedBGColors, 8) +namespace USB { -} + + static I18n::Message sUSBConnectedMessagesProtection0[10] = { + I18n::Message::USBConnected, + I18n::Message::ConnectedMessage1, + I18n::Message::ConnectedMessage2, + I18n::Message::ConnectedMessage3, + I18n::Message::BlankMessage, + I18n::Message::ConnectedMessage4, + I18n::Message::ConnectedMessage5, + I18n::Message::ConnectedMessage6, + I18n::Message::DfuStatus1, + I18n::Message::USBProtectionLevel0}; + + static I18n::Message sUSBConnectedMessagesProtection1[10] = { + I18n::Message::USBConnected, + I18n::Message::ConnectedMessage1, + I18n::Message::ConnectedMessage2, + I18n::Message::ConnectedMessage3, + I18n::Message::BlankMessage, + I18n::Message::ConnectedMessage4, + I18n::Message::ConnectedMessage5, + I18n::Message::ConnectedMessage6, + I18n::Message::DfuStatus1, + I18n::Message::USBProtectionLevel1}; + + static I18n::Message sUSBConnectedMessagesProtection2[10] = { + I18n::Message::USBConnected, + I18n::Message::ConnectedMessage1, + I18n::Message::ConnectedMessage2, + I18n::Message::ConnectedMessage3, + I18n::Message::BlankMessage, + I18n::Message::ConnectedMessage4, + I18n::Message::ConnectedMessage5, + I18n::Message::ConnectedMessage6, + I18n::Message::DfuStatus1, + I18n::Message::USBProtectionLevel2}; + + static I18n::Message sUSBConnectedMessagesUnProtected[10] = { + I18n::Message::USBConnected, + I18n::Message::ConnectedMessage1, + I18n::Message::ConnectedMessage2, + I18n::Message::ConnectedMessage3, + I18n::Message::BlankMessage, + I18n::Message::ConnectedMessage4, + I18n::Message::ConnectedMessage5, + I18n::Message::ConnectedMessage6, + I18n::Message::DfuStatus1, + I18n::Message::DfuStatusUnProtected}; + + static KDColor sUSBConnectedFGColors[] = { + Palette::PrimaryText, + Palette::PrimaryText, + Palette::PrimaryText, + Palette::AccentText, + KDColorWhite, + Palette::PrimaryText, + Palette::PrimaryText, + Palette::PrimaryText, + Palette::PrimaryText, + Palette::AccentText}; + + static KDColor sUSBConnectedBGColors[] = { + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard, + Palette::BackgroundHard}; + + USBConnectedController::USBConnectedController() : ViewController(nullptr), step(0), already_init(false), m_messageView(sUSBConnectedMessagesProtection0, sUSBConnectedFGColors, sUSBConnectedBGColors, 10) + { + if(already_init){ + return; + } + if (step == 0 && GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) + { + getMessageView()->update(sUSBConnectedMessagesUnProtected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + }else if(step == 0){ + if(GlobalPreferences::sharedGlobalPreferences()->getDfuLevel() == 1){ + getMessageView()->update(sUSBConnectedMessagesProtection1, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + }else if(GlobalPreferences::sharedGlobalPreferences()->getDfuLevel() == 2){ + getMessageView()->update(sUSBConnectedMessagesProtection2, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + } + } + // else if (step == 1 && GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) + // { + // getMessageView()->update(sUSBConnectedMessages2UnProtected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // } + // else if (step == 1 && !GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) + // { + // getMessageView()->update(sUSBConnectedMessages2Protected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // } + already_init = true; + } + + // bool USBConnectedController::handleEvent(Ion::Events::Event event) + // { + // if (event.isKeyboardEvent()) + // { + // // Ne fonctionne pas pour l'instant fait bugger les events + // // if (step == 0) + // // { + // // if (GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) + // // { + // // getMessageView()->update(sUSBConnectedMessagesUnProtected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // // } + // // else + // // { + // // getMessageView()->update(sUSBConnectedMessagesProtected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // // } + // // step = 1; + // // } + // // else + // // { + // // if (GlobalPreferences::sharedGlobalPreferences()->dfuStatus()) + // // { + // // getMessageView()->update(sUSBConnectedMessages2UnProtected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // // } + // // else + // // { + // // getMessageView()->update(sUSBConnectedMessages2Protected, sUSBConnectedFGColors, sUSBConnectedBGColors, 10); + // // } + // // step = 0; + // // } + // return false; + // } + // return false; + // } } diff --git a/apps/usb/usb_connected_controller.h b/apps/usb/usb_connected_controller.h index c733062ed..b2f5a269f 100644 --- a/apps/usb/usb_connected_controller.h +++ b/apps/usb/usb_connected_controller.h @@ -2,7 +2,7 @@ #define USB_USB_CONNECTED_CONTROLLER_H #include -#include "../shared/message_view.h" +#include "usb_view.h" namespace USB { @@ -10,9 +10,12 @@ class USBConnectedController : public ViewController { public: USBConnectedController(); View * view() override { return &m_messageView; } - bool handleEvent(Ion::Events::Event event) override { return false; } + USBView * getMessageView() {return &m_messageView; } + bool handleEvent(Ion::Events::Event event) override { return false; }; private: - MessageView m_messageView; + int step; + bool already_init; + USBView m_messageView; }; } diff --git a/apps/usb/usb_view.cpp b/apps/usb/usb_view.cpp new file mode 100644 index 000000000..2eab7ee40 --- /dev/null +++ b/apps/usb/usb_view.cpp @@ -0,0 +1,56 @@ +#include "usb_view.h" +#include + +namespace USB { + USBView::USBView(I18n::Message *messages, KDColor *fgcolors, KDColor *bgcolors, uint8_t numberOfMessages) { + m_numberOfMessages = numberOfMessages < k_maxNumberOfMessages ? numberOfMessages : k_maxNumberOfMessages; + for (uint8_t i = 0; i < m_numberOfMessages; i++) { + m_messageTextViews[i].setFont(i == 0 ? KDFont::LargeFont : KDFont::SmallFont); + m_messageTextViews[i].setMessage(messages[i]); + m_messageTextViews[i].setAlignment(0.5f, 0.5f); + m_messageTextViews[i].setTextColor(fgcolors[i]); + m_messageTextViews[i].setBackgroundColor(bgcolors[i]); + } + } + + void USBView::drawRect(KDContext *ctx, KDRect rect) const { + ctx->fillRect(bounds(), Palette::BackgroundHard); + } + + View *USBView::subviewAtIndex(int index) { + if (index >= m_numberOfMessages) { + assert(false); + return nullptr; + } + return &(m_messageTextViews[index]); + } + + void USBView::update(I18n::Message *messages, KDColor *fgcolors, KDColor *bgcolors, uint8_t numberOfMessages){ + m_numberOfMessages = numberOfMessages < k_maxNumberOfMessages ? numberOfMessages : k_maxNumberOfMessages; + for (uint8_t i = 0; i < m_numberOfMessages; i++) { + m_messageTextViews[i].setFont(i == 0 ? KDFont::LargeFont : KDFont::SmallFont); + m_messageTextViews[i].setMessage(messages[i]); + m_messageTextViews[i].setAlignment(0.5f, 0.5f); + m_messageTextViews[i].setTextColor(fgcolors[i]); + m_messageTextViews[i].setBackgroundColor(bgcolors[i]); + } + reload(); + } + + void USBView::reload() { + markRectAsDirty(bounds()); + } + + void USBView::layoutSubviews(bool force) { + if (m_numberOfMessages == 0) { + return; + } + KDCoordinate width = bounds().width(); + KDCoordinate titleHeight = m_messageTextViews[0].minimalSizeForOptimalDisplay().height(); + KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); + m_messageTextViews[0].setFrame(KDRect(0, k_titleMargin, width, titleHeight), force); + for (uint8_t i = 1; i < m_numberOfMessages; i++) { + m_messageTextViews[i].setFrame(KDRect(0, k_paragraphHeight + (i - 1) * textHeight, width, textHeight), force); + } + } +} diff --git a/apps/usb/usb_view.h b/apps/usb/usb_view.h new file mode 100644 index 000000000..67e274093 --- /dev/null +++ b/apps/usb/usb_view.h @@ -0,0 +1,30 @@ +#ifndef USB_VIEW_H +#define USB_VIEW_H + +#include + +namespace USB +{ + class USBView : public View + { + public: + USBView(I18n::Message *messages, KDColor *fgcolors, KDColor *bgcolors, uint8_t numberOfMessages); + void drawRect(KDContext *ctx, KDRect rect) const override; + void reload(); + void update(I18n::Message *messages, KDColor *fgcolors, KDColor *bgcolors, uint8_t numberOfMessages); + protected: + int numberOfSubviews() const override { return m_numberOfMessages; } + View *subviewAtIndex(int index) override; + void layoutSubviews(bool force = false) override; + + private: + constexpr static KDCoordinate k_titleMargin = 30; + constexpr static KDCoordinate k_paragraphHeight = 80; + constexpr static uint8_t k_maxNumberOfMessages = 10; + MessageTextView m_messageTextViews[k_maxNumberOfMessages]; + uint8_t m_numberOfMessages; + }; + +} + +#endif diff --git a/build/device/secure_ext.py b/build/device/secure_ext.py new file mode 100644 index 000000000..68d2a6a65 --- /dev/null +++ b/build/device/secure_ext.py @@ -0,0 +1,29 @@ +import sys +import os + +MAGIK_CODE = [0x64, 0x6c, 0x31, 0x31, 0x23, 0x39, 0x38, 0x33, 0x35] +MAGIK_POS = [0x03, 0xb, 0x44f] + +if len(sys.argv) > 1: + print("Patching external bin...") + ext_path = os.path.join(os.getcwd(), sys.argv[1]) + if not os.path.isfile(ext_path): + print("Error: File not found!") + sys.exit(-1) + file = open(ext_path, "r+b") + first_packet = bytearray(file.read(2048)) + for b in first_packet: + if b != 255: + print("Error: Invalid file! (maybe already patched?)") + sys.exit(-1) + + for i in range(4): + first_packet[MAGIK_POS[0] + i] = MAGIK_CODE[i] + for i in range(4): + first_packet[MAGIK_POS[1] + i] = MAGIK_CODE[i + 5] + for i in range(len(MAGIK_CODE)): + first_packet[MAGIK_POS[2] + i] = MAGIK_CODE[i] + + file.seek(0) + file.write(first_packet) + print("External bin Patched!") \ No newline at end of file diff --git a/build/targets.device.mak b/build/targets.device.mak index 9498371c4..850cbf076 100644 --- a/build/targets.device.mak +++ b/build/targets.device.mak @@ -27,11 +27,11 @@ $(BUILD_DIR)/%.map: $(BUILD_DIR)/%.elf @echo "LDMAP $@" $(Q) $(LD) $^ $(LDFLAGS) -Wl,-M -Wl,-Map=$@ -o /dev/null -.PHONY: %_memory_map -%_memory_map: $(BUILD_DIR)/%.map - @echo "========== MEMORY MAP =========" - $(Q) awk -f build/device/memory_map.awk < $< - @echo "===============================" +.PHONY: mapfile +mapfile: + $(BUILD_DIR)/%.map: $(BUILD_DIR)/%.elf + @echo "LDMAP $@" + $(Q) $(LD) $^ $(LDFLAGS) -Wl,-M -Wl,-Map=$@ -o /dev/null .PHONY: openocd openocd: @@ -72,3 +72,4 @@ binpack: $(BUILD_DIR)/flasher.light.bin $(BUILD_DIR)/epsilon.onboarding.two_bina cp $(BUILD_DIR)/epsilon.onboarding.internal.bin $(BUILD_DIR)/epsilon.onboarding.external.bin $(BUILD_DIR)/binpack cd $(BUILD_DIR) && for binary in flasher.light.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done cd $(BUILD_DIR) && tar cvfz binpack-$(MODEL)-`git rev-parse HEAD | head -c 7`.tgz binpack/* + $(PYTHON) build/device/secure_ext.py $(BUILD_DIR)/epsilon.onboarding.external.bin \ No newline at end of file diff --git a/ion/include/ion/usb.h b/ion/include/ion/usb.h index e5760bb94..d9ec8afd7 100644 --- a/ion/include/ion/usb.h +++ b/ion/include/ion/usb.h @@ -8,7 +8,7 @@ bool isPlugged(); bool isEnumerated(); // Speed-enumerated, to be accurate void clearEnumerationInterrupt(); -void DFU(bool exitWithKeyboard = true); +void DFU(bool exitWithKeyboard = true, bool unlocked = false, int level = 0); void enable(); void disable(); diff --git a/ion/src/device/flasher/main.cpp b/ion/src/device/flasher/main.cpp index 3dcfcd80d..09f05e8ca 100644 --- a/ion/src/device/flasher/main.cpp +++ b/ion/src/device/flasher/main.cpp @@ -11,6 +11,6 @@ void ion_main(int argc, const char * const argv[]) { Ion::USB::enable(); while (!Ion::USB::isEnumerated()) { } - Ion::USB::DFU(false); + Ion::USB::DFU(false, false, 0); } } diff --git a/ion/src/device/n0110/drivers/board.cpp b/ion/src/device/n0110/drivers/board.cpp index 0ed24868c..228fbe6fc 100644 --- a/ion/src/device/n0110/drivers/board.cpp +++ b/ion/src/device/n0110/drivers/board.cpp @@ -30,7 +30,9 @@ void initMPU() { Cache::dmb(); // 1.2 Disable fault exceptions - CORTEX.SHCRS()->setMEMFAULTENA(false); + CORTEX.SHCRS()->setMEMFAULTENA(true); + CORTEX.SHCRS()->setBUSFAULTENA(true); + CORTEX.SHCRS()->setUSGFAULTENA(true); // 1.3 Disable the MPU and clear the control register MPU.CTRL()->setENABLE(false); @@ -121,7 +123,7 @@ void init() { initClocks(); // The bootloader leaves its own after flashing - //SYSCFG.MEMRMP()->setMEM_MODE(SYSCFG::MEMRMP::MemMode::MainFlashmemory); + // SYSCFG.MEMRMP()->setMEM_MODE(SYSCFG::MEMRMP::MemMode::MainFlashmemory); // Ensure right location of interrupt vectors CORTEX.VTOR()->setVTOR((void*)&InitialisationVector); diff --git a/ion/src/device/n0110/flash.ld b/ion/src/device/n0110/flash.ld index 9728e4ad3..1f2ebb8bb 100644 --- a/ion/src/device/n0110/flash.ld +++ b/ion/src/device/n0110/flash.ld @@ -63,6 +63,14 @@ SECTIONS { . = ALIGN(4); *(.text.start) *(.text.abort) + *(.text.uf_abort) + *(.text.bf_abort) + *(.text.nmi_abort) + *(.text.abort_init) + *(.text.abort_core) + *(.text.abort_sleeping) + *(.text.abort_economy) + *(.text.abort_screen) *(.text.isr_systick) *(.text.__assert) *(.text.memcpy) @@ -89,6 +97,123 @@ SECTIONS { /* 'abort' dependencies */ *(.text._ZN3Ion6Device5Reset4coreEv) + *(.text._ZN3Ion3LED8setColorE7KDColor) + *(.text._ZN3Ion3LED11setBlinkingEtf) + *(.text._ZN3Ion6Device3LED*) + *(.text._ZNK3Ion6Device4Regs3TIMINS1_8RegisterItEEE4CCMREv) + *(.text._ZNK3Ion6Device4Regs3TIMINS1_8RegisterItEEE4BaseEv) + *(.text._ZNK3Ion6Device4Regs3*) + *(.text.___ZN3Ion6Device4Regs8*) + *(.text._ZNK3Ion6Device4Regs3TIMINS1_8RegisterItEEE4CCMREv) + *(.text._ZNK3Ion6Device4Regs3TIMINS1_8RegisterItEEE4CCMREv*) + *(.text._ZN3Ion6Device5Board15initPeripheralsEb) + *(.text._ZN3Ion6Device9Backlight4initEv) + *(.text._ZN3Ion6Device6Timing4initEv) + *(.text._ZN3Ion6Timing6msleepEj) + *(.text._ZN3Ion6Device8Keyboard4initEv) + *(.text._ZN3Ion6Device7Battery8initGPIOEv) + *(.text._ZN3Ion6Device3USB8initGPIOEv) + *(.text._ZN3Ion6Device9Backlight8setLevelEh) + *(.text._ZN3Ion6Device6Timing19setSysTickFrequencyEi) + *(.text._ZN3Ion6Device5Board17setClockFrequencyENS1_9FrequencyE) + *(.text._ZN3Ion6Device9Backlight10sendPulsesEi) + *(.text._ZN3Ion6Device5Board19shutdownPeripheralsEb) + *(.text._ZN3Ion6Device6Timing8shutdownEv) + *(.text._ZN3Ion6Device8Keyboard8shutdownEv) + *(.text._ZN9KDContext10drawStringEPKc7KDPointPK6KDFont7KDColorS6_i) + *(.text._ZNK8TextArea11ContentView12drawStringAtEP9KDContextiiPKci7KDColorS5_S4_S4_S5_*) + *(.text._ZL11KDPointZero*) + *(.text._ZGVZN12KDIonContext13sharedContextEvE7context) + *(.text._ZZN12KDIonContext13sharedContextEvE7context) + *(.text._ZN12KDIonContext13sharedContextEv) + *(.text._ZN20KDPostProcessContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN26KDPostProcessInvertContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN12KDIonContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN24KDPostProcessZoomContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN25KDPostProcessGammaContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN16KDRealIonContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN3Ion7Display15pushRectUniformE6KDRect7KDColor) + *(.text._ZNK6KDRect15intersectedWithERKS_) + *(.text._ZN7KDColor6RGB888Ehhh) + *(.text._ZN3Ion6Device7Display14setDrawingAreaE6KDRectNS1_11OrientationE) + *(.text.powf) + *(.text._ZN9KDContext16pushOrPullStringEPKc7KDPointPK6KDFont7KDColorS6_ibPi) + *(.text._ZNK7KDPoint12translatedByES_) + *(.text._ZNK6KDRect12translatedByE7KDPoint) + *(.text._Z7toGammai) + *(.text._ZN3Ion7Display8pullRectE6KDRectP7KDColor) + *(.text._ZN24KDPostProcessZoomContext8pullRectE6KDRectP7KDColor) + *(.text._ZN16KDRealIonContext8pullRectE6KDRectP7KDColor) + *(.text._ZN25KDPostProcessGammaContext8pullRectE6KDRectP7KDColor) + *(.text._ZN12KDIonContext8pullRectE6KDRectP7KDColor) + *(.text._ZN26KDPostProcessInvertContext8pullRectE6KDRectP7KDColor) + *(.text._ZN20KDPostProcessContext8pullRectE6KDRectP7KDColor) + *(.text.sqrtf) + *(.text._ZN11UTF8Decoder13nextCodePointEv) + *(.text._ZN7KDColor5blendES_S_h) + *(.text._ZN9KDContext17blendRectWithMaskE6KDRect7KDColorPKhPS1_) + *(.text.scalbnf) + *(.text._ZNK6KDRect10intersectsERKS_) + *(.text._ZN9KDContext18fillRectWithPixelsE6KDRectPK7KDColorPS1_) + *(.text._ZN9KDContext15setClippingRectE6KDRect) + *(.text._ZN9KDContext9setOriginE7KDPoint) + *(.text._ZN20KDPostProcessContext9setOriginE7KDPoint) + *(.text._ZN20KDPostProcessContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN26KDPostProcessInvertContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN20KDPostProcessContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN12KDIonContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN12KDIonContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN26KDPostProcessInvertContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN24KDPostProcessZoomContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN24KDPostProcessZoomContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN25KDPostProcessGammaContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN25KDPostProcessGammaContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN16KDRealIonContext15pushRectUniformE6KDRect7KDColor) + *(.text._ZN16KDRealIonContext8pushRectE6KDRectPK7KDColor) + *(.text._ZN3Ion7Display8pushRectE6KDRectPK7KDColor) + *(.text._ZN3Ion7Display15pushRectUniformE6KDRect7KDColor) + *(.text._ZNK6KDRect7isEmptyEv) + *(.text._ZN20KDPostProcessContext15setClippingRectE6KDRect) + *(.text._ZNK6KDFont17indexForCodePointE9CodePoint) + *(.text._ZNK6KDFont26fetchGrayscaleGlyphAtIndexEhPh) + *(.text.LZ4_decompress_safe) + *(.text.LZ4_wildCopy) + *(.text.*DFU*) + *(.text.*isEnumerated*) + *(.text._ZN3Ion3USB6enableEv) + *(.text._ZN3Ion7Battery5levelEv) + *(.text._ZN3Ion7Battery7voltageEv) + *(.text._ZN3Ion3USB9isPluggedEv) + *(.text.*sleepConfiguration*) + *(.text.*onOnOffKeyDown*) + *(.text.*WakeUp*) + *(.text._ZN3Ion6Device9Backlight*) + *(.text._ZN3Ion9Backlight*) + + /* Rodata Truc Relou */ + *(.text._ZNK10Statistics5Store6medianEi) + *(.text._ZNK10Regression5Store12meanOfColumnEiib) + *(.text._ZNK6Shared15DoublePairStore11sumOfColumnEiib) + *(.text._ZNK10Statistics5Store13firstQuartileEi) + *(.text._ZNK10Regression5Store23squaredValueSumOfColumnEiib) + *(.text._ZNK10Regression5Store16varianceOfColumnEiib) + *(.text._ZNK10Statistics5Store8maxValueEi) + *(.text._ZNK10Regression5Store25standardDeviationOfColumnEiib) + *(.text._ZNK10Statistics5Store13thirdQuartileEi) + *(.text._ZNK10Statistics5Store8minValueEi) + *(.text._ZNK6Shared8Interval18IntervalParameters*) + *(.text._ZN6Shared8Interval18IntervalParameters*) + *(.text.sqrt) + *(.text.log) + *(.text._ZN17GlobalPreferences23sharedGlobalPreferencesEv) + *(.text._ZNK10Statistics5Store16sumOfOccurrencesEi) + *(.text.floor) + *(.text.ceil) + *(.text._ZNK10Statistics5Store21frequenciesAreIntegerEi) + *(.text._ZNK10Statistics5Store34sortedElementAtCumulatedPopulationEidb) + *(.text._ZNK10Statistics5Store33sortedElementAtCumulatedFrequencyEidb) + *(.text.round) + *(.text._ZNK10Statistics5Store8minIndexEPdi*) /* 'standby' dependencies '*/ *(.text._ZN3Ion6Device5Power20internalFlashStandbyEv) @@ -113,7 +238,49 @@ SECTIONS { /* 'start' dependencies */ *(.rodata._ZN3Ion6Device4RegsL5GPIOAE) *(.rodata._ZN3Ion6Device4RegsL5GPIOBE) + *(.rodata._ZN3Ion6Device3LED6ConfigL7RGBPinsE) *(.rodata._ZN3Ion6Device5Board4initEv.str1.4) + *(.rodata._ZL12KDColorWhite*) + *(.rodata._ZL10KDColorRed*) + *(.rodata._ZL12KDColorBlack*) + *(.rodata._ZN3Ion6Device3SWD6ConfigL4PinsE) + *(.rodata._ZN3Ion6Device7Display6ConfigL8FSMCPinsE) + *(.rodata._ZZN3Ion6Device7Display9initPanelEvE11calibration) + *(.rodata._ZN3Ion6Device3USB6ConfigL5DmPinE) + *(.rodata._ZN3Ion6Device3USB6ConfigL5DpPinE) + *(.rodata._ZN3Ion6Device3USB6ConfigL7VbusPinE) + *(.rodata._ZN3Ion6Device8Keyboard6ConfigL10ColumnPinsE) + *(.rodata._ZN3Ion6Device8Keyboard6ConfigL7RowPinsE) + *(.rodata._ZZN3Ion6Device3USB12shutdownGPIOEvE4Pins) + *(.rodata._ZN6KDFont16privateLargeFontE) + *(.rodata.abort.str1.1) + *(.rodata.uf_abort.str1.1) + *(.rodata.bf_abort.str1.1) + *(.rodata.nmi_abort.str1.1) + *(.rodata.abort_screen.str1.1) + *(.rodata._ZL5table*) + *(.rodata._ZL15glyphDataOffset*) + *(.rodata._ZL11KDPointZero*) + *(.rodata._ZL9glyphData*) + *(.rodata._ZN4CodeL14HighlightColorE*) + *(.rodata._ZTV12KDIonContext) + *(.rodata._ZTV16KDRealIonContext) + *(.rodata._ZTV24KDPostProcessZoomContext) + *(.rodata._ZTV25KDPostProcessGammaContext) + *(.rodata._ZTV26KDPostProcessInvertContext) + *(.rodata.bp) + *(.rodata.dp_h) + *(.rodata.dp_l) + *(.rodata._ZN11MicroPython5Color5ParseEPvNS0_4ModeE*) + *(.rodata._ZN9Clipboard10storedTextEv*) + *(.rodata._ZN8Sequence14ListController27toolboxForInputEventHandlerEP17InputEventHandler*) + *(.rodata._ZN8Sequence23TypeParameterController25willDisplayCellAtLocationEP13HighlightCellii*) + *(.rodata._ZN6KDFont16privateSmallFontE) + *(.rodata._ZN4I18nL23CountryPreferencesArrayE) + *(.rodata.abort_sleeping.str1.1) + *(.rodata.abort_core.str1.1) + *(.rodata.dfu_bootloader) + *(.rodata) } >INTERNAL_FLASH .exam_mode_buffer ORIGIN(EXTERNAL_FLASH) : { diff --git a/ion/src/device/shared/boot/isr.c b/ion/src/device/shared/boot/isr.c index 5c201aa67..2ebde5c64 100644 --- a/ion/src/device/shared/boot/isr.c +++ b/ion/src/device/shared/boot/isr.c @@ -18,11 +18,11 @@ ISR InitialisationVector[INITIALISATION_VECTOR_SIZE] = { (ISR)&_stack_start, // Stack start start, // Reset service routine, - 0, // NMI service routine, + nmi_abort, // NMI service routine, abort, // HardFault service routine, 0, // MemManage service routine, - 0, // BusFault service routine, - 0, // UsageFault service routine, + bf_abort, // BusFault service routine, + uf_abort, // UsageFault service routine, 0, 0, 0, 0, // Reserved 0, // SVCall service routine, 0, // DebugMonitor service routine, diff --git a/ion/src/device/shared/boot/isr.h b/ion/src/device/shared/boot/isr.h index ca5becb13..be46adee9 100644 --- a/ion/src/device/shared/boot/isr.h +++ b/ion/src/device/shared/boot/isr.h @@ -5,6 +5,14 @@ extern "C" { #endif +void bf_abort(); +void uf_abort(); +void nmi_abort(); +void abort_init(); +void abort_core(const char *); +void abort_sleeping(); +void abort_economy(); +void abort_screen(const char *); void start(); void abort(); void isr_systick(); diff --git a/ion/src/device/shared/boot/rt0.cpp b/ion/src/device/shared/boot/rt0.cpp index 4cb671496..6444117f0 100644 --- a/ion/src/device/shared/boot/rt0.cpp +++ b/ion/src/device/shared/boot/rt0.cpp @@ -1,45 +1,52 @@ -#include "isr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include + #include "../drivers/board.h" -#include "../drivers/rtc.h" #include "../drivers/reset.h" +#include "../drivers/rtc.h" #include "../drivers/timing.h" +#include "isr.h" typedef void (*cxx_constructor)(); extern "C" { - extern char _data_section_start_flash; - extern char _data_section_start_ram; - extern char _data_section_end_ram; - extern char _bss_section_start_ram; - extern char _bss_section_end_ram; - extern cxx_constructor _init_array_start; - extern cxx_constructor _init_array_end; -} - -void __attribute__((noinline)) abort() { -#ifdef NDEBUG - Ion::Device::Reset::core(); -#else - while (1) { - } -#endif +extern char _data_section_start_flash; +extern char _data_section_start_ram; +extern char _data_section_end_ram; +extern char _bss_section_start_ram; +extern char _bss_section_end_ram; +extern cxx_constructor _init_array_start; +extern cxx_constructor _init_array_end; } /* In order to ensure that this method is execute from the external flash, we * forbid inlining it.*/ static void __attribute__((noinline)) external_flash_start() { - /* Init the peripherals. We do not initialize the backlight in case there is + /* Init the peripherals. We do not initialize the backlight in case there is * an on boarding app: indeed, we don't want the user to see the LCD tests * happening during the on boarding app. The backlight will be initialized * after the Power-On Self-Test if there is one or before switching to the * home app otherwise. */ - Ion::Device::Board::initPeripherals(false); - - return ion_main(0, nullptr); + Ion::Device::Board::initPeripherals(false); + return ion_main(0, nullptr); } /* This additional function call 'jump_to_external_flash' serves two purposes: @@ -61,7 +68,155 @@ static void __attribute__((noinline)) external_flash_start() { * internal flash to the external flash. */ static void __attribute__((noinline)) jump_to_external_flash() { - external_flash_start(); + external_flash_start(); +} + +void __attribute__((noinline)) abort_init() { + Ion::Device::Board::shutdownPeripherals(true); + Ion::Device::Board::initPeripherals(false); + Ion::Timing::msleep(100); + Ion::Backlight::init(); + Ion::LED::setColor(KDColorRed); + Ion::Backlight::setBrightness(180); +} + +void __attribute__((noinline)) abort_economy() { + int brightness = Ion::Backlight::brightness(); + bool plugged = Ion::USB::isPlugged(); + while (brightness > 0) { + brightness--; + Ion::Backlight::setBrightness(brightness); + Ion::Timing::msleep(50); + if(plugged || (!plugged && Ion::USB::isPlugged())){ + Ion::Backlight::setBrightness(180); + return; + } + } + Ion::Backlight::shutdown(); + while (1) { + Ion::Device::Power::sleepConfiguration(); + Ion::Device::WakeUp::onUSBPlugging(); + Ion::Device::WakeUp::onChargingEvent(); + Ion::Device::Power::internalFlashSuspend(true); + if (!plugged && Ion::USB::isPlugged()) { + break; + } + plugged = Ion::USB::isPlugged(); + }; + Ion::Device::Board::setStandardFrequency(Ion::Device::Board::Frequency::High); + Ion::Backlight::init(); + Ion::Backlight::setBrightness(180); +} + +void __attribute__((noinline)) abort_sleeping() { + if (Ion::Battery::level() != Ion::Battery::Charge::EMPTY) { + return; + } + // we don't use Ion::Power::suspend because we don't want to move the exam buffer into the internal + Ion::Device::Board::shutdownPeripherals(true); + bool plugged = Ion::USB::isPlugged(); + while (1) { + Ion::Device::Battery::initGPIO(); + Ion::Device::USB::initGPIO(); + Ion::Device::LED::init(); + Ion::Device::Power::sleepConfiguration(); + Ion::Device::Board::shutdownPeripherals(true); + Ion::Device::WakeUp::onUSBPlugging(); + Ion::Device::WakeUp::onChargingEvent(); + Ion::Device::Power::internalFlashSuspend(true); + Ion::Device::USB::initGPIO(); + if (!plugged && Ion::USB::isPlugged()) { + break; + } + plugged = Ion::USB::isPlugged(); + } + Ion::Device::Board::setStandardFrequency(Ion::Device::Board::Frequency::High); + abort_init(); +} + +void __attribute__((noinline)) abort_core(const char * text) { + Ion::Timing::msleep(100); + int counting; + while (true) { + counting = 0; + if (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) { + abort_sleeping(); + abort_screen(text); + } + + Ion::USB::enable(); + Ion::Battery::Charge previous_state = Ion::Battery::level(); + while (!Ion::USB::isEnumerated()) { + if (Ion::Battery::level() == Ion::Battery::Charge::LOW) { + if (previous_state != Ion::Battery::Charge::LOW) { + previous_state = Ion::Battery::Charge::LOW; + counting = 0; + } + Ion::Timing::msleep(500); + if (counting >= 20) { + abort_sleeping(); + abort_screen(text); + counting = -1; + } + counting++; + + } else { + if (previous_state == Ion::Battery::Charge::LOW) { + previous_state = Ion::Battery::level(); + counting = 0; + } + Ion::Timing::msleep(100); + if (counting >= 300) { + abort_economy(); + counting = -1; + } + counting++; + } + } + Ion::USB::DFU(false, false, 0); + } +} + +void __attribute__((noinline)) abort_screen(const char * text){ + KDRect screen = KDRect(0, 0, Ion::Display::Width, Ion::Display::Height); + Ion::Display::pushRectUniform(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), KDColor::RGB24(0xffffff)); + KDContext* ctx = KDIonContext::sharedContext(); + ctx->setOrigin(KDPointZero); + ctx->setClippingRect(screen); + ctx->drawString("UPSILON CRASH", KDPoint(90, 10), KDFont::LargeFont, KDColorRed, KDColor::RGB24(0xffffff)); + ctx->drawString("An error occurred", KDPoint(10, 30), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("If you have some important data, please", KDPoint(10, 45), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("use bit.ly/upsiBackup to backup them.", KDPoint(10, 60), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("YOU WILL LOSE ALL YOUR DATA", KDPoint(10, 85), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("→ You can try to reboot by presssing the", KDPoint(10, 110), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("reset button at the back of the calculator", KDPoint(10, 125), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("→ If Upsilon keeps crashing, you can connect", KDPoint(10, 140), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("the calculator to a computer or a phone", KDPoint(10, 160), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString("and try to reinstall Upsilon", KDPoint(10, 175), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff)); + ctx->drawString(text, KDPoint(220, 200), KDFont::SmallFont, KDColorRed, KDColor::RGB24(0xffffff)); +} + +void __attribute__((noinline)) abort() { + abort_init(); + abort_screen("HARDFAULT"); + abort_core("HARDFAULT"); +} + +void __attribute__((noinline)) nmi_abort() { + abort_init(); + abort_screen("NMIFAULT"); + abort_core("NMIFAULT"); +} + +void __attribute__((noinline)) bf_abort() { + abort_init(); + abort_screen("BUSFAULT"); + abort_core("BUSFAULT"); +} +void __attribute__((noinline)) uf_abort() { + abort_init(); + abort_screen("USAGEFAULT"); + abort_core("USAGEFAULT"); } /* When 'start' is executed, the external flash is supposed to be shutdown. We @@ -69,27 +224,27 @@ static void __attribute__((noinline)) jump_to_external_flash() { * (just in case 'start' was to be called from the external flash). */ void __attribute__((noinline)) start() { - /* This is where execution starts after reset. + /* This is where execution starts after reset. * Many things are not initialized yet so the code here has to pay attention. */ - /* Copy data section to RAM + /* Copy data section to RAM * The data section is R/W but its initialization value matters. It's stored * in Flash, but linked as if it were in RAM. Now's our opportunity to copy * it. Note that until then the data section (e.g. global variables) contains * garbage values and should not be used. */ - size_t dataSectionLength = (&_data_section_end_ram - &_data_section_start_ram); - memcpy(&_data_section_start_ram, &_data_section_start_flash, dataSectionLength); + size_t dataSectionLength = (&_data_section_end_ram - &_data_section_start_ram); + memcpy(&_data_section_start_ram, &_data_section_start_flash, dataSectionLength); - /* Zero-out the bss section in RAM + /* Zero-out the bss section in RAM * Until we do, any uninitialized global variable will be unusable. */ - size_t bssSectionLength = (&_bss_section_end_ram - &_bss_section_start_ram); - memset(&_bss_section_start_ram, 0, bssSectionLength); + size_t bssSectionLength = (&_bss_section_end_ram - &_bss_section_start_ram); + memset(&_bss_section_start_ram, 0, bssSectionLength); - /* Initialize the FPU as early as possible. + /* Initialize the FPU as early as possible. * For example, static C++ objects are very likely to manipulate float values */ - Ion::Device::Board::initFPU(); + Ion::Device::Board::initFPU(); - /* Call static C++ object constructors + /* Call static C++ object constructors * The C++ compiler creates an initialization function for each static object. * The linker then stores the address of each of those functions consecutively * between _init_array_start and _init_array_end. So to initialize all C++ @@ -97,30 +252,30 @@ void __attribute__((noinline)) start() { * call the pointed function. */ #define SUPPORT_CPP_GLOBAL_CONSTRUCTORS 0 #if SUPPORT_CPP_GLOBAL_CONSTRUCTORS - for (cxx_constructor * c = &_init_array_start; c<&_init_array_end; c++) { - (*c)(); - } + for (cxx_constructor* c = &_init_array_start; c < &_init_array_end; c++) { + (*c)(); + } #else - /* In practice, static initialized objects are a terrible idea. Since the init + /* In practice, static initialized objects are a terrible idea. Since the init * order is not specified, most often than not this yields the dreaded static * init order fiasco. How about bypassing the issue altogether? */ - if (&_init_array_start != &_init_array_end) { - abort(); - } + if (&_init_array_start != &_init_array_end) { + abort(); + } #endif - Ion::Device::Board::init(); + Ion::Device::Board::init(); - /* At this point, we initialized clocks and the external flash but no other + /* At this point, we initialized clocks and the external flash but no other * peripherals. */ - jump_to_external_flash(); + jump_to_external_flash(); - abort(); + abort(); } void __attribute__((interrupt, noinline)) isr_systick() { - auto t = Ion::Device::Timing::MillisElapsed; - t++; - Ion::Device::Timing::MillisElapsed = t; + auto t = Ion::Device::Timing::MillisElapsed; + t++; + Ion::Device::Timing::MillisElapsed = t; } diff --git a/ion/src/device/shared/usb/calculator.cpp b/ion/src/device/shared/usb/calculator.cpp index 73d6bf579..4d3818601 100644 --- a/ion/src/device/shared/usb/calculator.cpp +++ b/ion/src/device/shared/usb/calculator.cpp @@ -7,10 +7,11 @@ namespace Ion { namespace Device { namespace USB { -void Calculator::PollAndReset(bool exitWithKeyboard) { +void Calculator::PollAndReset(bool exitWithKeyboard, bool unlock, int level) { char serialNumber[Ion::Device::SerialNumber::Length+1]; Ion::Device::SerialNumber::copy(serialNumber); Calculator c(serialNumber); + /* Leave DFU mode if the Back key is pressed, the calculator unplugged or the * USB core soft-disconnected. */ @@ -19,6 +20,10 @@ void Calculator::PollAndReset(bool exitWithKeyboard) { uint8_t exitKeyColumn = Ion::Device::Keyboard::columnForKey(exitKey); Ion::Device::Keyboard::activateRow(exitKeyRow); + c.m_dfuInterface.setLevel(level); + if (unlock) { + c.m_dfuInterface.unlockDfu(); + } while (!(exitWithKeyboard && !c.isErasingAndWriting() && Ion::Device::Keyboard::columnIsActive(exitKeyColumn)) && Ion::USB::isPlugged() && diff --git a/ion/src/device/shared/usb/calculator.h b/ion/src/device/shared/usb/calculator.h index cf083860c..bf0a04db4 100644 --- a/ion/src/device/shared/usb/calculator.h +++ b/ion/src/device/shared/usb/calculator.h @@ -25,7 +25,7 @@ namespace USB { class Calculator : public Device { public: - static void PollAndReset(bool exitWithKeyboard) + static void PollAndReset(bool exitWithKeyboard, bool unlocked, int level) __attribute__((section(".dfu_entry_point"))) // Needed to pinpoint this symbol in the linker script __attribute__((used)) // Make sure this symbol is not discarded at link time ; // Return true if reset is needed diff --git a/ion/src/device/shared/usb/dfu_interface.cpp b/ion/src/device/shared/usb/dfu_interface.cpp index 2b98274b4..69370c0cb 100644 --- a/ion/src/device/shared/usb/dfu_interface.cpp +++ b/ion/src/device/shared/usb/dfu_interface.cpp @@ -1,286 +1,518 @@ -#include "dfu_interface.h" -#include -#include -#include - -namespace Ion { -namespace Device { -namespace USB { - -static inline uint32_t minUint32T(uint32_t x, uint32_t y) { return x < y ? x : y; } - -void DFUInterface::StatusData::push(Channel * c) const { - c->push(m_bStatus); - c->push(m_bwPollTimeout[2]); - c->push(m_bwPollTimeout[1]); - c->push(m_bwPollTimeout[0]); - c->push(m_bState); - c->push(m_iString); -} - -void DFUInterface::StateData::push(Channel * c) const { - c->push(m_bState); -} - -void DFUInterface::wholeDataReceivedCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) { - if (request->bRequest() == (uint8_t) DFURequest::Download) { - // Handle a download request - if (request->wValue() == 0) { - // The request is a special command - switch (transferBuffer[0]) { - case (uint8_t) DFUDownloadCommand::SetAddressPointer: - setAddressPointerCommand(request, transferBuffer, *transferBufferLength); - return; - case (uint8_t) DFUDownloadCommand::Erase: - eraseCommand(transferBuffer, *transferBufferLength); - return; - default: - m_state = State::dfuERROR; - m_status = Status::errSTALLEDPKT; - return; - } - } - if (request->wValue() == 1) { - m_ep0->stallTransaction(); - return; - } - if (request->wLength() > 0) { - // The request is a "real" download. Compute the writing address. - m_writeAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer; - // Store the received data until we copy it on the flash. - memcpy(m_largeBuffer, transferBuffer, *transferBufferLength); - m_largeBufferLength = *transferBufferLength; - m_state = State::dfuDNLOADSYNC; - } - } -} - -void DFUInterface::wholeDataSentCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) { - if (request->bRequest() == (uint8_t) DFURequest::GetStatus) { - // Do any needed action after the GetStatus request. - if (m_state == State::dfuMANIFEST) { - /* If we leave the DFU and reset immediately, dfu-util outputs an error: - * "File downloaded successfully - * dfu-util: Error during download get_status" - * If we sleep 1us here, there is no error. We put 1ms for security. - * This error might be due to the USB connection being cut too soon after - * the last USB exchange, so the host does not have time to process the - * answer received for the last GetStatus request. */ - Ion::Timing::msleep(1); - // Leave DFU routine: Leave DFU, reset device, jump to application code - leaveDFUAndReset(); - } else if (m_state == State::dfuDNBUSY) { - if (m_largeBufferLength != 0) { - // Here, copy the data from the transfer buffer to the flash memory - writeOnMemory(); - } - changeAddressPointerIfNeeded(); - eraseMemoryIfNeeded(); - m_state = State::dfuDNLOADIDLE; - } - } -} - -bool DFUInterface::processSetupInRequest(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) { - if (Interface::processSetupInRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength)) { - return true; - } - switch (request->bRequest()) { - case (uint8_t) DFURequest::Detach: - m_device->detach(); - return true; - case (uint8_t) DFURequest::Download: - return processDownloadRequest(request->wLength(), transferBufferLength); - case (uint8_t) DFURequest::Upload: - return processUploadRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength); - case (uint8_t) DFURequest::GetStatus: - return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); - case (uint8_t) DFURequest::ClearStatus: - return clearStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); - case (uint8_t) DFURequest::GetState: - return getState(transferBuffer, transferBufferLength, transferBufferMaxLength); - case (uint8_t) DFURequest::Abort: - return dfuAbort(transferBufferLength); - } - return false; -} - -bool DFUInterface::processDownloadRequest(uint16_t wLength, uint16_t * transferBufferLength) { - if (m_state != State::dfuIDLE && m_state != State::dfuDNLOADIDLE) { - m_state = State::dfuERROR; - m_status = Status::errNOTDONE; - m_ep0->stallTransaction(); - return false; - } - if (wLength == 0) { - // Leave DFU routine: Reset the device and jump to application code - m_state = State::dfuMANIFESTSYNC; - } else { - // Prepare to receive the download data - m_ep0->clearForOutTransactions(wLength); - m_state = State::dfuDNLOADSYNC; - } - return true; -} - -bool DFUInterface::processUploadRequest(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) { - if (m_state != State::dfuIDLE && m_state != State::dfuUPLOADIDLE) { - m_ep0->stallTransaction(); - return false; - } - if (request->wValue() == 0) { - /* The host requests to read the commands supported by the bootloader. After - * receiving this command, the device should returns N bytes representing - * the command codes for : - * Get command / Set Address Pointer / Erase / Read Unprotect - * We no not need it for now. */ - return false; - } else if (request->wValue() == 1) { - m_ep0->stallTransaction(); - return false; - } else { - /* We decided to never protect Read operation. Else we would have to check - * here it is not protected before reading. */ - - // Compute the reading address - uint32_t readAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer; - // Copy the requested memory zone into the transfer buffer. - uint16_t copySize = minUint32T(transferBufferMaxLength, request->wLength()); - memcpy(transferBuffer, (void *)readAddress, copySize); - *transferBufferLength = copySize; - } - m_state = State::dfuUPLOADIDLE; - return true; -} - -void DFUInterface::setAddressPointerCommand(SetupPacket * request, uint8_t * transferBuffer, uint16_t transferBufferLength) { - assert(transferBufferLength == 5); - // Compute the new address but change it after the next getStatus request. - m_potentialNewAddressPointer = transferBuffer[1] - + (transferBuffer[2] << 8) - + (transferBuffer[3] << 16) - + (transferBuffer[4] << 24); - m_state = State::dfuDNLOADSYNC; -} - -void DFUInterface::changeAddressPointerIfNeeded() { - if (m_potentialNewAddressPointer == 0) { - // There was no address change waiting. - return; - } - // If there is a new address pointer waiting, change the pointer address. - m_addressPointer = m_potentialNewAddressPointer; - m_potentialNewAddressPointer = 0; - m_state = State::dfuDNLOADIDLE; - m_status = Status::OK; -} - -void DFUInterface::eraseCommand(uint8_t * transferBuffer, uint16_t transferBufferLength) { - /* We determine whether the commands asks for a mass erase or which sector to - * erase. The erase must be done after the next getStatus request. */ - m_state = State::dfuDNLOADSYNC; - - if (transferBufferLength == 1) { - // Mass erase - m_erasePage = Flash::TotalNumberOfSectors(); - return; - } - - // Sector erase - assert(transferBufferLength == 5); - - uint32_t eraseAddress = transferBuffer[1] - + (transferBuffer[2] << 8) - + (transferBuffer[3] << 16) - + (transferBuffer[4] << 24); - - m_erasePage = Flash::SectorAtAddress(eraseAddress); - if (m_erasePage < 0) { - // Unrecognized sector - m_state = State::dfuERROR; - m_status = Status::errTARGET; - } -} - - -void DFUInterface::eraseMemoryIfNeeded() { - if (m_erasePage < 0) { - // There was no erase waiting. - return; - } - - willErase(); - if (m_erasePage == Flash::TotalNumberOfSectors()) { - Flash::MassErase(); - } else { - Flash::EraseSector(m_erasePage); - } - - /* Put an out of range value in m_erasePage to indicate that no erase is - * waiting. */ - m_erasePage = -1; - m_state = State::dfuDNLOADIDLE; - m_status = Status::OK; -} - -void DFUInterface::writeOnMemory() { - if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) { - // Write on SRAM - // FIXME We should check that we are not overriding the current instructions. - memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength); - } else if (Flash::SectorAtAddress(m_writeAddress) >= 0) { - Flash::WriteMemory(reinterpret_cast(m_writeAddress), m_largeBuffer, m_largeBufferLength); - } else { - // Invalid write address - m_largeBufferLength = 0; - m_state = State::dfuERROR; - m_status = Status::errTARGET; - return; - } - - // Reset the buffer length - m_largeBufferLength = 0; - // Change the interface state and status - m_state = State::dfuDNLOADIDLE; - m_status = Status::OK; -} - - -bool DFUInterface::getStatus(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) { - // Change the status if needed - if (m_state == State::dfuMANIFESTSYNC) { - m_state = State::dfuMANIFEST; - } else if (m_state == State::dfuDNLOADSYNC) { - m_state = State::dfuDNBUSY; - } - // Copy the status on the TxFifo - *transferBufferLength = StatusData(m_status, m_state).copy(transferBuffer, transferBufferMaxLength); - return true; -} - -bool DFUInterface::clearStatus(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) { - m_status = Status::OK; - m_state = State::dfuIDLE; - return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); -} - -bool DFUInterface::getState(uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t maxSize) { - *transferBufferLength = StateData(m_state).copy(transferBuffer, maxSize); - return true; -} - -bool DFUInterface::dfuAbort(uint16_t * transferBufferLength) { - m_status = Status::OK; - m_state = State::dfuIDLE; - *transferBufferLength = 0; - return true; -} - -void DFUInterface::leaveDFUAndReset() { - m_device->setResetOnDisconnect(true); - m_device->detach(); -} - -} -} -} + +#include "dfu_interface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace Ion { +namespace Device { +namespace USB { + +static inline uint32_t minUint32T(uint32_t x, uint32_t y) { return x < y ? x : y; } + +void DFUInterface::StatusData::push(Channel *c) const { + c->push(m_bStatus); + c->push(m_bwPollTimeout[2]); + c->push(m_bwPollTimeout[1]); + c->push(m_bwPollTimeout[0]); + c->push(m_bState); + c->push(m_iString); +} + +void DFUInterface::StateData::push(Channel *c) const { + c->push(m_bState); +} + +void DFUInterface::wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) { + if (request->bRequest() == (uint8_t)DFURequest::Download) { + // Handle a download request + if (request->wValue() == 0) { + // The request is a special command + switch (transferBuffer[0]) { + case (uint8_t)DFUDownloadCommand::SetAddressPointer: + setAddressPointerCommand(request, transferBuffer, *transferBufferLength); + return; + case (uint8_t)DFUDownloadCommand::Erase: + eraseCommand(transferBuffer, *transferBufferLength); + return; + default: + m_state = State::dfuERROR; + m_status = Status::errSTALLEDPKT; + return; + } + } + if (request->wValue() == 1) { + m_ep0->stallTransaction(); + return; + } + if (request->wLength() > 0) { + // The request is a "real" download. Compute the writing address. + m_writeAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer; + + // Store the received data until we copy it on the flash. + memcpy(m_largeBuffer, transferBuffer, *transferBufferLength); + m_largeBufferLength = *transferBufferLength; + m_state = State::dfuDNLOADSYNC; + } + } +} + +void DFUInterface::wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) { + if (request->bRequest() == (uint8_t)DFURequest::GetStatus) { + // Do any needed action after the GetStatus request. + if (m_state == State::dfuMANIFEST) { + if (m_dfuLevel == 1 && m_isFirstExternalFlash && !m_isInternalLocked) { + return; + } + /* If we leave the DFU and reset immediately, dfu-util outputs an error: + * "File downloaded successfully + * dfu-util: Error during download get_status" + * If we sleep 1us here, there is no error. We put 1ms for security. + * This error might be due to the USB connection being cut too soon after + * the last USB exchange, so the host does not have time to process the + * answer received for the last GetStatus request. */ + Ion::Timing::msleep(1); + // Leave DFU routine: Leave DFU, reset device, jump to application code + leaveDFUAndReset(); + } else if (m_state == State::dfuDNBUSY) { + m_state = State::dfuDNBUSY; + if (m_largeBufferLength != 0) { + // Here, copy the data from the transfer buffer to the flash memory + writeOnMemory(); + } + changeAddressPointerIfNeeded(); + eraseMemoryIfNeeded(); + m_state = State::dfuDNLOADIDLE; + } + } +} + +bool DFUInterface::processSetupInRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) { + if (Interface::processSetupInRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength)) { + return true; + } + switch (request->bRequest()) { + case (uint8_t)DFURequest::Detach: + m_device->detach(); + return true; + case (uint8_t)DFURequest::Download: + return processDownloadRequest(request->wLength(), transferBufferLength); + case (uint8_t)DFURequest::Upload: + return processUploadRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength); + case (uint8_t)DFURequest::GetStatus: + return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); + case (uint8_t)DFURequest::ClearStatus: + return clearStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); + case (uint8_t)DFURequest::GetState: + return getState(transferBuffer, transferBufferLength, transferBufferMaxLength); + case (uint8_t)DFURequest::Abort: + return dfuAbort(transferBufferLength); + } + return false; +} + +bool DFUInterface::processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength) { + if (m_state != State::dfuIDLE && m_state != State::dfuDNLOADIDLE) { + m_state = State::dfuERROR; + m_status = Status::errNOTDONE; + m_ep0->stallTransaction(); + return false; + } + if (wLength == 0) { + // Leave DFU routine: Reset the device and jump to application code + m_state = State::dfuMANIFESTSYNC; + } else { + // Prepare to receive the download data + m_ep0->clearForOutTransactions(wLength); + m_state = State::dfuDNLOADSYNC; + } + return true; +} + +bool DFUInterface::processUploadRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) { + if (m_state != State::dfuIDLE && m_state != State::dfuUPLOADIDLE) { + m_ep0->stallTransaction(); + return false; + } + if (request->wValue() == 0) { + /* The host requests to read the commands supported by the bootloader. After + * receiving this command, the device should returns N bytes representing + * the command codes for : + * Get command / Set Address Pointer / Erase / Read Unprotect + * We no not need it for now. */ + return false; + } else if (request->wValue() == 1) { + m_ep0->stallTransaction(); + return false; + } else { + /* We decided to never protect Read operation. Else we would have to check + * here it is not protected before reading. */ + + // Compute the reading address + uint32_t readAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer; + // Copy the requested memory zone into the transfer buffer. + uint16_t copySize = minUint32T(transferBufferMaxLength, request->wLength()); + memcpy(transferBuffer, (void *)readAddress, copySize); + *transferBufferLength = copySize; + } + m_state = State::dfuUPLOADIDLE; + return true; +} + +void DFUInterface::setAddressPointerCommand(SetupPacket *request, uint8_t *transferBuffer, uint16_t transferBufferLength) { + assert(transferBufferLength == 5); + // Compute the new address but change it after the next getStatus request. + m_potentialNewAddressPointer = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24); + m_state = State::dfuDNLOADSYNC; +} + +void DFUInterface::changeAddressPointerIfNeeded() { + if (m_potentialNewAddressPointer == 0) { + // There was no address change waiting. + return; + } + // If there is a new address pointer waiting, change the pointer address. + m_addressPointer = m_potentialNewAddressPointer; + m_potentialNewAddressPointer = 0; + m_state = State::dfuDNLOADIDLE; + m_status = Status::OK; +} + +void DFUInterface::eraseCommand(uint8_t *transferBuffer, uint16_t transferBufferLength) { + /* We determine whether the commands asks for a mass erase or which sector to + * erase. The erase must be done after the next getStatus request. */ + m_state = State::dfuDNLOADSYNC; + + if (transferBufferLength == 1) { + // Mass erase + m_erasePage = Flash::TotalNumberOfSectors(); + return; + } + + // Sector erase + assert(transferBufferLength == 5); + + m_eraseAddress = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24); + + m_erasePage = Flash::SectorAtAddress(m_eraseAddress); + if (m_erasePage < 0) { + // Unrecognized sector + m_state = State::dfuERROR; + m_status = Status::errTARGET; + } +} + +void DFUInterface::eraseMemoryIfNeeded() { + if (m_erasePage < 0) { + return; + } + willErase(); + if ((m_eraseAddress >= k_ExternalBorderAddress && m_eraseAddress < ExternalFlash::Config::EndAddress) || m_dfuUnlocked) { + int32_t order = Flash::SectorAtAddress(m_eraseAddress); + Flash::EraseSector(order); + } + m_state = State::dfuDNLOADIDLE; + m_status = Status::OK; + m_erasePage = -1; +} + +void DFUInterface::writeOnMemory() { + if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) { + // Write on SRAM + // FIXME We should check that we are not overriding the current instructions. + memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength); + reset_custom_vars(); // On reset les vars car la ram n'a pas de secteur à effacer + } else if (Flash::SectorAtAddress(m_writeAddress) >= 0) { + if (m_dfuLevel == 2) { + m_largeBufferLength = 0; + m_state = State::dfuERROR; + m_status = Status::errWRITE; + return; + } + + int current_memory_flashed; + if (m_writeAddress >= InternalFlash::Config::StartAddress && m_writeAddress <= InternalFlash::Config::EndAddress) { + if (m_isInternalLocked && !m_dfuUnlocked) // On vérifie si l'external a été flash + { + m_largeBufferLength = 0; + m_state = State::dfuERROR; + m_status = Status::errTARGET; + leaveDFUAndReset(false); // Numworks flash l'internal avant donc on exit pour afficher le message + return; + } + current_memory_flashed = 0; + + //on écrit dans la mémoire interne + if (m_isFirstInternalFlash && !m_dfuUnlocked) { + m_temp_is_valid = true; + for (int i = 0; i < 4; i++) { + if (magik[i] != m_largeBuffer[magik_adrs + i]) { + m_temp_is_valid = false; + break; + } + } + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + m_state = State::dfuERROR; + m_status = Status::errVERIFY; + //leaveDFUAndReset(); On ne leave plus sinon on fait crash la calc si il n'y a que la partie ext. + return; + } else { + m_isFirstInternalFlash = false; + } + } + } else { + current_memory_flashed = 1; + // Nous écrivons la partie external os + if (m_writeAddress < k_ExternalBorderAddress && m_isFirstExternalFlash && !m_dfuUnlocked) // On vérifie si on installe des apps ext + { + // if (m_dfuLevel == 1 && m_isInternalLocked) { + // m_largeBufferLength = 0; + // m_state = State::dfuERROR; + // m_status = Status::errTARGET; + // return; + // } + if (m_dfuLevel == 0) { + // Partie moche du code parce que je n'arrivais pas à compil avec 3 boucles for sous msys + int adress_magik = magik_ext_adrs[0]; + m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik]; + m_largeBuffer[adress_magik] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1]; + m_largeBuffer[adress_magik + 1] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2]; + m_largeBuffer[adress_magik + 2] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3]; + m_largeBuffer[adress_magik + 3] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + adress_magik = magik_ext_adrs[1]; + + m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik]; + m_largeBuffer[adress_magik] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 1]; + m_largeBuffer[adress_magik + 1] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 2]; + m_largeBuffer[adress_magik + 2] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 3]; + m_largeBuffer[adress_magik + 3] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + adress_magik = magik_ext_adrs[2]; + m_temp_is_valid = true; + + m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik]; + m_largeBuffer[adress_magik] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1]; + m_largeBuffer[adress_magik + 1] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2]; + m_largeBuffer[adress_magik + 2] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3]; + m_largeBuffer[adress_magik + 3] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + + m_temp_is_valid = external_magik[4] == m_largeBuffer[adress_magik + 4]; + m_largeBuffer[adress_magik + 4] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik + 5]; + m_largeBuffer[adress_magik + 5] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 6]; + m_largeBuffer[adress_magik + 6] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 7]; + m_largeBuffer[adress_magik + 7] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } + m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 8]; + m_largeBuffer[adress_magik + 8] = 0xff; + + if (!m_temp_is_valid) { + m_largeBufferLength = 0; + leaveDFUAndReset(false); + return; + } else { + m_isFirstExternalFlash = false; + m_isInternalLocked = false; + } + } else { + m_isFirstExternalFlash = false; + m_isInternalLocked = false; + } + } + } + if (m_last_memoryFlashed >= 0 && current_memory_flashed != m_last_memoryFlashed) { + m_last_memoryFlashed = -1; + } + + m_erasePage = Flash::SectorAtAddress(m_writeAddress); + + //On vérifie qu'on a pas déjà effacé le secteur et si ce n'est pas un secteur external déjà effacé + if ((m_last_memoryFlashed < 0 || m_erasePage != m_lastPageErased) && m_writeAddress < k_ExternalBorderAddress && !m_dfuUnlocked) { + Flash::EraseSector(m_erasePage); + m_last_memoryFlashed = current_memory_flashed; + } + + m_lastPageErased = m_erasePage; + m_erasePage = -1; + + Ion::Timing::msleep(1); + Flash::WriteMemory(reinterpret_cast(m_writeAddress), m_largeBuffer, m_largeBufferLength); + } else { + // Invalid write address + m_largeBufferLength = 0; + m_state = State::dfuERROR; + m_status = Status::errTARGET; + return; + } + // Reset the buffer length + m_largeBufferLength = 0; + // Change the interface state and status + m_state = State::dfuDNLOADIDLE; + m_status = Status::OK; +} + +bool DFUInterface::getStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) { + // Change the status if needed + if (m_state == State::dfuMANIFESTSYNC) { + m_state = State::dfuMANIFEST; + } else if (m_state == State::dfuDNLOADSYNC) { + m_state = State::dfuDNBUSY; + } + // Copy the status on the TxFifo + *transferBufferLength = StatusData(m_status, m_state).copy(transferBuffer, transferBufferMaxLength); + return true; +} + +bool DFUInterface::clearStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) { + m_status = Status::OK; + m_state = State::dfuIDLE; + return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength); +} + +bool DFUInterface::getState(uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t maxSize) { + *transferBufferLength = StateData(m_state).copy(transferBuffer, maxSize); + return true; +} + +bool DFUInterface::dfuAbort(uint16_t *transferBufferLength) { + m_status = Status::OK; + m_state = State::dfuIDLE; + *transferBufferLength = 0; + return true; +} + +void DFUInterface::leaveDFUAndReset(bool do_reset) { + reset_custom_vars(); + m_isInternalLocked = true; + m_isFirstInternalFlash = true; + m_isFirstExternalFlash = true; + m_device->setResetOnDisconnect(do_reset); + m_device->detach(); +} + +} // namespace USB +} // namespace Device +} // namespace Ion diff --git a/ion/src/device/shared/usb/dfu_interface.h b/ion/src/device/shared/usb/dfu_interface.h index 0ae25d874..7d4ce8a7d 100644 --- a/ion/src/device/shared/usb/dfu_interface.h +++ b/ion/src/device/shared/usb/dfu_interface.h @@ -8,173 +8,217 @@ #include "stack/endpoint0.h" #include "stack/setup_packet.h" #include "stack/streamable.h" +#include +#include -namespace Ion { -namespace Device { -namespace USB { - -class DFUInterface : public Interface { - -public: - DFUInterface(Device * device, Endpoint0 * ep0, uint8_t bInterfaceAlternateSetting) : - Interface(ep0), - m_device(device), - m_status(Status::OK), - m_state(State::dfuIDLE), - m_addressPointer(0), - m_potentialNewAddressPointer(0), - m_erasePage(-1), - m_largeBuffer{0}, - m_largeBufferLength(0), - m_writeAddress(0), - m_bInterfaceAlternateSetting(bInterfaceAlternateSetting), - m_isErasingAndWriting(false) +namespace Ion +{ + namespace Device { - } - uint32_t addressPointer() const { return m_addressPointer; } - void wholeDataReceivedCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) override; - void wholeDataSentCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) override; - bool isErasingAndWriting() const { return m_isErasingAndWriting; } - -protected: - void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override { - assert(interfaceAlternativeIndex == m_bInterfaceAlternateSetting); - } - uint8_t getActiveInterfaceAlternative() override { - return m_bInterfaceAlternateSetting; - } - bool processSetupInRequest(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) override; - -private: - // DFU Request Codes - enum class DFURequest { - Detach = 0, - Download = 1, - Upload = 2, - GetStatus = 3, - ClearStatus = 4, - GetState = 5, - Abort = 6 - }; - - // DFU Download Commmand Codes - enum class DFUDownloadCommand { - GetCommand = 0x00, - SetAddressPointer = 0x21, - Erase = 0x41, - ReadUnprotect = 0x92 - }; - - enum class Status : uint8_t { - OK = 0x00, - errTARGET = 0x01, - errFILE = 0x02, - errWRITE = 0x03, - errERASE = 0x04, - errCHECK_ERASED = 0x05, - errPROG = 0x06, - errVERIFY = 0x07, - errADDRESS = 0x08, - errNOTDONE = 0x09, - errFIRMWARE = 0x0A, - errVENDOR = 0x0B, - errUSBR = 0x0C, - errPOR = 0x0D, - errUNKNOWN = 0x0E, - errSTALLEDPKT = 0x0F - }; - - enum class State : uint8_t { - appIDLE = 0, - appDETACH = 1, - dfuIDLE = 2, - dfuDNLOADSYNC = 3, - dfuDNBUSY = 4, - dfuDNLOADIDLE = 5, - dfuMANIFESTSYNC = 6, - dfuMANIFEST = 7, - dfuMANIFESTWAITRESET = 8, - dfuUPLOADIDLE = 9, - dfuERROR = 10 - }; - - class StatusData : public Streamable { - public: - StatusData(Status status, State state, uint32_t pollTimeout = 1) : - /* We put a default pollTimeout value of 1ms: if the device is busy, the - * host has to wait 1ms before sending a getStatus Request. */ - m_bStatus((uint8_t)status), - m_bwPollTimeout{uint8_t((pollTimeout>>16) & 0xFF), uint8_t((pollTimeout>>8) & 0xFF), uint8_t(pollTimeout & 0xFF)}, - m_bState((uint8_t)state), - m_iString(0) + namespace USB { - } - protected: - void push(Channel * c) const override; - private: - uint8_t m_bStatus; // Status resulting from the execution of the most recent request - uint8_t m_bwPollTimeout[3]; // m_bwPollTimeout is 24 bits - uint8_t m_bState; // State of the device immediately following transmission of this response - uint8_t m_iString; - }; - class StateData : public Streamable { - public: - StateData(State state) : m_bState((uint8_t)state) {} - protected: - void push(Channel * c) const override; - private: - uint8_t m_bState; // Current state of the device - }; + class DFUInterface : public Interface + { - /* The Flash and SRAM addresses are in flash.ld. However, dfu_interface is + public: + DFUInterface(Device *device, Endpoint0 *ep0, uint8_t bInterfaceAlternateSetting) : Interface(ep0), + m_device(device), + m_status(Status::OK), + m_state(State::dfuIDLE), + m_addressPointer(0), + m_potentialNewAddressPointer(0), + m_erasePage(-1), + m_largeBuffer{0}, + m_largeBufferLength(0), + m_writeAddress(0), + m_eraseAddress(0), + m_bInterfaceAlternateSetting(bInterfaceAlternateSetting), + m_isErasingAndWriting(false), + m_isFirstInternalFlash(true), + m_temp_is_valid(false), + m_isInternalLocked(true), + m_isFirstExternalFlash(true), + m_last_memoryFlashed(-1), + m_lastPageErased(-1), + m_dfuUnlocked(false), + m_dfuLevel(0) + { + } + uint32_t addressPointer() const { return m_addressPointer; } + void wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override; + void wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override; + bool isErasingAndWriting() const { return m_isErasingAndWriting; } + void unlockDfu() {m_dfuUnlocked = true;}; + void setLevel(int lvl) {m_dfuLevel = lvl; } + + protected: + void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override + { + assert(interfaceAlternativeIndex == m_bInterfaceAlternateSetting); + } + uint8_t getActiveInterfaceAlternative() override + { + return m_bInterfaceAlternateSetting; + } + bool processSetupInRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) override; + + private: + // DFU Request Codes + enum class DFURequest + { + Detach = 0, + Download = 1, + Upload = 2, + GetStatus = 3, + ClearStatus = 4, + GetState = 5, + Abort = 6 + }; + + // DFU Download Commmand Codes + enum class DFUDownloadCommand + { + GetCommand = 0x00, + SetAddressPointer = 0x21, + Erase = 0x41, + ReadUnprotect = 0x92 + }; + + enum class Status : uint8_t + { + OK = 0x00, + errTARGET = 0x01, + errFILE = 0x02, + errWRITE = 0x03, + errERASE = 0x04, + errCHECK_ERASED = 0x05, + errPROG = 0x06, + errVERIFY = 0x07, + errADDRESS = 0x08, + errNOTDONE = 0x09, + errFIRMWARE = 0x0A, + errVENDOR = 0x0B, + errUSBR = 0x0C, + errPOR = 0x0D, + errUNKNOWN = 0x0E, + errSTALLEDPKT = 0x0F + }; + + enum class State : uint8_t + { + appIDLE = 0, + appDETACH = 1, + dfuIDLE = 2, + dfuDNLOADSYNC = 3, + dfuDNBUSY = 4, + dfuDNLOADIDLE = 5, + dfuMANIFESTSYNC = 6, + dfuMANIFEST = 7, + dfuMANIFESTWAITRESET = 8, + dfuUPLOADIDLE = 9, + dfuERROR = 10 + }; + + class StatusData : public Streamable + { + public: + StatusData(Status status, State state, uint32_t pollTimeout = 10) : /* We put a default pollTimeout value of 1ms: if the device is busy, the + * host has to wait 1ms before sending a getStatus Request. */ + m_bStatus((uint8_t)status), + m_bwPollTimeout{uint8_t((pollTimeout >> 16) & 0xFF), uint8_t((pollTimeout >> 8) & 0xFF), uint8_t(pollTimeout & 0xFF)}, + m_bState((uint8_t)state), + m_iString(0) + { + } + + protected: + void push(Channel *c) const override; + + private: + uint8_t m_bStatus; // Status resulting from the execution of the most recent request + uint8_t m_bwPollTimeout[3]; // m_bwPollTimeout is 24 bits + uint8_t m_bState; // State of the device immediately following transmission of this response + uint8_t m_iString; + }; + + class StateData : public Streamable + { + public: + StateData(State state) : m_bState((uint8_t)state) {} + + protected: + void push(Channel *c) const override; + + private: + uint8_t m_bState; // Current state of the device + }; + + /* The Flash and SRAM addresses are in flash.ld. However, dfu_interface is * linked with dfu.ld, so we cannot access the values. */ - constexpr static uint32_t k_sramStartAddress = 0x20000000; - constexpr static uint32_t k_sramEndAddress = 0x20040000; + constexpr static uint32_t k_sramStartAddress = 0x20000000; + constexpr static uint32_t k_sramEndAddress = 0x20040000; + constexpr static uint32_t k_ExternalBorderAddress = 0x90200000; - // Download and upload - bool processDownloadRequest(uint16_t wLength, uint16_t * transferBufferLength); - bool processUploadRequest(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength); - // Address pointer - void setAddressPointerCommand(SetupPacket * request, uint8_t * transferBuffer, uint16_t transferBufferLength); - void changeAddressPointerIfNeeded(); - // Access memory - void eraseCommand(uint8_t * transferBuffer, uint16_t transferBufferLength); - void eraseMemoryIfNeeded(); - void writeOnMemory(); - void unlockFlashMemory(); - void lockFlashMemoryAndPurgeCaches(); - // Status - bool getStatus(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength); - bool clearStatus(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength); - // State - bool getState(uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t maxSize); - // Abort - bool dfuAbort(uint16_t * transferBufferLength); - // Leave DFU - void leaveDFUAndReset(); - /* Erase and Write state. After starting the erase of flash memory, the user + const static int magik_adrs = 0x1C4; + constexpr static int magik_ext_adrs[3] = {0x03, 0xb, 0x44f}; + constexpr static uint8_t magik[4] = {0xF0, 0x0D, 0xC0, 0xDE}; + constexpr static uint8_t external_magik[9] = {0x64, 0x6c, 0x31, 0x31, 0x23, 0x39, 0x38, 0x33, 0x35}; + + // Download and upload + bool processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength); + bool processUploadRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength); + // Address pointer + void setAddressPointerCommand(SetupPacket *request, uint8_t *transferBuffer, uint16_t transferBufferLength); + void changeAddressPointerIfNeeded(); + // Access memory + void eraseCommand(uint8_t *transferBuffer, uint16_t transferBufferLength); + void eraseMemoryIfNeeded(); + void eraseMemoryIfNeededWithoutErasingAtAll(); + void writeOnMemory(); + void unlockFlashMemory(); + void lockFlashMemoryAndPurgeCaches(); + // Status + bool getStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength); + bool clearStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength); + // State + bool getState(uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t maxSize); + // Abort + bool dfuAbort(uint16_t *transferBufferLength); + // Leave DFU + void leaveDFUAndReset(bool do_reset=true); + /* Erase and Write state. After starting the erase of flash memory, the user * can no longer leave DFU mode by pressing the Back key of the keyboard. This * way, we prevent the user from interrupting a software download. After every * software download, the calculator resets, which unlocks the "exit on * pressing back". */ - void willErase() { m_isErasingAndWriting = true; } + void willErase() { m_isErasingAndWriting = true; } + void reset_custom_vars() {m_temp_is_valid = true; m_last_memoryFlashed = -1; m_lastPageErased = -1;} - Device * m_device; - Status m_status; - State m_state; - uint32_t m_addressPointer; - uint32_t m_potentialNewAddressPointer; - int32_t m_erasePage; - uint8_t m_largeBuffer[Endpoint0::MaxTransferSize]; - uint16_t m_largeBufferLength; - uint32_t m_writeAddress; - uint8_t m_bInterfaceAlternateSetting; - bool m_isErasingAndWriting; -}; + Device *m_device; + Status m_status; + State m_state; + uint32_t m_addressPointer; + uint32_t m_potentialNewAddressPointer; + int32_t m_erasePage; + uint8_t m_largeBuffer[Endpoint0::MaxTransferSize]; + uint16_t m_largeBufferLength; + uint32_t m_writeAddress; + uint32_t m_eraseAddress; + uint8_t m_bInterfaceAlternateSetting; + bool m_isErasingAndWriting; + bool m_isFirstInternalFlash; + bool m_temp_is_valid; + bool m_isInternalLocked; + bool m_isFirstExternalFlash; + int m_last_memoryFlashed; // -1: aucune; 0: internal; 1: external + int m_lastPageErased; // -1 par défaut + bool m_dfuUnlocked; + int m_dfuLevel; + }; -} -} + } + } } #endif diff --git a/ion/src/device/shared/usb/dfu_relocated.cpp b/ion/src/device/shared/usb/dfu_relocated.cpp index 82868a88c..f68cd2e96 100644 --- a/ion/src/device/shared/usb/dfu_relocated.cpp +++ b/ion/src/device/shared/usb/dfu_relocated.cpp @@ -11,9 +11,9 @@ extern char _dfu_bootloader_flash_end; namespace Ion { namespace USB { -typedef void (*PollFunctionPointer)(bool exitWithKeyboard); +typedef void (*PollFunctionPointer)(bool exitWithKeyboard, bool unlocked, int level); -void DFU(bool exitWithKeyboard) { +void DFU(bool exitWithKeyboard, bool unlocked, int level) { /* DFU transfers can serve two purposes: * - Transfering RAM data between the machine and a host, e.g. Python scripts @@ -74,7 +74,7 @@ void DFU(bool exitWithKeyboard) { * add-symbol-file ion/src/device/usb/dfu.elf 0x20038000 */ - dfu_bootloader_entry(exitWithKeyboard); + dfu_bootloader_entry(exitWithKeyboard, unlocked, level); /* 5- Restore interrupts */ Device::Timing::init(); diff --git a/ion/src/device/shared/usb/dfu_xip.cpp b/ion/src/device/shared/usb/dfu_xip.cpp index 753948f73..dce014cd2 100644 --- a/ion/src/device/shared/usb/dfu_xip.cpp +++ b/ion/src/device/shared/usb/dfu_xip.cpp @@ -3,8 +3,8 @@ namespace Ion { namespace USB { -void DFU(bool exitWithKeyboard) { - Ion::Device::USB::Calculator::PollAndReset(exitWithKeyboard); +void DFU(bool exitWithKeyboard, bool unlocked, int level) { + Ion::Device::USB::Calculator::PollAndReset(exitWithKeyboard, unlocked, level); } } diff --git a/ion/src/shared/dummy/usb.cpp b/ion/src/shared/dummy/usb.cpp index ce3c0fd2c..4f3554dff 100644 --- a/ion/src/shared/dummy/usb.cpp +++ b/ion/src/shared/dummy/usb.cpp @@ -14,7 +14,7 @@ bool isEnumerated() { void clearEnumerationInterrupt() { } -void DFU(bool) { +void DFU(bool, bool, int) { } void enable() { diff --git a/ion/src/simulator/3ds/driver/usb.cpp b/ion/src/simulator/3ds/driver/usb.cpp index 59e83bea5..17cea3ce7 100644 --- a/ion/src/simulator/3ds/driver/usb.cpp +++ b/ion/src/simulator/3ds/driver/usb.cpp @@ -13,7 +13,7 @@ bool Ion::USB::isEnumerated() { void Ion::USB::clearEnumerationInterrupt() { } -void Ion::USB::DFU(bool) { +void Ion::USB::DFU(bool, bool, int) { } void Ion::USB::enable() { diff --git a/kandinsky/fonts/code_points.h b/kandinsky/fonts/code_points.h index 1804fc64a..8671637f9 100644 --- a/kandinsky/fonts/code_points.h +++ b/kandinsky/fonts/code_points.h @@ -105,6 +105,7 @@ uint32_t CodePoints[] = { 0x7d, // } // RIGHT CURLY BRACKET 0x7e, // ~ // TILDE + 0xa1, // ¡ // INVERTED EXCLAMATION MARK 0xb0, // ° // DEGREE SIGN 0xb7, // · // MIDDLE DOT