Resolved conflicts

This commit is contained in:
Quentin Guidée
2019-12-24 01:07:22 +01:00
62 changed files with 478 additions and 290 deletions

View File

@@ -14,7 +14,8 @@ jobs:
build-device-n0100:
runs-on: ubuntu-latest
steps:
- run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- uses: numworks/setup-arm-toolchain@v1
- uses: actions/checkout@v1
- run: make -j2 MODEL=n0100 epsilon.dfu
- run: make -j2 MODEL=n0100 epsilon.onboarding.dfu
@@ -30,7 +31,8 @@ jobs:
build-device-n0110:
runs-on: ubuntu-latest
steps:
- run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- uses: numworks/setup-arm-toolchain@v1
- uses: actions/checkout@v1
- run: make -j2 epsilon.dfu
- run: make -j2 epsilon.onboarding.dfu

View File

@@ -92,6 +92,10 @@ $(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.gene
apps_tests_src = $(app_calculation_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_solver_test_src)
apps_tests_src += $(addprefix apps/,\
global_preferences.cpp \
)
# Configure variants
apps_all_src = $(app_src)
apps_all_src += $(apps_launch_default_src) $(apps_launch_on_boarding_src

View File

@@ -201,8 +201,8 @@ bool AppsContainer::processEvent(Ion::Events::Event event) {
// Warning: if the window is dirtied, you need to call window()->redraw()
if (event == Ion::Events::USBPlug) {
if (Ion::USB::isPlugged()) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
displayExamModePopUp(false);
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
displayExamModePopUp(GlobalPreferences::ExamMode::Off);
window()->redraw();
} else {
Ion::USB::enable();
@@ -251,8 +251,8 @@ void AppsContainer::run() {
* and it is visible when reflashing a N0100 (there is some noise on the
* screen before the logo appears). */
Ion::Display::pushRectUniform(screenRect, KDColorWhite);
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
activateExamMode();
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode());
}
refreshPreferences();
@@ -313,8 +313,8 @@ void AppsContainer::reloadTitleBarView() {
m_window.reloadTitleBarView();
}
void AppsContainer::displayExamModePopUp(bool activate) {
m_examPopUpController.setActivatingExamMode(activate);
void AppsContainer::displayExamModePopUp(GlobalPreferences::ExamMode mode) {
m_examPopUpController.setTargetExamMode(mode);
s_activeApp->displayModalViewController(&m_examPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin);
}
@@ -329,7 +329,7 @@ void AppsContainer::shutdownDueToLowBattery() {
}
while (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) {
Ion::Backlight::setBrightness(0);
if (!GlobalPreferences::sharedGlobalPreferences()->examMode()) {
if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
/* Unless the LED is lit up for the exam mode, switch off the LED. IF the
* low battery event happened during the Power-On Self-Test, a LED might
* have stayed lit up. */
@@ -362,7 +362,8 @@ void AppsContainer::redrawWindow(bool force) {
m_window.redraw(force);
}
void AppsContainer::activateExamMode() {
void AppsContainer::activateExamMode(GlobalPreferences::ExamMode examMode) {
assert(examMode == GlobalPreferences::ExamMode::Standard || examMode == GlobalPreferences::ExamMode::Dutch);
reset();
Preferences * preferences = Preferences::sharedPreferences();
switch ((int)preferences->colorOfLED()) {
@@ -379,6 +380,14 @@ void AppsContainer::activateExamMode() {
Ion::LED::setColor(KDColorYellow);
break;
}
/* The Dutch exam mode LED is supposed to be orange but we can only make
* blink "pure" colors: with RGB leds on or off (as the PWM is used for
* blinking). The closest "pure" color is Yellow. Moreover, Orange LED is
* already used when the battery is charging. Using yellow, we can assert
* that the yellow LED only means that Dutch exam mode is on and avoid
* confusing states when the battery is charging and states when the Dutch
* exam mode is on. */
// Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorYellow : KDColorRed);
Ion::LED::setBlinking(1000, 0.1f);
}

View File

@@ -13,6 +13,7 @@
#include "exam_pop_up_controller_delegate.h"
#include "battery_timer.h"
#include "suspend_timer.h"
#include "global_preferences.h"
#include "backlight_dimming_timer.h"
#include "shared/global_context.h"
#include "on_boarding/pop_up_controller.h"
@@ -41,12 +42,12 @@ public:
bool updateBatteryState();
void refreshPreferences();
void reloadTitleBarView();
void displayExamModePopUp(bool activate);
void displayExamModePopUp(GlobalPreferences::ExamMode mode);
void shutdownDueToLowBattery();
void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus);
OnBoarding::PopUpController * promptController();
void redrawWindow(bool force = false);
void activateExamMode();
void activateExamMode(GlobalPreferences::ExamMode examMode);
// Exam pop-up controller delegate
void examDeactivatingPopUpIsDismissed() override;
// Ion::StorageDelegate

View File

@@ -1,5 +1,6 @@
#include "calculation.h"
#include "../shared/poincare_helpers.h"
#include "../global_preferences.h"
#include <poincare/exception_checkpoint.h>
#include <poincare/undefined.h>
#include <poincare/unreal.h>
@@ -123,7 +124,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
}
if (shouldOnlyDisplayExactOutput()) {
m_displayOutput = DisplayOutput::ExactOnly;
} else if (input().recursivelyMatches(
// Force all results to be ApproximateOnly in Dutch exam mode
} else if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch ||
input().recursivelyMatches(
[](const Expression e, Context * c) {
constexpr int approximateOnlyTypesCount = 9;
/* If the input contains the following types, we only display the

View File

@@ -10,14 +10,14 @@ using namespace Poincare;
ExamPopUpController::ExamPopUpController(ExamPopUpControllerDelegate * delegate) :
ViewController(nullptr),
m_contentView(this),
m_isActivatingExamMode(false),
m_targetExamMode(GlobalPreferences::ExamMode::Unknown),
m_delegate(delegate)
{
}
void ExamPopUpController::setActivatingExamMode(bool activatingExamMode) {
m_isActivatingExamMode = activatingExamMode;
m_contentView.setMessages(activatingExamMode);
void ExamPopUpController::setTargetExamMode(GlobalPreferences::ExamMode mode) {
m_targetExamMode = mode;
m_contentView.setMessagesForExamMode(mode);
}
View * ExamPopUpController::view() {
@@ -25,7 +25,7 @@ View * ExamPopUpController::view() {
}
void ExamPopUpController::viewDidDisappear() {
if (m_isActivatingExamMode == false) {
if (m_targetExamMode == GlobalPreferences::ExamMode::Off) {
m_delegate->examDeactivatingPopUpIsDismissed();
}
}
@@ -53,13 +53,15 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) :
}, parentResponder), KDFont::SmallFont),
m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) {
ExamPopUpController * controller = (ExamPopUpController *)context;
GlobalPreferences::sharedGlobalPreferences()->setExamMode(controller->isActivatingExamMode());
GlobalPreferences::ExamMode mode = controller->targetExamMode();
assert(mode != GlobalPreferences::ExamMode::Unknown);
GlobalPreferences::sharedGlobalPreferences()->setExamMode(mode);
AppsContainer * container = AppsContainer::sharedAppsContainer();
if (controller->isActivatingExamMode()) {
container->activateExamMode();
} else {
if (mode == GlobalPreferences::ExamMode::Off) {
Ion::LED::setColor(KDColorBlack);
Ion::LED::updateColorWithPlugAndCharge();
} else {
container->activateExamMode(mode);
}
container->refreshPreferences();
Container::activeApp()->dismissModalViewController();
@@ -89,15 +91,20 @@ int ExamPopUpController::ContentView::selectedButton() {
return 1;
}
void ExamPopUpController::ContentView::setMessages(bool activingExamMode) {
if (activingExamMode) {
void ExamPopUpController::ContentView::setMessagesForExamMode(GlobalPreferences::ExamMode mode) {
if (mode == GlobalPreferences::ExamMode::Off) {
m_messageTextView1.setMessage(I18n::Message::ExitExamMode1);
m_messageTextView2.setMessage(I18n::Message::ExitExamMode2);
m_messageTextView3.setMessage(I18n::Message::Default);
} else if (mode == GlobalPreferences::ExamMode::Standard) {
m_messageTextView1.setMessage(I18n::Message::ActiveExamModeMessage1);
m_messageTextView2.setMessage(I18n::Message::ActiveExamModeMessage2);
m_messageTextView3.setMessage(I18n::Message::ActiveExamModeMessage3);
} else {
m_messageTextView1.setMessage(I18n::Message::ExitExamMode1);
m_messageTextView2.setMessage(I18n::Message::ExitExamMode2);
m_messageTextView3.setMessage(I18n::Message::Default);
assert(mode == GlobalPreferences::ExamMode::Dutch);
m_messageTextView1.setMessage(I18n::Message::ActiveDutchExamModeMessage1);
m_messageTextView2.setMessage(I18n::Message::ActiveDutchExamModeMessage2);
m_messageTextView3.setMessage(I18n::Message::ActiveDutchExamModeMessage3);
}
}

View File

@@ -3,6 +3,7 @@
#include <escher.h>
#include "exam_pop_up_controller_delegate.h"
#include "global_preferences.h"
class HighContrastButton : public Button {
public:
@@ -13,8 +14,8 @@ public:
class ExamPopUpController : public ViewController {
public:
ExamPopUpController(ExamPopUpControllerDelegate * delegate);
void setActivatingExamMode(bool activingExamMode);
bool isActivatingExamMode() const { return m_isActivatingExamMode; }
void setTargetExamMode(GlobalPreferences::ExamMode mode);
GlobalPreferences::ExamMode targetExamMode() const { return m_targetExamMode; }
// View Controller
View * view() override;
void viewDidDisappear() override;
@@ -28,7 +29,7 @@ private:
void drawRect(KDContext * ctx, KDRect rect) const override;
void setSelectedButton(int selectedButton);
int selectedButton();
void setMessages(bool activingExamMode);
void setMessagesForExamMode(GlobalPreferences::ExamMode mode);
private:
constexpr static KDCoordinate k_buttonMargin = 10;
constexpr static KDCoordinate k_buttonHeight = 20;
@@ -45,7 +46,7 @@ private:
MessageTextView m_messageTextView3;
};
ContentView m_contentView;
bool m_isActivatingExamMode;
GlobalPreferences::ExamMode m_targetExamMode;
ExamPopUpControllerDelegate * m_delegate;
};

View File

@@ -5,20 +5,26 @@ GlobalPreferences * GlobalPreferences::sharedGlobalPreferences() {
return &globalPreferences;
}
bool GlobalPreferences::examMode() const {
GlobalPreferences::ExamMode GlobalPreferences::examMode() const {
if (m_examMode == ExamMode::Unknown) {
m_examMode = (ExamMode)Ion::ExamMode::FetchExamMode();
uint8_t mode = Ion::ExamMode::FetchExamMode();
assert(mode >= 0 && mode < 3); // mode can be cast in ExamMode (Off, Standard or Dutch)
m_examMode = (ExamMode)mode;
}
assert((int)m_examMode == 0 || (int)m_examMode == 1);
return (bool)m_examMode;
return m_examMode;
}
void GlobalPreferences::setExamMode(bool activateExamMode) {
if (((bool)examMode()) == activateExamMode) {
void GlobalPreferences::setExamMode(ExamMode mode) {
ExamMode currentMode = examMode();
if (currentMode == mode) {
return;
}
Ion::ExamMode::ToggleExamMode();
m_examMode = (ExamMode)activateExamMode;
assert(mode != ExamMode::Unknown);
int8_t deltaMode = (int8_t)mode - (int8_t)currentMode;
deltaMode = deltaMode < 0 ? deltaMode + 3 : deltaMode;
assert(deltaMode > 0);
Ion::ExamMode::IncrementExamMode(deltaMode);
m_examMode = mode;
}
void GlobalPreferences::setBrightnessLevel(int brightnessLevel) {

View File

@@ -5,11 +5,18 @@
class GlobalPreferences {
public:
enum class ExamMode : int8_t {
Unknown = -1,
Off = 0,
Standard = 1,
Dutch = 2
};
static GlobalPreferences * sharedGlobalPreferences();
I18n::Language language() const { return m_language; }
void setLanguage(I18n::Language language) { m_language = language; }
bool examMode() const;
void setExamMode(bool activateExamMode);
bool isInExamMode() const { return (int8_t)examMode() > 0; }
ExamMode examMode() const;
void setExamMode(ExamMode examMode);
bool showPopUp() const { return m_showPopUp; }
void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; }
int brightnessLevel() const { return m_brightnessLevel; }
@@ -22,13 +29,8 @@ private:
m_showPopUp(true),
m_brightnessLevel(Ion::Backlight::MaxBrightness) {}
I18n::Language m_language;
enum class ExamMode : uint8_t {
Deactivate = 0,
Activate = 1,
Unknown = 2
};
static_assert((uint8_t)GlobalPreferences::ExamMode::Deactivate == 0, "GlobalPreferences::setExamMode and examMode() are not right");
static_assert((uint8_t)GlobalPreferences::ExamMode::Activate == 1, "GlobalPreferences::setExamMode and examMode() are not right");
static_assert((int8_t)GlobalPreferences::ExamMode::Off == 0, "GlobalPreferences::isInExamMode() is not right");
static_assert((int8_t)GlobalPreferences::ExamMode::Unknown < 0, "GlobalPreferences::isInExamMode() is not right");
mutable ExamMode m_examMode;
bool m_showPopUp;
int m_brightnessLevel;

View File

@@ -1,2 +1,5 @@
Apps = "Anwendungen"
AppsCapital = "OMEGA"
AppsCapital = "ANWENDUNGEN"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,2 +1,5 @@
Apps = "Applications"
AppsCapital = "OMEGA"
AppsCapital = "APPLICATIONS"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,2 +1,5 @@
Apps = "Aplicaciones"
AppsCapital = "OMEGA"
AppsCapital = "APLICACIONES"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,2 +1,5 @@
Apps = "Applications"
AppsCapital = "OMEGA"
AppsCapital = "APPLICATIONS"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,2 +1,5 @@
Apps = "Aplicações"
AppsCapital = "OMEGA"
AppsCapital = "APLICAÇÕES"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -58,9 +58,14 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc
bool Controller::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
AppsContainer * container = AppsContainer::sharedAppsContainer();
bool switched = container->switchTo(container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1));
assert(switched);
(void) switched; // Silence compilation warning about unused variable.
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1);
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch && selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp) {
App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
} else {
bool switched = container->switchTo(selectedSnapshot);
assert(switched);
(void) switched; // Silence compilation warning about unused variable.
}
return true;
}

View File

@@ -49,8 +49,8 @@ void LogoController::viewDidDisappear() {
Ion::LED::setColor(m_previousLEDColor);
/* TODO: instead of setting again the exam mode, put the previous led color
* AND BLINKING.*/
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
AppsContainer::sharedAppsContainer()->activateExamMode();
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
AppsContainer::sharedAppsContainer()->activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode());
}
}
ViewController::viewDidDisappear();

View File

@@ -20,7 +20,7 @@ KDColor PowerOnSelfTest::Perform() {
resultColor = KDColorRed;
}
} else {
resultColor = KDColorBlue;
resultColor = KDColorPurple;
}
Ion::LED::setColor(resultColor);
return previousLEDColor;

View File

@@ -9,6 +9,7 @@ ComplexFormat = "Komplex"
ExamMode = "Testmodus"
ActivateExamMode = "Starten Testmodus"
ExamModeActive = "Wieder starten Testmodus"
ActivateDutchExamMode = "Activate Dutch exam mode"
About = "Über"
Degrees = "Grad "
Gradians = "Gone "

View File

@@ -9,6 +9,7 @@ ComplexFormat = "Complex format"
ExamMode = "Exam mode"
ActivateExamMode = "Activate exam mode"
ExamModeActive = "Reactivate exam mode"
ActivateDutchExamMode = "Activate Dutch exam mode"
About = "About"
Degrees = "Degrees "
Gradians = "Gradians "

View File

@@ -9,6 +9,7 @@ ComplexFormat = "Forma compleja"
ExamMode = "Modo examen"
ActivateExamMode = "Activar el modo examen"
ExamModeActive = "Reactivar el modo examen"
ActivateDutchExamMode = "Activate Dutch exam mode"
About = "Acerca"
Degrees = "Grados "
Gradians = "Gradianes "

View File

@@ -9,6 +9,7 @@ ComplexFormat = "Forme complexe"
ExamMode = "Mode examen"
ActivateExamMode = "Activer le mode examen"
ExamModeActive = "Réactiver le mode examen"
ActivateDutchExamMode = "Activate Dutch exam mode"
About = "À propos"
Degrees = "Degrés "
Gradians = "Grades "

View File

@@ -9,6 +9,7 @@ ComplexFormat = "Complexos"
ExamMode = "Modo de exame"
ActivateExamMode = "Ativar o modo de exame"
ExamModeActive = "Reativar o modo de exame"
ActivateDutchExamMode = "Activate Dutch exam mode"
About = "Acerca"
Degrees = "Graus "
Gradians = "Grados "

View File

@@ -14,7 +14,7 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M
//sub-menus
constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)};
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)};
#ifdef USERNAME
constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)};
@@ -26,7 +26,7 @@ constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5),
SettingsMessageTree(I18n::Message::Brightness),
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 3),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 4),
SettingsMessageTree(I18n::Message::BetaPopUp),
SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6),
#ifdef USERNAME

View File

@@ -15,7 +15,7 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M
//sub-menus
constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)};
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)};
#ifdef USERNAME
constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)};
@@ -27,7 +27,7 @@ constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5),
SettingsMessageTree(I18n::Message::Brightness),
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 3),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 4),
SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6),
#ifdef USERNAME
SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 7)};

View File

@@ -14,7 +14,7 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M
//sub-menus
constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode)};
constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::SymbolicEnabled), SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)};
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)};
#ifdef USERNAME
constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)};
@@ -26,7 +26,7 @@ constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5),
SettingsMessageTree(I18n::Message::Brightness),
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 3),
SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 4),
SettingsMessageTree(I18n::Message::UpdatePopUp),
SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6),
#ifdef USERNAME

View File

@@ -1,6 +1,7 @@
#include "exam_mode_controller.h"
#include "../../global_preferences.h"
#include "../../apps_container.h"
#include <apps/i18n.h>
#include <assert.h>
#include <cmath>
#include <poincare/preferences.h>
@@ -17,17 +18,31 @@ ExamModeController::ExamModeController(Responder * parentResponder) :
m_examModeCell(I18n::Message::Default, KDFont::LargeFont),
m_ledCell(KDFont::LargeFont, KDFont::SmallFont),
m_symbolicCell(I18n::Message::SymbolicEnabled, KDFont::LargeFont)
m_cell{MessageTableCell(I18n::Message::ExamModeActive, KDFont::LargeFont), MessageTableCell(I18n::Message::ActivateDutchExamMode, KDFont::LargeFont)}
{
}
void ExamModeController::didEnterResponderChain(Responder * previousFirstResponder) {
m_selectableTableView.reloadData();
int ExamModeController::initialSelectedRow() const {
int row = selectedRow();
if (row >= numberOfRows()) {
return numberOfRows()-1;
} else if (row < 0) {
return 0;
}
return row;
}
bool ExamModeController::handleEvent(Ion::Events::Event event) {
I18n::Message childLabel = m_messageTreeModel->children(selectedRow())->label();
if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
// If the exam mode is already on, this re-activate the same exam mode
mode = GlobalPreferences::sharedGlobalPreferences()->examMode();
if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive)
AppsContainer::sharedAppsContainer()->displayExamModePopUp(true);
return true;
} else if (childLabel == I18n::Message::ActivateDutchExamMode) {
mode = GlobalPreferences::ExamMode::Dutch
if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive)
AppsContainer::sharedAppsContainer()->displayExamModePopUp(true);
return true;
@@ -53,6 +68,13 @@ bool ExamModeController::handleEvent(Ion::Events::Event event) {
return GenericSubController::handleEvent(event);
}
int ExamModeController::numberOfRows() const {
if (GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
return 1;
}
return GenericSubController::numberOfRows();
}
HighlightCell * ExamModeController::reusableCell(int index, int type) {
assert(index == 0);
if (type == 0) {
@@ -76,14 +98,21 @@ int ExamModeController::reusableCellCount(int type) {
assert(false);
return 0;
}
/*assert(type == 0);
assert(index >= 0 && index < k_maxNumberOfCells);
return &m_cell[index];*/
}
/*int ExamModeController::reusableCellCount(int type) {
return k_maxNumberOfCells;
}*/
void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index) {
Preferences * preferences = Preferences::sharedPreferences();
GenericSubController::willDisplayCellForIndex(cell, index);
I18n::Message thisLabel = m_messageTreeModel->children(index)->label();
if (GlobalPreferences::sharedGlobalPreferences()->examMode() && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) {
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode() && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) {
MessageTableCell * myCell = (MessageTableCell *)cell;
myCell->setMessage(I18n::Message::ExamModeActive);
}

View File

@@ -9,17 +9,23 @@ namespace Settings {
class ExamModeController : public GenericSubController {
public:
ExamModeController(Responder * parentResponder);
void didEnterResponderChain(Responder * previousFirstResponder) override;
bool handleEvent(Ion::Events::Event event) override;
int numberOfRows() const 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:
<<<<<<< HEAD
MessageTableCell m_examModeCell;
MessageTableCellWithChevronAndMessage m_ledCell;
PreferencesController m_preferencesController;
MessageTableCellWithSwitch m_symbolicCell;
=======
int initialSelectedRow() const override;
static constexpr int k_maxNumberOfCells = 2;
MessageTableCell m_cell[k_maxNumberOfCells];
>>>>>>> upstream/master
};
}

View File

@@ -26,8 +26,12 @@ View * GenericSubController::view() {
return &m_selectableTableView;
}
void GenericSubController::didEnterResponderChain(Responder * previousFirstResponder) {
selectCellAtLocation(0, initialSelectedRow());
m_selectableTableView.reloadData();
}
void GenericSubController::didBecomeFirstResponder() {
selectCellAtLocation(0, 0);
Container::activeApp()->setFirstResponder(&m_selectableTableView);
}
@@ -75,10 +79,6 @@ void GenericSubController::setMessageTreeModel(const MessageTree * messageTreeMo
m_messageTreeModel = (MessageTree *)messageTreeModel;
}
void GenericSubController::viewWillAppear() {
m_selectableTableView.reloadData();
}
void GenericSubController::viewDidDisappear() {
m_selectableTableView.deselectTable();
}

View File

@@ -11,6 +11,7 @@ public:
GenericSubController(Responder * parentResponder);
const char * title() override;
View * view() override;
void didEnterResponderChain(Responder * previousFirstResponder) override;
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
int numberOfRows() const override;
@@ -20,10 +21,10 @@ public:
virtual int typeAtLocation(int i, int j) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
void setMessageTreeModel(const MessageTree * messageTreeModel);
void viewWillAppear() override;
void viewDidDisappear() override;
protected:
StackViewController * stackController() const;
virtual int initialSelectedRow() const { return 0; }
constexpr static KDCoordinate k_topBottomMargin = 13;
SelectableTableView m_selectableTableView;
MessageTree * m_messageTreeModel;

View File

@@ -23,7 +23,6 @@ PreferencesController::PreferencesController(Responder * parentResponder) :
}
void PreferencesController::didBecomeFirstResponder() {
selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label()));
Container::activeApp()->setFirstResponder(&m_selectableTableView);
}
@@ -188,7 +187,7 @@ void PreferencesController::setPreferenceWithValueIndex(I18n::Message message, i
}
}
int PreferencesController::valueIndexForPreference(I18n::Message message) {
int PreferencesController::valueIndexForPreference(I18n::Message message) const {
Preferences * preferences = Preferences::sharedPreferences();
if (message == I18n::Message::AngleUnit) {
return (int)preferences->angleUnit();

View File

@@ -18,9 +18,10 @@ protected:
constexpr static int k_totalNumberOfCell = 4;
private:
constexpr static const KDFont * k_layoutFont = KDFont::SmallFont;
int initialSelectedRow() const override { return valueIndexForPreference(m_messageTreeModel->label()); }
Poincare::Layout layoutForPreferences(I18n::Message message);
void setPreferenceWithValueIndex(I18n::Message message, int valueIndex);
int valueIndexForPreference(I18n::Message message);
int valueIndexForPreference(I18n::Message message) const;
MessageTableCellWithExpression m_cells[k_totalNumberOfCell];
};

View File

@@ -2,6 +2,9 @@ ActivateDeactivate = "Aktivieren/Deaktivieren"
ActiveExamModeMessage1 = "Alle Ihre Daten werden "
ActiveExamModeMessage2 = "gelöscht, wenn Sie den "
ActiveExamModeMessage3 = "Testmodus einschalten."
ActiveDutchExamModeMessage1 = "All your data will be deleted when"
ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Achsen"
Cancel = "Abbrechen"
ClearColumn = "Spalte löschen"

View File

@@ -2,6 +2,9 @@ ActivateDeactivate = "Turn on/off"
ActiveExamModeMessage1 = "All your data will be "
ActiveExamModeMessage2 = "deleted when you activate "
ActiveExamModeMessage3 = "the exam mode."
ActiveDutchExamModeMessage1 = "All your data will be deleted when"
ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Axes"
Cancel = "Cancel"
ClearColumn = "Clear column"

View File

@@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar"
ActiveExamModeMessage1 = "Todos sus datos se "
ActiveExamModeMessage2 = "eliminaran al activar "
ActiveExamModeMessage3 = "el modo examen."
ActiveDutchExamModeMessage1 = "All your data will be deleted when"
ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Ejes"
Cancel = "Cancelar"
ClearColumn = "Borrar la columna"

View File

@@ -2,6 +2,9 @@ ActivateDeactivate = "Activer/Désactiver"
ActiveExamModeMessage1 = "Toutes vos données seront "
ActiveExamModeMessage2 = "supprimées si vous activez "
ActiveExamModeMessage3 = "le mode examen."
ActiveDutchExamModeMessage1 = "All your data will be deleted when"
ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Axes"
Cancel = "Annuler"
ClearColumn = "Effacer la colonne"

View File

@@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar"
ActiveExamModeMessage1 = "Todos os seus dados serão "
ActiveExamModeMessage2 = "apagados se você ligar "
ActiveExamModeMessage3 = "o modo de exame."
ActiveDutchExamModeMessage1 = "All your data will be deleted when"
ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Eixos"
Cancel = "Cancelar"
ClearColumn = "Excluir coluna"

View File

@@ -1,6 +1,7 @@
#include "equation_store.h"
#include "../constant.h"
#include "../shared/poincare_helpers.h"
#include "../global_preferences.h"
#include <limits.h>
#include <poincare/constant.h>
@@ -193,6 +194,8 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
}
}
// Create the results' layouts
// In Dutch exam mode, display only approximate solutions
bool forbidExactSolutions = GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch;
int solutionIndex = 0;
int initialNumberOfSolutions = m_numberOfSolutions <= k_maxNumberOfExactSolutions ? m_numberOfSolutions : -1;
// We iterate through the solutions and the potential delta
@@ -211,7 +214,9 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
char approximateBuffer[::Constant::MaxSerializedExpressionSize];
m_exactSolutionExactLayouts[solutionIndex].serializeForParsing(exactBuffer, ::Constant::MaxSerializedExpressionSize);
m_exactSolutionApproximateLayouts[solutionIndex].serializeForParsing(approximateBuffer, ::Constant::MaxSerializedExpressionSize);
m_exactSolutionIdentity[solutionIndex] = strcmp(exactBuffer, approximateBuffer) == 0;
/* Cheat: declare exact and approximate solutions to be identical in
* Dutch exam mode to display only the approximate solutions. */
m_exactSolutionIdentity[solutionIndex] = forbidExactSolutions || strcmp(exactBuffer, approximateBuffer) == 0;
if (!m_exactSolutionIdentity[solutionIndex]) {
char buffer[::Constant::MaxSerializedExpressionSize];
m_exactSolutionEquality[solutionIndex] = exactSolutions[i].isEqualToItsApproximationLayout(exactSolutionsApproximations[i], buffer, ::Constant::MaxSerializedExpressionSize, preferences->complexFormat(), preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), context);

View File

@@ -71,7 +71,7 @@ void TitleBarView::layoutSubviews() {
m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height()));
KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay();
m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize));
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight));
} else {
m_examModeIconView.setFrame(KDRectZero);

View File

@@ -60,22 +60,3 @@ $(BUILD_DIR)/bench.flash.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/$(MODEL)/interna
bench_src = $(ion_xip_src) $(liba_src) $(kandinsky_src) $(poincare_src) $(libaxx_src) $(app_shared_src) $(ion_target_device_bench_src)
$(BUILD_DIR)/bench.ram.$(EXE): $(call object_for,$(bench_src))
$(BUILD_DIR)/bench.flash.$(EXE): $(call object_for,$(bench_src))
.PHONY: %.two_binaries
%.two_binaries: %.elf
@echo "Building an internal and an external binary for $<"
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $< $(basename $<).external.bin
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $< $(basename $<).internal.bin
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).external.bin
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).internal.bin
.PHONY: binpack
binpack: $(BUILD_DIR)/flasher.light.bin $(BUILD_DIR)/epsilon.onboarding.two_binaries
rm -rf $(BUILD_DIR)/binpack
mkdir -p $(BUILD_DIR)/binpack
cp $(BUILD_DIR)/flasher.light.bin $(BUILD_DIR)/binpack
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/*

View File

@@ -19,3 +19,31 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex
sleep 2; \
fi
$(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^)
.PHONY: %.two_binaries
%.two_binaries: %.elf
@echo "Building an internal and an external binary for $<"
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).external.bin
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).internal.bin
.PHONY: binpack
binpack:
rm -rf build/binpack
mkdir -p build/binpack
make clean
make -j8 $(BUILD_DIR)/flasher.light.bin
cp $(BUILD_DIR)/flasher.light.bin build/binpack
make clean
make -j8 $(BUILD_DIR)/bench.flash.bin
make -j8 $(BUILD_DIR)/bench.ram.bin
cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin build/binpack
make clean
make -j8 $(BUILD_DIR)/epsilon.onboarding.update.two_binaries
cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin build/binpack
make clean
cd build && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done
cd build && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack
rm -rf build/binpack

View File

@@ -5,16 +5,17 @@
class Responder {
public:
Responder(Responder * parentResponder);
Responder(Responder * parentResponder) : m_parentResponder(parentResponder) {}
virtual bool handleEvent(Ion::Events::Event event) { return false; }; // Default implementation does nothing
virtual void didBecomeFirstResponder();
virtual void willResignFirstResponder();
virtual void didEnterResponderChain(Responder * previousFirstResponder);
virtual void willExitResponderChain(Responder * nextFirstResponder);
Responder * parentResponder() const;
virtual void didBecomeFirstResponder() {}
virtual void willResignFirstResponder() {}
virtual void didEnterResponderChain(Responder * previousFirstResponder) {}
virtual void willExitResponderChain(Responder * nextFirstResponder) {}
Responder * parentResponder() const { return m_parentResponder; }
Responder * commonAncestorWith(Responder * responder);
void setParentResponder(Responder * responder);
void setParentResponder(Responder * responder) { m_parentResponder = responder; }
private:
bool hasAncestor(Responder * responder) const;
Responder * m_parentResponder;
};

View File

@@ -2,62 +2,29 @@
#include <escher/container.h>
#include <assert.h>
Responder::Responder(Responder * parentResponder) :
m_parentResponder(parentResponder)
{
}
Responder * Responder::parentResponder() const {
return m_parentResponder;
}
void Responder::setParentResponder(Responder * responder) {
m_parentResponder = responder;
}
void Responder::didBecomeFirstResponder() {
}
void Responder::willResignFirstResponder() {
}
void Responder::didEnterResponderChain(Responder * previousFirstResponder) {
}
void Responder::willExitResponderChain(Responder * nextFirstResponder) {
}
Responder * Responder::commonAncestorWith(Responder * responder) {
if (responder == nullptr) {
return nullptr;
}
if (this == responder) {
return this;
Responder * p = this;
while (p != nullptr) {
if (responder->hasAncestor(p)) {
return p;
}
p = p->parentResponder();
}
Responder * rootResponder = this;
while (rootResponder->parentResponder() != responder && rootResponder->parentResponder() != nullptr) {
rootResponder = rootResponder->parentResponder();
}
if (rootResponder->parentResponder() == responder) {
return responder;
}
rootResponder = responder;
while (rootResponder->parentResponder() != this && rootResponder->parentResponder() != nullptr) {
rootResponder = rootResponder->parentResponder();
}
if (rootResponder->parentResponder() == this) {
return this;
}
Responder * r = nullptr;
if (parentResponder()) {
r = parentResponder()->commonAncestorWith(responder);
}
Responder * s = nullptr;
if (responder->parentResponder()) {
s = commonAncestorWith(responder->parentResponder());
}
if (r) {
return r;
}
return s;
return nullptr;
}
bool Responder::hasAncestor(Responder * responder) const {
assert(responder != nullptr);
Responder * p = const_cast<Responder *>(this);
while (p != nullptr) {
if (p == responder) {
return true;
}
p = p->parentResponder();
}
return false;
}

View File

@@ -1,11 +1,15 @@
#ifndef ION_EXAM_MODE_H
#define ION_EXAM_MODE_H
extern "C" {
#include <stdint.h>
}
namespace Ion {
namespace ExamMode {
bool FetchExamMode();
void ToggleExamMode();
uint8_t FetchExamMode();
void IncrementExamMode(uint8_t delta);
}
}

View File

@@ -19,20 +19,5 @@ ion_src += $(addprefix ion/src/shared/, \
ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared
$(call object_for,$(ion_device_src) $(dfu_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(usb_src) $(ion_target_device_bench_src) $(ion_device_dfu_xip_src) $(ion_device_dfu_relocated_src) $(ion_console_uart_src)): SFLAGS += $(ION_DEVICE_SFLAGS)
$(call object_for,$(sort $(ion_device_src) $(dfu_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(usb_src) $(ion_target_device_bench_src) $(ion_device_dfu_xip_src) $(ion_device_dfu_relocated_src) $(ion_console_uart_src))): SFLAGS += $(ION_DEVICE_SFLAGS)
ion_src += $(ion_device_src)
# When using the register.h C++ file in production mode, we expect the compiler
# to completely inline all bit manipulations. For some reason, if we build using
# the -Os optimization flag, GCC doesn't inline everything and and ends up
# emitting calls to aeabi_llsl for 64-bits registers. This is very sub-optimal
# so we're enforcing -O3 for this specific file.
ifneq ($(DEBUG),1)
ifneq ($(COMPILER),llvm)
$(BUILD_DIR)/ion/src/device/led.o: SFLAGS+=-O3
$(BUILD_DIR)/ion/src/device/console.o: SFLAGS+=-O3
$(BUILD_DIR)/ion/src/device/display.o: SFLAGS+=-O3
$(BUILD_DIR)/ion/src/device/swd.o: SFLAGS+=-O3
endif
endif

View File

@@ -22,7 +22,10 @@ using namespace Regs;
constexpr static uint32_t StartAddress = 0xFFFFFFFF;
constexpr static uint32_t EndAddress = 0xFFFFFFFF;
constexpr static int NumberOfSectors = 0;
constexpr static int NumberOf4KSectors = 0;
constexpr static int NumberOf32KSectors = 0;
constexpr static int NumberOf64KSectors = 0;
constexpr static int NumberOfSectors = NumberOf4KSectors + NumberOf32KSectors + NumberOf64KSectors;
constexpr static AFGPIOPin Pins[] = {};
}

View File

@@ -7,43 +7,39 @@ namespace Cache {
using namespace Regs;
void privateCleanInvalidateDisableDCache(bool clean, bool invalidate, bool disable) {
// Select Level 1 data cache
CORTEX.CSSELR()->set(0);
dsb();
// Associativity = 6
uint32_t sets = CORTEX.CCSIDR()->getNUMSETS();
uint32_t ways = CORTEX.CCSIDR()->getASSOCIATIVITY();
// Disable D-Cache
if (disable) {
CORTEX.CCR()->setDC(false);
dsb();
}
do {
uint32_t w = ways;
do {
if (clean) {
if (invalidate) {
class CORTEX::DCCISW dccisw;
dccisw.setSET(sets);
dccisw.setWAY(w);
CORTEX.DCCISW()->set(dccisw);
} else {
class CORTEX::DCCSW dccsw;
dccsw.setSET(sets);
dccsw.setWAY(w);
CORTEX.DCCSW()->set(dccsw);
}
} else if (invalidate) {
class CORTEX::DCISW dcisw;
dcisw.setSET(sets);
dcisw.setWAY(w);
CORTEX.DCISW()->set(dcisw);
}
__asm volatile("nop");
} while (w-- != 0);
} while (sets-- != 0);
// Pick the right DC??SW register according to invalidate/disable parameters
volatile CORTEX::DCSW * target = nullptr;
if (clean && invalidate) {
target = CORTEX.DCCISW();
} else if (clean) {
target = CORTEX.DCCSW();
} else {
assert(invalidate);
target = CORTEX.DCISW();
}
class CORTEX::CCSIDR ccsidr = CORTEX.CCSIDR()->get();
uint32_t sets = ccsidr.getNUMSETS();
uint32_t ways = ccsidr.getASSOCIATIVITY();
for (int set = sets; set >= 0; set--) {
for (int way = ways; way >= 0; way--) {
class CORTEX::DCSW dcsw;
dcsw.setSET(set);
dcsw.setWAY(way);
target->set(dcsw);
}
}
dsb();
isb();
@@ -69,7 +65,7 @@ void cleanDCache() {
void enableDCache() {
invalidateDCache();
CORTEX.CCR()->setDC(true);
CORTEX.CCR()->setDC(true); // Enable D-cache
dsb();
isb();
}
@@ -81,14 +77,14 @@ void disableDCache() {
void invalidateICache() {
dsb();
isb();
CORTEX.ICIALLU()->set(0);
CORTEX.ICIALLU()->set(0); // Invalidate I-cache
dsb();
isb();
}
void enableICache() {
invalidateICache();
CORTEX.CCR()->setIC(true);
CORTEX.CCR()->setIC(true); // Enable I-cache
dsb();
isb();
}
@@ -96,8 +92,10 @@ void enableICache() {
void disableICache() {
dsb();
isb();
CORTEX.CCR()->setIC(false);
invalidateICache();
CORTEX.CCR()->setIC(false); // Disable I-cache
CORTEX.ICIALLU()->set(0); // Invalidate I-cache
dsb();
isb();
}

View File

@@ -22,7 +22,12 @@ using namespace Regs;
constexpr static uint32_t StartAddress = 0x90000000;
constexpr static uint32_t EndAddress = 0x90800000;
constexpr static int NumberOfSectors = 128;
constexpr static int NumberOf4KSectors = 8;
constexpr static int NumberOf32KSectors = 1;
constexpr static int NumberOf64KSectors = 128 - 1;
constexpr static int NumberOfSectors = NumberOf4KSectors + NumberOf32KSectors + NumberOf64KSectors;
constexpr static AFGPIOPin Pins[] = {
AFGPIOPin(GPIOB, 2, GPIO::AFR::AlternateFunction::AF9, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast),
AFGPIOPin(GPIOB, 6, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast),

View File

@@ -14,7 +14,7 @@ constexpr static AFGPIOPin VbusPin = AFGPIOPin(GPIOA, 9, GPIO::AFR::AlternateFun
constexpr static AFGPIOPin DmPin = AFGPIOPin(GPIOA, 11, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast);
constexpr static AFGPIOPin DpPin = AFGPIOPin(GPIOA, 12, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast);
constexpr static const char * InterfaceStringDescriptor = "@Flash/0x08000000/04*016Kg/0x90000000/64*064Kg,64*064Kg";
constexpr static const char * InterfaceStringDescriptor = "@Flash/0x08000000/04*016Kg/0x90000000/08*004Kg,01*032Kg,63*064Kg,64*064Kg";
}
}

View File

@@ -9,7 +9,7 @@ namespace LED {
KDColor updateColorWithPlugAndCharge() {
KDColor ledColor = getColor();
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { // If exam mode is on, we do not update the LED with the plugged/charging state
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode() { // If exam mode is on, we do not update the LED with the plugged/charging state
if (USB::isPlugged()) {
ledColor = Battery::isCharging() ? KDColorOrange : KDColorGreen;
} else {

View File

@@ -3,14 +3,14 @@
#include "flash.h"
#include <assert.h>
namespace Ion {
namespace ExamMode {
extern "C" {
extern char _exam_mode_buffer_start;
extern char _exam_mode_buffer_end;
}
namespace Ion {
namespace ExamMode {
char ones[Config::ExamModeBufferSize]
__attribute__((section(".exam_mode_buffer")))
__attribute__((used))
@@ -18,33 +18,24 @@ char ones[Config::ExamModeBufferSize]
/* The exam mode is written in flash so that it is resilient to resets.
* We erase the dedicated flash sector (all bits written to 1) and, upon
* activating or deactivating the exam mode we write one bit to 0. To determine
* if we are in exam mode, we count the number of leading 0 bits. If it is even,
* the exam mode is deactivated, if it is odd, the exam mode is activated. */
* deactivating or activating standard or Dutch exam mode we write one or two
* bits to 0. To determine in which exam mode we are, we count the number of
* leading 0 bits. If it is equal to:
* - 0[3]: the exam mode is off;
* - 1[3]: the standard exam mode is activated;
* - 2[3]: the Dutch exam mode is activated. */
/* significantExamModeAddress returns the first uint32_t * in the exam mode
* flash sector that does not point to 0. If this flash sector has only 0s, it
* is erased (to 1) and significantExamModeAddress returns the start of the
* sector. */
* flash sector that does not point to 0. If this flash sector has only 0s or
* if it has only one 1, it is erased (to 1) and significantExamModeAddress
* returns the start of the sector. */
uint32_t * SignificantExamModeAddress() {
uint32_t * persitence_start = (uint32_t *)&_exam_mode_buffer_start;
uint32_t * persitence_end = (uint32_t *)&_exam_mode_buffer_end;
while (persitence_start < persitence_end && *persitence_start == 0x0) {
// Skip even number of zero bits
persitence_start++;
}
if (persitence_start == persitence_end) {
assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0);
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start));
return (uint32_t *)&_exam_mode_buffer_start;
}
return persitence_start;
}
constexpr static size_t numberOfBitsInByte = 8;
size_t firstOneBit(int i, size_t size) {
// if i = 0b000011101, firstOneBitInByte(i) returns 5
size_t numberOfBitsAfterLeadingZeroes(int i) {
int minShift = 0;
int maxShift = size;
int maxShift = numberOfBitsInByte;
while (maxShift > minShift+1) {
int shift = (minShift + maxShift)/2;
int shifted = i >> shift;
@@ -57,23 +48,72 @@ size_t firstOneBit(int i, size_t size) {
return maxShift;
}
bool FetchExamMode() {
uint32_t * readingAddress = SignificantExamModeAddress();
size_t numberOfLeading0 = 32 - firstOneBit(*readingAddress, 32);
return numberOfLeading0 % 2 == 1;
uint8_t * SignificantExamModeAddress() {
uint32_t * persitence_start_32 = (uint32_t *)&_exam_mode_buffer_start;
uint32_t * persitence_end_32 = (uint32_t *)&_exam_mode_buffer_end;
assert(persitence_end_32 - persitence_start_32 % 4 == 0);
while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) {
// Scan by groups of 32 bits to reach first non-zero bit
persitence_start_32++;
}
uint8_t * persitence_start_8 = (uint8_t *)persitence_start_32;
uint8_t * persitence_end_8 = (uint8_t *)persitence_end_32;
while (persitence_start_8 < persitence_end_8 && *persitence_start_8 == 0x0) {
// Scan by groups of 8 bits to reach first non-zero bit
persitence_start_8++;
}
if (persitence_start_8 == persitence_end_8
// we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector
|| (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) {
assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0);
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start));
return (uint8_t *)&_exam_mode_buffer_start;
}
return persitence_start_8;
}
void ToggleExamMode() {
uint32_t * writingAddress = SignificantExamModeAddress();
uint8_t FetchExamMode() {
uint8_t * readingAddress = SignificantExamModeAddress();
// Count the number of 0[3] before reading address
uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % 3;
// Count the number of 0[3] at reading address
size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 3;
return (nbOfZerosBefore + numberOfLeading0) % 3;
}
void IncrementExamMode(uint8_t delta) {
assert(delta == 1 || delta == 2);
uint8_t * writingAddress = SignificantExamModeAddress();
assert(*writingAddress != 0);
// Compute the new value with one bit switched
uint8_t numberOfLeadingZeroes = 32 - firstOneBit(*writingAddress, 32);
/* When writing in flash, we can only switch a 1 to a 0. If we want to switch
* the fifth bit in a byte, we can thus write "11110111". */
uint32_t newValue = ~(1 << (31 - numberOfLeadingZeroes));
size_t nbOfTargetedOnes = numberOfBitsAfterLeadingZeroes(*writingAddress);
// Compute the new value with delta bits switched to 0.
/* We write in 2 bytes instead of 1, in case there was only one bit
* left to 1 in writingAddress. */
nbOfTargetedOnes += numberOfBitsInByte;
nbOfTargetedOnes -= delta;
constexpr size_t newValueSize = sizeof(uint16_t)/sizeof(uint8_t);
uint8_t newValue[newValueSize];
if (nbOfTargetedOnes > numberOfBitsInByte) {
size_t nbOfTargetedOnesInFirstByte = nbOfTargetedOnes - numberOfBitsInByte;
assert(nbOfTargetedOnesInFirstByte <= numberOfBitsInByte);
newValue[0] = ((uint16_t)1 << nbOfTargetedOnesInFirstByte) - 1;
newValue[1] = 0xFF;
} else {
assert(nbOfTargetedOnes <= numberOfBitsInByte);
newValue[0] = 0;
newValue[1] = ((uint16_t)1 << nbOfTargetedOnes) - 1;
}
// Write the value in flash
Ion::Device::Flash::WriteMemory((uint8_t *)writingAddress, (uint8_t *)&newValue, sizeof(uint32_t));
/* As the number of changed bits is capped by 2, if *writingAddress has more
* than one remaining 1 bit, we know we toggle bits only in the first byte of
* newValue. We can settle for writing one byte instead of two. */
size_t writtenFlash = *writingAddress == 1 ? sizeof(uint16_t) : sizeof(uint8_t);
/* Avoid writing out of sector */
assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 || (writingAddress == (uint8_t *)&_exam_mode_buffer_end - 1 && writtenFlash == 1));
Ion::Device::Flash::WriteMemory(writingAddress, newValue, writtenFlash);
}
}

View File

@@ -71,6 +71,8 @@ enum class Command : uint8_t {
Reset = 0x99,
// Erase the whole chip or a 64-Kbyte block as being "1"
ChipErase = 0xC7,
Erase4KbyteBlock = 0x20,
Erase32KbyteBlock = 0x52,
Erase64KbyteBlock = 0xD8,
SetReadParameters = 0xC0,
DeepPowerDown = 0xB9,
@@ -79,6 +81,8 @@ enum class Command : uint8_t {
};
static constexpr uint8_t NumberOfAddressBitsIn64KbyteBlock = 16;
static constexpr uint8_t NumberOfAddressBitsIn32KbyteBlock = 15;
static constexpr uint8_t NumberOfAddressBitsIn4KbyteBlock = 12;
class ExternalFlashStatusRegister {
public:
@@ -367,10 +371,23 @@ void shutdown() {
}
int SectorAtAddress(uint32_t address) {
/* WARNING: this code assumes that the flash sectors are of increasing size:
* first all 4K sectors, then all 32K sectors, and finally all 64K sectors. */
int i = address >> NumberOfAddressBitsIn64KbyteBlock;
if (i >= Config::NumberOfSectors) {
if (i > Config::NumberOf64KSectors) {
return -1;
}
if (i >= 1) {
return Config::NumberOf4KSectors + Config::NumberOf32KSectors + i - 1;
}
i = address >> NumberOfAddressBitsIn32KbyteBlock;
if (i >= 1) {
i = Config::NumberOf4KSectors + i - 1;
assert(i >= 0 && i <= Config::NumberOf32KSectors);
return i;
}
i = address >> NumberOfAddressBitsIn4KbyteBlock;
assert(i <= Config::NumberOf4KSectors);
return i;
}
@@ -408,7 +425,22 @@ void __attribute__((noinline)) EraseSector(int i) {
unlockFlash();
send_command(Command::WriteEnable);
wait();
send_write_command(Command::Erase64KbyteBlock, reinterpret_cast<uint8_t *>(i << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0);
/* WARNING: this code assumes that the flash sectors are of increasing size:
* first all 4K sectors, then all 32K sectors, and finally all 64K sectors. */
if (i < Config::NumberOf4KSectors) {
send_write_command(Command::Erase4KbyteBlock, reinterpret_cast<uint8_t *>(i << NumberOfAddressBitsIn4KbyteBlock), nullptr, 0);
} else if (i < Config::NumberOf4KSectors + Config::NumberOf32KSectors) {
/* If the sector is the number Config::NumberOf4KSectors, we want to write
* at the address 1 << NumberOfAddressBitsIn32KbyteBlock, hence the formula
* (i - Config::NumberOf4KSectors + 1). */
send_write_command(Command::Erase32KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors + 1) << NumberOfAddressBitsIn32KbyteBlock), nullptr, 0);
} else {
/* If the sector is the number
* Config::NumberOf4KSectors - Config::NumberOf32KSectors, we want to write
* at the address 1 << NumberOfAddressBitsIn32KbyteBlock, hence the formula
* (i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1). */
send_write_command(Command::Erase64KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1) << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0);
}
wait();
set_as_memory_mapped();
}

View File

@@ -15,7 +15,12 @@
* 2^7 64KiB blocks 0x..0000 - 0x..FFFF
* 2^7 * 2 32KiB blocks 0x..0000 - 0x..7FFF or 0x..8000 - 0x..FFFF
* 2^7 * 2 * 2^3 4KiB blocks 0x...000 - 0x...FFF
* 2^7 * 2 * 2^3 * 2^4 256B pages 0x....00 - 0x....FF */
* 2^7 * 2 * 2^3 * 2^4 256B pages 0x....00 - 0x....FF
*
* To be able to erase a small sector for the exam mode, we say that the flash
* is cut into 8 + 1 + 2^7-1 = 136 sectors: 8 sectors of 4Kb, 1 sector of 32Kb
* and 2^7-1 sectors of 64Kb. These sectors are the smallest erasable units. If
* need be, we can define more sectors to erase even more finely the flash. */
namespace Ion {
namespace Device {

View File

@@ -12,7 +12,13 @@ using namespace Regs;
void core() {
// Perform a full core reset
Ion::Device::Cache::dsb(); // Complete all memory accesses
CORTEX.AIRCR()->requestReset();
Ion::Device::Cache::dsb();
// Wait until reset
while (true) {
asm("nop");
}
}
/* We isolate the jump code that needs to be executed from the internal
@@ -41,8 +47,7 @@ void __attribute__((noinline)) internalFlashJump(uint32_t jumpIsrVectorAddress)
void jump(uint32_t jumpIsrVectorAddress) {
// Disable cache before reset
Ion::Device::Cache::disableDCache();
Ion::Device::Cache::disableICache();
Ion::Device::Cache::disable();
/* Shutdown all clocks and periherals to mimic a hardware reset. */
Board::shutdownPeripherals();

View File

@@ -72,6 +72,7 @@ public:
#if REGS_CORTEX_CONFIG_CACHE
class CCSIDR : public Register32 {
public:
using Register32::Register32;
REGS_FIELD(ASSOCIATIVITY, uint16_t, 12, 3);
REGS_FIELD(NUMSETS, uint16_t, 27, 13);
};
@@ -100,25 +101,20 @@ public:
using Register32::Register32;
};
class DCISW : public Register32 {
class DCSW : public Register32 {
public:
DCISW() : Register32(0) {}
DCSW() : Register32(0) {}
REGS_FIELD(SET, uint16_t, 13, 5);
REGS_FIELD(WAY, uint8_t, 31, 30);
};
class DCCSW : public Register32 {
public:
DCCSW() : Register32(0) {}
REGS_FIELD(SET, uint16_t, 13, 5);
REGS_FIELD(WAY, uint8_t, 31, 30);
class DCISW : public DCSW {
};
class DCCISW : public Register32 {
public:
DCCISW() : Register32(0) {}
REGS_FIELD(SET, uint16_t, 13, 5);
REGS_FIELD(WAY, uint8_t, 31, 30);
class DCCSW : public DCSW {
};
class DCCISW : public DCSW {
};
#endif

View File

@@ -4,6 +4,8 @@
#include <stdint.h>
#include <assert.h>
#define always_inline __attribute__((always_inline))
namespace Ion {
namespace Device {
namespace Regs {
@@ -22,7 +24,7 @@ public:
T get() volatile {
return m_value;
}
void setBitRange(uint8_t high, uint8_t low, T value) volatile {
always_inline void setBitRange(uint8_t high, uint8_t low, T value) volatile {
m_value = bit_range_set_value(high, low, m_value, value);
}
T getBitRange(uint8_t high, uint8_t low) volatile {
@@ -57,8 +59,8 @@ typedef Register<uint64_t> Register64;
}
}
#define REGS_FIELD_R(name,type,high,low) type get##name() volatile { return (type)getBitRange(high,low); };
#define REGS_FIELD_W(name,type,high,low) void set##name(type v) volatile { static_assert(sizeof(type) <= 4, "Invalid size"); setBitRange(high, low, static_cast<uint32_t>(v)); };
#define REGS_FIELD_R(name,type,high,low) always_inline type get##name() volatile { return (type)getBitRange(high,low); };
#define REGS_FIELD_W(name,type,high,low) always_inline void set##name(type v) volatile { static_assert(sizeof(type) <= 4, "Invalid size"); setBitRange(high, low, static_cast<uint32_t>(v)); };
#define REGS_FIELD(name,type,high,low) REGS_FIELD_R(name,type,high,low); REGS_FIELD_W(name,type,high,low);
#define REGS_TYPE_FIELD(name,high,low) REGS_FIELD(name,name,high,low)
#define REGS_BOOL_FIELD(name,bit) REGS_FIELD(name,bool,bit,bit)

View File

@@ -3,11 +3,11 @@
namespace Ion {
namespace ExamMode {
bool FetchExamMode() {
uint8_t FetchExamMode() {
return false;
}
void ToggleExamMode() {
void IncrementExamMode(uint8_t delta) {
}
}

View File

@@ -46,5 +46,6 @@ constexpr KDColor KDColorGreen = KDColor::RGB24(0x00FF00);
constexpr KDColor KDColorBlue = KDColor::RGB24(0x0000FF);
constexpr KDColor KDColorYellow = KDColor::RGB24(0xFFFF00);
constexpr KDColor KDColorOrange = KDColor::RGB24(0xFF9900);
constexpr KDColor KDColorPurple = KDColor::RGB24(0xFF00DD);
#endif

View File

@@ -9,6 +9,7 @@
namespace Poincare {
namespace ApproximationHelper {
template <typename T> int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
template <typename T> std::complex<T> TruncateRealOrImaginaryPartAccordingToArgument(std::complex<T> c);
template <typename T> using ComplexCompute = Complex<T>(*)(const std::complex<T>, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);

View File

@@ -15,6 +15,18 @@ template <typename T> T absMod(T a, T b) {
return result > b/2 ? b-result : result;
}
static inline int absInt(int x) { return x < 0 ? -x : x; }
template <typename T> int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) {
Evaluation<T> evaluation = expression->approximate(T(), context, complexFormat, angleUnit);
T scalar = evaluation.toScalar();
if (std::isnan(scalar) || scalar != (int)scalar) {
*isUndefined = true;
return 0;
}
return absInt((int)scalar);
}
template <typename T> std::complex<T> ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex<T> c) {
T arg = std::arg(c);
T precision = 10*Expression::Epsilon<T>();
@@ -92,6 +104,8 @@ template<typename T> MatrixComplex<T> ApproximationHelper::ElementWiseOnComplexM
return matrix;
}
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<float>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<double>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template std::complex<float> Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument<float>(std::complex<float>);
template std::complex<double> Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument<double>(std::complex<double>);
template Poincare::Evaluation<float> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<float> compute);

View File

@@ -1,5 +1,6 @@
#include <poincare/great_common_divisor.h>
#include <poincare/approximation_helper.h>
#include <poincare/arithmetic.h>
#include <poincare/layout_helper.h>
#include <poincare/rational.h>
@@ -27,22 +28,20 @@ Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionConte
template<typename T>
Evaluation<T> GreatCommonDivisorNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit);
T f1 = f1Input.toScalar();
T f2 = f2Input.toScalar();
if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) {
bool isUndefined = false;
int a = ApproximationHelper::PositiveIntegerApproximationIfPossible<T>(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit);
int b = ApproximationHelper::PositiveIntegerApproximationIfPossible<T>(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit);
if (isUndefined) {
return Complex<T>::Undefined();
}
int a = (int)f2;
int b = (int)f1;
if (f1 > f2) {
if (b > a) {
int temp = b;
b = a;
a = (int)f1;
a = temp;
}
int r = 0;
while((int)b!=0){
r = a - ((int)(a/b))*b;
r = a - (a/b)*b;
a = b;
b = r;
}

View File

@@ -1,4 +1,5 @@
#include <poincare/least_common_multiple.h>
#include <poincare/approximation_helper.h>
#include <poincare/rational.h>
#include <poincare/undefined.h>
#include <poincare/arithmetic.h>
@@ -27,26 +28,24 @@ Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionCont
template<typename T>
Evaluation<T> LeastCommonMultipleNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit);
T f1 = f1Input.toScalar();
T f2 = f2Input.toScalar();
if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) {
bool isUndefined = false;
int a = ApproximationHelper::PositiveIntegerApproximationIfPossible<T>(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit);
int b = ApproximationHelper::PositiveIntegerApproximationIfPossible<T>(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit);
if (isUndefined) {
return Complex<T>::Undefined();
}
if (f1 == 0.0f || f2 == 0.0f) {
if (a == 0 || b == 0) {
return Complex<T>::Builder(0.0);
}
int a = (int)f2;
int b = (int)f1;
if (f1 > f2) {
if (b > a) {
int temp = b;
b = a;
a = (int)f1;
a = temp;
}
int product = a*b;
int r = 0;
while((int)b!=0){
r = a - ((int)(a/b))*b;
r = a - (a/b)*b;
a = b;
b = r;
}

View File

@@ -269,12 +269,18 @@ QUIZ_CASE(poincare_approximation_function) {
assert_expression_approximates_to<float>("gcd(234,394)", "2");
assert_expression_approximates_to<double>("gcd(234,394)", "2");
assert_expression_approximates_to<float>("gcd(-234,394)", "2");
assert_expression_approximates_to<double>("gcd(234,-394)", "2");
assert_expression_approximates_to<float>("gcd(-234,-394)", "2");
assert_expression_approximates_to<float>("im(2+3𝐢)", "3");
assert_expression_approximates_to<double>("im(2+3𝐢)", "3");
assert_expression_approximates_to<float>("lcm(234,394)", "46098");
assert_expression_approximates_to<double>("lcm(234,394)", "46098");
assert_expression_approximates_to<float>("lcm(-234,394)", "46098");
assert_expression_approximates_to<double>("lcm(234,-394)", "46098");
assert_expression_approximates_to<float>("lcm(-234,-394)", "46098");
assert_expression_approximates_to<float>("int(x,x, 1, 2)", "1.5");
assert_expression_approximates_to<double>("int(x,x, 1, 2)", "1.5");