Compare commits

..

36 Commits

Author SHA1 Message Date
Laury
352cf39602 Merge overrightarrow 2021-11-11 20:21:44 +01:00
Mino1289
eed6683c74 Merge pull request #3 from Mino1289/upsilon-ref-latex
[apps/reader] Refactoring the LaTeX parser
2021-11-07 20:54:59 +01:00
Mino1289
9d5904396d [apps/reader] Fix rendering bug 2021-11-07 20:52:21 +01:00
Mino1289
7dec23dd91 Merge pull request #4 from devdl11/upsilon-ref-latex
[apps/reader] Fixing LD Error
2021-11-07 17:40:34 +01:00
dl11
e5fb5f390e LD Simple Fix 2021-11-07 17:05:55 +01:00
Mino1289
e3887ca077 [apps/reader] Refactoring the parser 2021-11-07 15:14:00 +01:00
Mino1289
46a30a6061 [kandinsky/font] Simplify including code_points 2021-11-05 16:49:04 +01:00
Mino1289
32ccd8530c [kandinsky/font build] Using all font only when reader app is defined, else it's the classic font 2021-11-04 23:59:18 +01:00
Mino1289
6ff8b007be Update apps/reader/README.md
Co-authored-by: Lauryy06 <80424145+Lauryy06@users.noreply.github.com>
2021-11-04 22:08:45 +01:00
Mino1289
0834cbd054 [apps/reader] Ajout d'une documentation (md & html) 2021-11-01 18:16:18 +01:00
Mino1289
a138ecaa9e [apps/reader] Ajout d'une documentation (md & html) 2021-11-01 18:14:55 +01:00
Mino1289
f8e6ee64ef [apps/reader] Changement de nom de certaines lettres grecs, comme LaTeX 2021-11-01 17:50:56 +01:00
Mino1289
5fbc7feaa1 [apps/reader] Ajout de \leq et \neq 2021-10-31 23:18:32 +01:00
Mino1289
1a2a61a43c [apps/reader build] Fix n0110 CI Merci @RedGl0w pour l'aide :) 2021-10-30 18:54:36 +02:00
Mino1289
25766967e2 [apps/reader] Add symbols and Arrows 2021-10-30 17:36:55 +02:00
Mino1289
52ac8e2acb [apps/reader] Changement du FLAG pour éviter de compiler certains caractères sans l'app reader 2021-10-30 17:34:53 +02:00
Mino1289
8cc09405e1 [apps/reader kandinsky/fonts] Remove useless font if reader app is not compiled 2021-10-29 15:24:44 +02:00
Mino1289
efdf2a379f [apps/reader] Ajout de toute les lettres grecs Majuscule 2021-10-27 21:46:54 +02:00
Laury
26496fbf00 [reader] Added ovverightarrow in parser and fix a bug in reader 2021-10-27 15:39:53 +02:00
Mino1289
668641ce95 [apps/reader] Toutes les lettres grecs en minuscule 2021-10-26 22:33:08 +02:00
Mino1289
72dfb76cc8 [apps/reader] Add mathematical symbols to TexParser 2021-10-26 20:07:34 +02:00
Mino1289
0dafa539df [apps/reader] TexParser fixed 2021-10-26 17:19:23 +02:00
Mino1289
36c984c73b [apps/reader] Modification du caractère d'erreur 2021-10-25 22:27:23 +02:00
Mino1289
fd5fba07e5 [apps/reader] Meilleur builder pour les symbols, mais ne marche pas 2021-10-24 15:15:59 +02:00
Mino1289
6e6ba6a985 [kandinsky] Extract lots of useful symbols of font file 2021-10-24 00:11:19 +02:00
Mino1289
57078755a3 [apps/reader] Support de \pi & \theta (compile mais n'affiche pas dans reader) 2021-10-23 23:28:02 +02:00
Lauryy06
710930d8e1 Merge branch 'upsilon-dev-latex' into upsilon-dev-latex 2021-10-23 13:35:52 +02:00
Laury
5c9bccdd99 [reader] Continuation of Latex parser 2021-10-23 00:21:28 +02:00
Mino1289
6ffb70e513 [apps/reader] oublie d'un ; 2021-10-23 00:09:46 +02:00
Mino1289
b42d4197c9 [apps/code] fix et réorganisation du fichier (un peu) 2021-10-23 00:07:19 +02:00
Mino1289
17be5934e0 [apps/reader] Ajout du support de \sqrt[n]{x} dans le parser LaTeX 2021-10-22 23:44:10 +02:00
Mino1289
18e7926500 Finish merging (unsolved conflicts) 2021-10-22 22:57:45 +02:00
Mino1289
559d5d26dd Merge branch 'upsilon-dev-latex' of https://github.com/Mino1289/Upsilon into upsilon-dev-latex 2021-10-22 22:55:50 +02:00
Laury
89c08acc7f [reader] Fix bug in Latex handling 2021-10-22 22:37:17 +02:00
Mino1289
04cf7bb0bf [apps/reader] Changing lot of if/else if for a switch statement 2021-10-22 22:09:57 +02:00
Laury
73f2a7ecac [reader] Foundation of latex handling 2021-10-22 21:23:35 +02:00
171 changed files with 3484 additions and 2971 deletions

View File

@@ -1,6 +1,6 @@
---
name: Bug report
about: Upsilon is not working like it should? Let us know!
about: Omega is not working like it should? Let us know!
title: ''
labels: 'Status: Triage, Type: Bug'
assignees: ''
@@ -23,7 +23,5 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device (please complete the following information):**
- The device on which you're running Upsilon (computer, n0110, n0100, etc...)
- Upsilon Version: [go to settings > about > Upsilon Version and type the version here]
- Upsilon commit: [settings > about > click one time on epsilon version]
**Desktop (please complete the following information):**
- Omega Version: [go to settings > about > Omega Version and type the version here]

View File

@@ -1,6 +1,6 @@
---
name: Feature request
about: Suggest an idea for Upsilon
about: Suggest an idea for Omega
title: ''
labels: 'Status: Triage, Type: Feature'
assignees: ''

View File

@@ -0,0 +1,28 @@
---
name: OMEGA BETA ONLY - Bug report
about: Omega 1.21 is not working like it should? Let us know!
title: "[BETA-1.21] …"
labels: 'Status: Triage, Type: Bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- Omega Version: [go to settings > about > Omega Version and type the version here]
- Discord username: ..........#....

View File

@@ -1,6 +1,6 @@
---
name: Problems during installation
about: Need help to install Upsilon?
about: Need help to install Omega?
title: ''
labels: 'Status: Triage, Type: Installation issue'
assignees: ''
@@ -16,4 +16,4 @@ Copy/paste the logs here (If you have some)
```
**Environment**
- Upsilon Version: {go to settings > about > Upsilon Version and type the version here}
- Omega Version: {go to settings > about > Omega Version and type the version here}

View File

@@ -140,7 +140,7 @@ jobs:
steps:
- uses: numworks/setup-emscripten@v1
with:
sdk: 1.40.1-fastcomp
sdk: latest-upstream
- uses: actions/checkout@v2
with:
submodules: 'recursive'

2
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "apps/rpn"]
path = apps/rpn
url = https://github.com/Lauryy06/Upsilon-RPN.git
url = https://github.com/Omega-Numworks/Omega-RPN.git
[submodule "apps/atomic"]
path = apps/atomic
url = https://github.com/Lauryy06/atomic

View File

@@ -126,7 +126,7 @@ Vous aurez besoin de devkitPro et de devkitARM disponible dans votre `$PATH` (in
```bash
git clone --recursive https://github.com/Lauryy06/Upsilon.git
cd Upsilon
git checkout --recursive upsilon-dev
git checkout --recursive omega-dev
make PLATFORM=simulator TARGET=3ds -j
```

View File

@@ -240,7 +240,7 @@ You need devkitPro and devkitARM installed and in your path (instructions [here]
```bash
git clone --recursive https://github.com/Lauryy06/Upsilon.git
cd Upsilon
git checkout --recursive upsilon-dev
git checkout --recursive omega-dev
make PLATFORM=simulator TARGET=3ds -j
```
You can then put epsilon.3dsx on a SD card to run it from the HBC or use 3dslink to launch it over the network:

View File

@@ -138,7 +138,7 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
Ion::LED::updateColorWithPlugAndCharge();
}
if (event == Ion::Events::USBEnumeration) {
if (Ion::USB::isPlugged() && GlobalPreferences::sharedGlobalPreferences()->getDfuLevel() != 3) {
if (Ion::USB::isPlugged()) {
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,9 +147,7 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
* pictogram. */
updateBatteryState();
if (switchTo(usbConnectedAppSnapshot())) {
Ion::USB::DFU(true, GlobalPreferences::sharedGlobalPreferences()->dfuStatus(), GlobalPreferences::sharedGlobalPreferences()->getDfuLevel());
GlobalPreferences::sharedGlobalPreferences()->dfuResetStep();
GlobalPreferences::sharedGlobalPreferences()->setDfuStatus(false);
Ion::USB::DFU();
// Update LED when exiting DFU mode
Ion::LED::updateColorWithPlugAndCharge();
bool switched = switchTo(activeSnapshot);

View File

@@ -75,13 +75,13 @@ void BatteryView::drawRect(KDContext * ctx, KDRect rect) const {
assert(!m_isPlugged);
// Low: Quite empty battery
ctx->fillRect(KDRect(batteryInsideX, 0, 2*k_elementWidth, k_batteryHeight), Palette::BatteryLow);
ctx->fillRect(KDRect(3*k_elementWidth+k_separatorThickness, 0, k_batteryWidth-5*k_elementWidth-2*k_separatorThickness, k_batteryHeight), KDColor::blend(Palette::Toolbar, Palette::Battery, 128));
ctx->fillRect(KDRect(3*k_elementWidth+k_separatorThickness, 0, k_batteryWidth-5*k_elementWidth-2*k_separatorThickness, k_batteryHeight), Palette::BatteryInCharge);
} else if (m_chargeState == Ion::Battery::Charge::SOMEWHERE_INBETWEEN) {
assert(!m_isPlugged);
// Middle: Half full battery
constexpr KDCoordinate middleChargeWidth = batteryInsideWidth/2;
ctx->fillRect(KDRect(batteryInsideX, 0, middleChargeWidth, k_batteryHeight), Palette::Battery);
ctx->fillRect(KDRect(batteryInsideX+middleChargeWidth, 0, middleChargeWidth, k_batteryHeight), KDColor::blend(Palette::Toolbar, Palette::Battery, 128));
ctx->fillRect(KDRect(batteryInsideX+middleChargeWidth, 0, middleChargeWidth, k_batteryHeight), Palette::BatteryInCharge);
} else {
assert(m_chargeState == Ion::Battery::Charge::FULL);
// Full but not plugged: Full battery

View File

@@ -29,12 +29,6 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
Context * context = App::app()->localContext();
Preferences * preferences = Preferences::sharedPreferences();
Poincare::ExpressionNode::ReductionContext reductionContext = Poincare::ExpressionNode::ReductionContext(context,
preferences->complexFormat(), preferences->angleUnit(),
GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
ExpressionNode::ReductionTarget::SystemForApproximation,
ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition,
Poincare::ExpressionNode::UnitConversion::Default);
PoincareHelpers::Reduce(&m_expression, context, ExpressionNode::ReductionTarget::SystemForAnalysis);
@@ -52,108 +46,60 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
Expression a = polynomialCoefficients[2];
Expression b = polynomialCoefficients[1];
Expression c = polynomialCoefficients[0];
bool aIsNotOne = !(a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isOne());
Expression delta = Subtraction::Builder(Power::Builder(b.clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), a.clone(), c.clone()));
PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
// Alpha is -b/2a, but because after we use -α, we immediately store -α=-(-b/2a)=b/2a.
Expression minusAlpha = Division::Builder(b.clone(), Multiplication::Builder(Rational::Builder(2), a.clone()));
PoincareHelpers::Reduce(&minusAlpha, context, ExpressionNode::ReductionTarget::SystemForApproximation);
Expression alpha = Opposite::Builder(Division::Builder(b.clone(), Multiplication::Builder(Rational::Builder(2), a.clone())));
PoincareHelpers::Simplify(&alpha, context, ExpressionNode::ReductionTarget::User);
// Same thing for β
Expression minusBeta = Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone()));
PoincareHelpers::Reduce(&minusBeta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
enum MultiplicationTypeForA {
Nothing,
Minus,
Parenthesis,
Normal
};
MultiplicationTypeForA multiplicationTypeForA;
if (a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isOne()) {
multiplicationTypeForA = MultiplicationTypeForA::Nothing;
}
else if(a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isMinusOne()){
multiplicationTypeForA = MultiplicationTypeForA::Minus;
}
else if (a.type() == ExpressionNode::Type::Addition) {
multiplicationTypeForA = MultiplicationTypeForA::Parenthesis;
}
else {
multiplicationTypeForA = MultiplicationTypeForA::Normal;
}
PoincareHelpers::Simplify(&a, context, ExpressionNode::ReductionTarget::User);
Expression beta = Opposite::Builder(Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone())));
PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
/*
* Because when can't apply reduce or simplify to keep the
* canonized form we must beautify the expression manually
* Because when can't apply reduce or simplify to keep the canonised
* we must beautify the expression manually
*/
Expression xMinusAlphaPowerTwo;
Expression alpha = getOppositeIfExists(minusAlpha, &reductionContext);
if (alpha.isUninitialized()) {
PoincareHelpers::Simplify(&minusAlpha, context, ExpressionNode::ReductionTarget::User);
xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), minusAlpha)), Rational::Builder(2));
Expression canonised;
if (alpha.type() == ExpressionNode::Type::Opposite) {
canonised = Addition::Builder(Symbol::Builder("x", strlen("x")), alpha.childAtIndex(0).clone());
}
else {
PoincareHelpers::Simplify(&alpha, context, ExpressionNode::ReductionTarget::User);
xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), alpha)), Rational::Builder(2));
canonised = Subtraction::Builder(Symbol::Builder("x", strlen("x")), alpha.clone());
}
Expression xMinusAlphaPowerTwoWithFactor;
switch (multiplicationTypeForA)
{
case MultiplicationTypeForA::Nothing:
xMinusAlphaPowerTwoWithFactor = xMinusAlphaPowerTwo;
break;
case MultiplicationTypeForA::Minus:
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(a.clone(), xMinusAlphaPowerTwo);
break;
case MultiplicationTypeForA::Parenthesis:
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(Parenthesis::Builder(a.clone()), xMinusAlphaPowerTwo);
break;
case MultiplicationTypeForA::Normal:
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(a.clone(), xMinusAlphaPowerTwo);
break;
default:
assert(false);
break;
canonised = Power::Builder(Parenthesis::Builder(canonised.clone()), Rational::Builder(2));
if (aIsNotOne) {
canonised = Multiplication::Builder(a.clone(), canonised.clone());
}
Expression canonized;
Expression beta = getOppositeIfExists(minusBeta, &reductionContext);
if (beta.isUninitialized()) {
PoincareHelpers::Simplify(&minusBeta, context, ExpressionNode::ReductionTarget::User);
canonized = Subtraction::Builder(xMinusAlphaPowerTwoWithFactor, minusBeta);
if (beta.type() == ExpressionNode::Type::Opposite) {
canonised = Subtraction::Builder(canonised.clone(), beta.childAtIndex(0).clone());
}
else {
PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
canonized = Addition::Builder(xMinusAlphaPowerTwoWithFactor, beta);
canonised = Addition::Builder(canonised.clone(), beta.clone());
}
Expression x0;
Expression x1;
if (delta.nullStatus(context) == ExpressionNode::NullStatus::Null) {
// x0 = x1 = -b/(2a)
x0 = Division::Builder(Opposite::Builder(b.clone()), Multiplication::Builder(Rational::Builder(2), a.clone()));
x0 = Division::Builder(Opposite::Builder(b), Multiplication::Builder(Rational::Builder(2), a));
m_numberOfSolutions = 1;
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
}
else {
// x0 = (-b-sqrt(delta))/(2a)
x0 = Division::Builder(Subtraction::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
// x1 = (-b+sqrt(delta))/(2a)
x1 = Division::Builder(Addition::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
x1 = Division::Builder(Addition::Builder(Opposite::Builder(b), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a));
m_numberOfSolutions = 2;
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::SystemForApproximation);
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
if (x0.type() == ExpressionNode::Type::Unreal) {
assert(x1.type() == ExpressionNode::Type::Unreal);
m_numberOfSolutions = 0;
@@ -163,87 +109,40 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
Expression factorized;
if (m_numberOfSolutions == 2) {
Expression firstFactor;
Expression secondFactor;
Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
if (x0Opposite.isUninitialized()) {
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
firstFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0);
}
else {
PoincareHelpers::Simplify(&x0Opposite, context, ExpressionNode::ReductionTarget::User);
firstFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite);
}
if (x0.type() == ExpressionNode::Type::Opposite) {
factorized = Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x0.childAtIndex(0).clone()));
}
Expression x1Opposite = getOppositeIfExists(x1, &reductionContext);
if (x1Opposite.isUninitialized()) {
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
secondFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1);
else {
factorized = Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone()));
}
if (x1.type() == ExpressionNode::Type::Opposite) {
factorized = Multiplication::Builder(factorized.clone(), Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x1.childAtIndex(0).clone())));
}
else {
PoincareHelpers::Simplify(&x1Opposite, context, ExpressionNode::ReductionTarget::User);
secondFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x1Opposite);
factorized = Multiplication::Builder(factorized.clone(), Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1.clone())));
}
Expression solutionProduct = Multiplication::Builder(Parenthesis::Builder(firstFactor), Parenthesis::Builder(secondFactor));
switch (multiplicationTypeForA)
{
case MultiplicationTypeForA::Nothing:
factorized = solutionProduct;
break;
case MultiplicationTypeForA::Minus:
factorized = Multiplication::Builder(a.clone(), solutionProduct);
break;
case MultiplicationTypeForA::Parenthesis:
factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
break;
case MultiplicationTypeForA::Normal:
factorized = Multiplication::Builder(a.clone(), solutionProduct);
break;
default:
assert(false);
break;
if (aIsNotOne) {
factorized = Multiplication::Builder(a.clone(), factorized.clone());
}
}
else if (m_numberOfSolutions == 1) {
Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
Expression factor;
if (x0Opposite.isUninitialized()) {
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
factor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0);
if (x0.type() == ExpressionNode::Type::Opposite) {
factorized = Power::Builder(Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x0.childAtIndex(0).clone())), Rational::Builder(2));
}
else {
PoincareHelpers::Simplify(&x0Opposite, context, ExpressionNode::ReductionTarget::User);
factor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite);
factorized = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone())), Rational::Builder(2));
}
Expression solutionProduct = Power::Builder(Parenthesis::Builder(factor), Rational::Builder(2));
switch (multiplicationTypeForA)
{
case MultiplicationTypeForA::Nothing:
factorized = solutionProduct;
break;
case MultiplicationTypeForA::Minus:
factorized = Multiplication::Builder(a.clone(), solutionProduct);
break;
case MultiplicationTypeForA::Parenthesis:
factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
break;
case MultiplicationTypeForA::Normal:
factorized = Multiplication::Builder(a.clone(), solutionProduct);
break;
default:
assert(false);
break;
if (aIsNotOne) {
factorized = Multiplication::Builder(a.clone(), factorized.clone());
}
}
PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::User);
m_layouts[0] = PoincareHelpers::CreateLayout(canonized);
m_layouts[0] = PoincareHelpers::CreateLayout(canonised);
if (m_numberOfSolutions > 0) {
m_layouts[1] = PoincareHelpers::CreateLayout(factorized);
m_layouts[2] = PoincareHelpers::CreateLayout(delta);
@@ -257,27 +156,6 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
}
}
Expression SecondDegreeListController::getOppositeIfExists(Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext) {
if (e.isNumber() && e.sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
Number n = static_cast<Number&>(e);
return std::move(n.setSign(ExpressionNode::Sign::Positive));
}
else if (e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() > 0 && e.childAtIndex(0).isNumber() && e.childAtIndex(0).sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
Multiplication m = static_cast<Multiplication&>(e);
if (m.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast<Rational&>(e).isMinusOne()) {
// The negative numeral factor is -1, we just remove it
m.removeChildAtIndexInPlace(0);
} else {
Expression firstChild = m.childAtIndex(0);
Number n = static_cast<Number&>(firstChild);
m.childAtIndex(0).setChildrenInPlace(n.setSign(ExpressionNode::Sign::Positive));
}
PoincareHelpers::Simplify(&m, reductionContext->context(), ExpressionNode::ReductionTarget::User);
return std::move(m);
}
return Expression();
}
I18n::Message SecondDegreeListController::messageAtIndex(int index) {
if (m_numberOfSolutions > 0) {
if (index == 0) {

View File

@@ -14,7 +14,6 @@ public:
void setExpression(Poincare::Expression e) override;
private:
Poincare::Expression getOppositeIfExists(Poincare::Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext);
I18n::Message messageAtIndex(int index) override;
int m_numberOfSolutions;
};

View File

@@ -81,7 +81,7 @@ void HistoryViewCell::reloadSubviewHighlight() {
m_ellipsis.setHighlighted(false);
if (isHighlighted()) {
if (m_dataSource->selectedSubviewType() == HistoryViewCellDataSource::SubviewType::Input) {
m_inputView.setExpressionBackgroundColor(Palette::Select);
m_inputView.setExpressionBackgroundColor(Palette::ListCellBackgroundSelected);
} else if (m_dataSource->selectedSubviewType() == HistoryViewCellDataSource::SubviewType::Output) {
m_scrollableOutputView.evenOddCell()->setHighlighted(true);
} else {

View File

@@ -1,8 +1,6 @@
apps += Code::App
app_headers += apps/code/app.h
SFLAGS += -DHAS_CODE
app_code_src = $(addprefix apps/code/,\
app.cpp \
console_controller.cpp \

View File

@@ -102,7 +102,7 @@ void EditorView::GutterView::setOffset(KDCoordinate offset) {
KDSize EditorView::GutterView::minimalSizeForOptimalDisplay() const {
int numberOfChars = 2; // TODO: Could be computed
return KDSize(2 * k_margin + numberOfChars * m_font->glyphSize().width(), 0);
return KDSize(2 * k_margin + numberOfChars * Poincare::Preferences::sharedPreferences()->KDPythonFont()->glyphSize().width(), 0);
}
}

View File

@@ -21,10 +21,10 @@ void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) cons
const int nodeNameLength = m_scriptNode->nameLength();
KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength);
const KDCoordinate nodeNameY = k_topMargin;
ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, Palette::PrimaryText, backgroundColor, nodeNameLength);
ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength);
// If it is needed, draw the parentheses
if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) {
ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, Palette::PrimaryText, backgroundColor);
ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor);
}
/* If it exists, draw the source name. If it did not fit, we would have put

View File

@@ -8,9 +8,11 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
return ScriptBaseNamed(baseName).isNull();
}
// Here we add "base" script
ScriptStore::ScriptStore() {
addScriptFromTemplate(ScriptTemplate::Squares());
addScriptFromTemplate(ScriptTemplate::Parabola());
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
addScriptFromTemplate(ScriptTemplate::Polynomial());
}
void ScriptStore::deleteAllScripts() {

View File

@@ -5,9 +5,103 @@ namespace Code {
constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import *
)");
constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"(from math import *
from turtle import *
def squares(angle=0.5):
reset()
L=330
speed(10)
penup()
goto(-L/2,-L/2)
pendown()
for i in range(660):
forward(L)
left(90+angle)
L=L-L*sin(angle*pi/180)
hideturtle())");
constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set
# N_iteration: degree of precision
import kandinsky
def mandelbrot(N_iteration):
for x in range(320):
for y in range(222):
# Compute the mandelbrot sequence for the point c = (c_r, c_i) with start value z = (z_r, z_i)
z = complex(0,0)
# Rescale to fit the drawing screen 320x222
c = complex(3.5*x/319-2.5, -2.5*y/221+1.25)
i = 0
while (i < N_iteration) and abs(z) < 2:
i = i + 1
z = z*z+c
# Choose the color of the dot from the Mandelbrot sequence
rgb = int(255*i/N_iteration)
col = kandinsky.color(int(rgb*0.82),int(rgb*0.13),int(rgb*0.18))
# Draw a pixel colored in 'col' at position (x,y)
kandinsky.set_pixel(x,y,col))");
constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import *
# roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0
def roots(a,b,c):
delta = b*b-4*a*c
if delta == 0:
return -b/(2*a)
elif delta > 0:
x_1 = (-b-sqrt(delta))/(2*a)
x_2 = (-b+sqrt(delta))/(2*a)
return x_1, x_2
else:
return None)");
constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import *
from math import *
g=9.81
def x(t,v_0,alpha):
return v_0*cos(alpha)*t
def y(t,v_0,alpha,h_0):
return -0.5*g*t**2+v_0*sin(alpha)*t+h_0
def vx(v_0,alpha):
return v_0*cos(alpha)
def vy(t,v_0,alpha):
return -g*t+v_0*sin(alpha)
def t_max(v_0,alpha,h_0):
return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g
def simulation(v_0=15,alpha=pi/4,h_0=2):
tMax=t_max(v_0,alpha,h_0)
accuracy=1/10**(floor(log10(tMax))-1)
T_MAX=floor(tMax*accuracy)+1
X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]
Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]
VX=[vx(v_0,alpha) for t in range(T_MAX)]
VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]
for i in range(T_MAX):
arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)
grid()
show())");
const ScriptTemplate * ScriptTemplate::Empty() {
return &emptyScriptTemplate;
}
const ScriptTemplate * ScriptTemplate::Squares() {
return &squaresScriptTemplate;
}
const ScriptTemplate * ScriptTemplate::Mandelbrot() {
return &mandelbrotScriptTemplate;
}
const ScriptTemplate * ScriptTemplate::Polynomial() {
return &polynomialScriptTemplate;
}
const ScriptTemplate * ScriptTemplate::Parabola() {
return &parabolaScriptTemplate;
}
}

View File

@@ -9,6 +9,10 @@ class ScriptTemplate {
public:
constexpr ScriptTemplate(const char * name, const char * value) : m_name(name), m_value(value) {}
static const ScriptTemplate * Empty();
static const ScriptTemplate * Squares();
static const ScriptTemplate * Mandelbrot();
static const ScriptTemplate * Polynomial();
static const ScriptTemplate * Parabola();
const char * name() const { return m_name; }
const char * content() const { return m_value + Script::StatusSize(); }
const char * value() const { return m_value; }

View File

@@ -37,10 +37,10 @@ namespace Code {
}
void toolboxIonKeys::toolboxIonView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, Palette::WallScreen);
ctx->strokeRect(rect, Palette::ListCellBorder);
ctx->drawString(I18n::translate(I18n::Message::PressAKey),KDPoint(rect.left()+80, rect.top()+20),KDFont::LargeFont,Palette::PrimaryText,Palette::WallScreen);
ctx->fillRect(rect, Palette::GrayBright);
ctx->strokeRect(rect, Palette::GrayDark);
ctx->drawString(I18n::translate(I18n::Message::PressAKey),KDPoint(rect.left()+80, rect.top()+20));
}
View * toolboxIonKeys::view(){

View File

@@ -30,15 +30,6 @@ 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; }
@@ -46,7 +37,6 @@ 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
@@ -56,10 +46,6 @@ 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) {}
@@ -70,10 +56,6 @@ 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;

View File

@@ -2,5 +2,3 @@ Apps = "Anwendungen"
AppsCapital = "UPSILON"
ForbidenAppInExamMode1 = "Diese Anwendung ist im"
ForbidenAppInExamMode2 = "Prüfungsmodus nicht erlaubt."
DfuWarning1 = "DFU-Schutzwarnung"
DfuWarning2 = "Mehr Informationen: bit.ly/upsiDfu"

View File

@@ -2,5 +2,3 @@ Apps = "Applications"
AppsCapital = "UPSILON"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"
DfuWarning1 = "DFU Protection Warning"
DfuWarning2 = "More informations: bit.ly/upsiDfu"

View File

@@ -2,5 +2,3 @@ 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"

View File

@@ -2,5 +2,3 @@ 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"

View File

@@ -2,5 +2,3 @@ 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"

View File

@@ -2,5 +2,3 @@ Apps = "Applicazioni"
AppsCapital = "UPSILON"
ForbidenAppInExamMode1 = "Questa applicazione è"
ForbidenAppInExamMode2 = "proibita nella modalità d'esame"
DfuWarning1 = "Avviso protezione DFU"
DfuWarning2 = "Più informazioni: bit.ly/upsiDfu"

View File

@@ -2,5 +2,3 @@ Apps = "Applicaties"
AppsCapital = "UPSILON"
ForbidenAppInExamMode1 = "Deze applicatie is"
ForbidenAppInExamMode2 = "uitgesloten in examenstand"
DfuWarning1 = "DFU-beveiligingswaarschuwing"
DfuWarning2 = "Meer informatie: bit.ly/upsiDfu"

View File

@@ -2,5 +2,3 @@ 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"

View File

@@ -87,33 +87,9 @@ 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()) {

View File

@@ -5,7 +5,7 @@
MathVariableBoxEmptyController::MathVariableBoxEmptyView::MathVariableBoxEmptyView() :
ModalViewEmptyView(),
m_layoutExample(0.5f, 0.5f, Palette::PrimaryText, Palette::WallScreen)
m_layoutExample(0.5f, 0.5f, KDColorBlack, Palette::WallScreen)
{
initMessageViews();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,12 +1,15 @@
apps += Reader::App
app_headers += apps/reader/app.h
SFLAGS += -DHAS_READER
app_sreader_src = $(addprefix apps/reader/,\
app.cpp \
list_book_controller.cpp \
utility.cpp \
read_book_controller \
word_wrap_view.cpp \
tex_parser.cpp \
)
apps_src += $(app_sreader_src)

View File

@@ -6,8 +6,10 @@ Thanks to [Gabriel79](https://github.com/Gabriel79) for the original reader app,
# Rich text format
Reader app supports now a rich text format :
* `$` around a mathematical expression **without spaces** to render it
* `$` around a LaTeX expression to render it
* `%` around a color-code (see below) to change the color of the text
### LaTeX expressions
You can read the documentation for the LaTeX Parser [here](TexParser.md).
### Color codes :
|code|color|
| --:| ---:|

1901
apps/reader/TexParser.html Normal file

File diff suppressed because it is too large Load Diff

51
apps/reader/TexParser.md Normal file
View File

@@ -0,0 +1,51 @@
# LaTeX Parser
In the reader app, you can read a txt file. You can also read a txt file with LaTeX expression inside of it.
All the symbols you can use are listed here :
|Command|Output||Command|Output|
|--:|:--:|--:|--:|:--:|
|Math|Expressions||||
|`\frac{ab}{cd}`|$\frac{ab}{cd}$||`\sqrt[n]{x}`|$\sqrt[n]{x}$|
|Math|Symbols|||
|`\times`|$\times$||`\div`|$\div$|
|`\forall`|$\forall$||`\exists`|$\exists$|
|`\partial`|$\partial$||`\pm`|$\pm$|
|`\infty`|$\infty$||`\approx`|$\approx$|
|`\neq`|$\neq$||`\equiv`|$\equiv$|
|`\leq`|$\leq$||`\geq`|$\geq$|
|Simple|Arrows||Double|Arrows|
|`\leftarrow`|$\leftarrow$||`\Leftarrow`|$\Leftarrow$|
|`\rightarrow`|$\rightarrow$||`\Rightarrow`|$\Rightarrow$|
|`\uparrow`|$\uparrow$||`\Uparrow`|$\Uparrow$|
|`\downarrow`|$\downarrow$||`\Downarrow`|$\Downarrow$|
|`\leftrightarrow`|$\leftrightarrow$||||
|`\updownarrow`|$\updownarrow$||||
|Greek Capital|Letters||Greek Small|Letters|
|`\Alpha`|$\Alpha$||`\alpha`|$\alpha$|
|`\Beta`|$\Beta$||`\beta`|$\beta$|
|`\Gamma`|$\Gamma$||`\gamma`|$\gamma$|
|`\Delta`|$\Delta$||`\delta`|$\delta$|
|`\Epsilon`|$\Epsilon$||`\epsilon`|$\epsilon$|
|`\Zeta`|$\Zeta$||`\zeta`|$\zeta$|
|`\Eta`|$\Eta$||`\eta`|$\eta$|
|`\Theta`|$\Theta$||`\theta`|$\theta$|
|`\Iota`|$\Iota$||`\iota`|$\iota$|
|`\Kappa`|$\Kappa$||`\kappa`|$\kappa$|
|`\Lambda`|$\Lambda$||`\lambda`|$\lambda$|
|`\Mu`|$\Mu$||`\mu`|$\mu$|
|`\Nu`|$\Nu$||`\nu`|$\nu$|
|`\Xi`|$\Xi$||`\xi`|$\xi$|
|`\Omicron`|$\Omicron$|||
|`\Pi`|$\Pi$||`\pi`|$\pi$|
|`\Rho`|$\Rho$||`\rho`|$\rho$|
|`\Sigma`|$\Sigma$||`\sigma`|$\sigma$|
|`\Tau`|$\Tau$||`\tau`|$\tau$|
|`\Upsilon`|$\Upsilon$||`\upsilon`|$\upsilon$|
|`\Phi`|$\Phi$||`\phi`|$\phi$|
|`\Chi`|$\Chi$||`\chi`|$\chi$|
|`\Psi`|$\Psi$||`\psi`|$\psi$|
|`\Omega`|$\Omega$||`\omega`|$\omega$|

210
apps/reader/tex_parser.cpp Normal file
View File

@@ -0,0 +1,210 @@
#include "tex_parser.h"
#include <ion/unicode/utf8_decoder.h>
namespace Reader {
// List of available Symbols
static constexpr char const * k_SymbolsCommands[] = {
"times", "div", "forall", "partial", "exists", "pm", "approx", "infty", "neq", "equiv", "leq", "geq",
"leftarrow", "uparrow", "rightarrow", "downarrow", "leftrightarrow", "updownarrow", "Leftarrow", "Uparrow", "Rightarrow", "Downarrow",
"Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda",
"Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi","Omega",
"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda",
"mu", "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega",
};
//List of the available Symbol's CodePoints in the same order of the Symbol's list
static constexpr uint32_t const k_SymbolsCodePoints[] = {
0xd7, 0xf7, 0x2200, 0x2202, 0x2203, 0xb1, 0x2248, 0x221e, 0x2260, 0x2261, 0x2264, 0x2265,
0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b,
0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9,
0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb,
0x3bc, 0x3bd, 0x3be, 0x3bf, 0x3c0, 0x3c1, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x3c8, 0x3c9
};
// List of available Function Commands that don't require a specific handling
static constexpr char const * k_FunctionCommands[] = {
"arcos", "arcsin", "arctan", "arg", "cos", "cosh", "cot", "coth",
"csc", "deg", "det", "dim", "exp", "gcd", "hom", "inf",
"ker", "lg", "lim", "liminf", "limsup", "ln", "log", "max",
"min", "Pr", "sec", "sin", "sinh", "sup", "tan", "tanh"
};
TexParser::TexParser(const char * text, const char * endOfText) :
m_text(text),
m_endOfText(endOfText),
m_hasError(false)
{
}
Layout TexParser::getLayout() {
Layout layout = popText(0);
if (m_hasError) {
return CodePointLayout::Builder(CodePoint(0xfffd));
}
return layout;
}
Layout TexParser::popBlock() {
while (*m_text == ' ') {
m_text ++;
}
if (*m_text == '{') {
m_text ++;
return popText('}');
}
if (*m_text == '\\') {
m_text ++;
return popCommand();
}
if (m_text >= m_endOfText) {
m_hasError = true;
}
UTF8Decoder decoder(m_text);
m_text ++;
return CodePointLayout::Builder(decoder.nextCodePoint());
}
Layout TexParser::popText(char stop) {
HorizontalLayout layout = HorizontalLayout::Builder();
const char * start = m_text;
while (m_text < m_endOfText && *m_text != stop) {
switch (*m_text) {
// TODO: Factorize this code
case '\\':
if (start != m_text) {
layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
}
m_text ++;
layout.addOrMergeChildAtIndex(popCommand(), layout.numberOfChildren(), false);
start = m_text;
break;
case ' ':
if (start != m_text) {
layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
}
m_text ++;
start = m_text;
break;
case '^':
if (start != m_text) {
layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
}
m_text ++;
layout.addOrMergeChildAtIndex(VerticalOffsetLayout::Builder(popBlock(), VerticalOffsetLayoutNode::Position::Superscript), layout.numberOfChildren(), false);
start = m_text;
break;
case '_':
if (start != m_text) {
layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
}
m_text ++;
layout.addOrMergeChildAtIndex(VerticalOffsetLayout::Builder(popBlock(), VerticalOffsetLayoutNode::Position::Subscript), layout.numberOfChildren(), false);
start = m_text;
break;
default:
m_text ++;
}
}
if (start != m_text) {
layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
}
m_text ++;
if (layout.numberOfChildren() == 1) {
return layout.squashUnaryHierarchyInPlace();
}
return layout;
}
Layout TexParser::popCommand() {
// TODO: Factorize this code
if (strncmp(k_fracCommand, m_text, strlen(k_fracCommand)) == 0) {
if (isCommandEnded(*(m_text + strlen(k_fracCommand)))) {
m_text += strlen(k_fracCommand);
return popFracCommand();
}
}
if (strncmp(k_sqrtCommand, m_text, strlen(k_sqrtCommand)) == 0) {
if (isCommandEnded(*(m_text + strlen(k_sqrtCommand)))) {
m_text += strlen(k_sqrtCommand);
return popSqrtCommand();
}
}
if (strncmp(k_overrightArrowCommand, m_text, strlen(k_overrightArrowCommand)) == 0) {
if (isCommandEnded(*(m_text + strlen(k_overrightArrowCommand)))) {
m_text += strlen(k_overrightArrowCommand);
return popOverrightarrowCommand();
}
}
for (int i = 0; i < k_NumberOfSymbols; i++) {
if (strncmp(k_SymbolsCommands[i], m_text, strlen(k_SymbolsCommands[i])) == 0) {
if (isCommandEnded(*(m_text + strlen(k_SymbolsCommands[i])))) {
m_text += strlen(k_SymbolsCommands[i]);
return popSymbolCommand(i);
}
}
}
for (int i = 0; i < k_NumberOfFunctionCommands; i++) {
if (strncmp(k_FunctionCommands[i], m_text, strlen(k_FunctionCommands[i])) == 0) {
if (isCommandEnded(*(m_text + strlen(k_FunctionCommands[i])))) {
m_text += strlen(k_FunctionCommands[i]);
return LayoutHelper::String(k_FunctionCommands[i], strlen(k_FunctionCommands[i]));
}
}
}
m_hasError = true;
return LayoutHelper::String(m_text, strlen(m_text));
}
// Expressions
Layout TexParser::popFracCommand() {
Layout numerator = popBlock();
Layout denominator = popBlock();
FractionLayout l = FractionLayout::Builder(numerator, denominator);
return l;
}
Layout TexParser::popSqrtCommand() {
while (*m_text == ' ') {
m_text ++;
}
if (*m_text == '[') {
m_text ++;
Layout rootFactor = popText(']');
Layout belowRoot = popBlock();
return NthRootLayout::Builder(belowRoot, rootFactor);
}
else {
return NthRootLayout::Builder(popBlock());
}
}
Layout TexParser::popOverrightarrowCommand() {
return VectorLayout::Builder(popBlock());
}
Layout TexParser::popSymbolCommand(int SymbolIndex) {
uint32_t codePoint = k_SymbolsCodePoints[SymbolIndex];
return CodePointLayout::Builder(codePoint);
}
inline bool TexParser::isCommandEnded(char c) const {
return !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z');
}
}

47
apps/reader/tex_parser.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef __TEX_PARSER_H__
#define __TEX_PARSER_H__
#include <poincare_layouts.h>
#include <poincare/layout_helper.h>
#include <string.h>
using namespace Poincare;
namespace Reader
{
/// @brief Class used in the WordWrapTextView class to parse a Tex expression
class TexParser {
public:
TexParser(const char * text, const char * endOfText);
Layout getLayout();
private:
Layout popBlock();
Layout popText(char stop);
Layout popCommand();
// Expressions
Layout popFracCommand();
Layout popSqrtCommand();
Layout popOverrightarrowCommand();
//Symbols
Layout popSymbolCommand(int SymbolIndex);
const char * m_text;
const char * m_endOfText;
bool m_hasError;
inline bool isCommandEnded(char c) const;
// Expressions that require specific handling
static constexpr char const * k_fracCommand = "frac";
static constexpr char const * k_sqrtCommand = "sqrt";
static constexpr char const * k_overrightArrowCommand = "overrightarrow";
static constexpr int const k_NumberOfSymbols = 70;
static constexpr int const k_NumberOfFunctionCommands = 32;
};
}
#endif

View File

@@ -117,7 +117,7 @@ const char * EndOfPrintableWord(const char * word, const char * end) {
UTF8Decoder decoder(word);
CodePoint codePoint = decoder.nextCodePoint();
const char * result = word;
while (codePoint != '\n' && codePoint != ' ' && codePoint != '%') {
while (codePoint != '\n' && codePoint != ' ' && codePoint != '%' && codePoint != '$') {
result = decoder.stringPosition();
if (result >= end) {
break;
@@ -127,4 +127,21 @@ const char * EndOfPrintableWord(const char * word, const char * end) {
return result;
}
const char * StartOfPrintableWord(const char * word, const char * start) {
if (word == start) {
return word;
}
UTF8Decoder decoder(start, word);
CodePoint codePoint = decoder.previousCodePoint();
const char * result = word;
while (codePoint != '\n' && codePoint != ' ' && codePoint != '%' && codePoint != '$') {
result = decoder.stringPosition();
if (result >= start) {
break;
}
codePoint = decoder.previousCodePoint();
}
return result;
}
}

View File

@@ -12,6 +12,7 @@ bool stringEndsWith(const char* str, const char* end);
int filesWithExtension(const char* extension, External::Archive::File* files, int filesSize);
void stringNCopy(char* dest, int max, const char* src, int len);
const char * EndOfPrintableWord(const char * word, const char * end);
const char * StartOfPrintableWord(const char * word, const char * start);
}
#endif

View File

@@ -1,6 +1,7 @@
#include "word_wrap_view.h"
#include "utility.h"
#include "tex_parser.h"
#include <poincare/expression.h>
#include "../shared/poincare_helpers.h"
#include <poincare/undefined.h>
@@ -38,16 +39,17 @@ void WordWrapTextView::previousPage() {
const int charWidth = m_font->glyphSize().width();
const int charHeight = m_font->glyphSize().height();
const char * endOfWord = text() + m_pageOffset - 1;
const char * startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
const char * endOfFile = text() + m_length;
const char * endOfWord = text() + m_pageOffset;
const char * startOfWord = StartOfPrintableWord(endOfWord, text());
KDSize textSize = KDSizeZero;
KDPoint textEndPosition(m_frame.width() - k_margin, m_frame.height() - k_margin);
while(startOfWord>=text()) {
startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
endOfWord = UTF8Helper::EndOfWord(startOfWord);
startOfWord = StartOfPrintableWord(endOfWord-1, text());
//endOfWord = EndOfPrintableWord(startOfWord, endOfFile);
if (*startOfWord == '%') {
if (updateTextColorBackward(startOfWord)) {
@@ -55,20 +57,28 @@ void WordWrapTextView::previousPage() {
continue;
}
}
if (*startOfWord == '$' && *(endOfWord-1) == '$') {
const int wordMaxLength = 128;
char word[wordMaxLength];
stringNCopy(word, wordMaxLength, startOfWord + 1, endOfWord-startOfWord-2);
Poincare::Expression expr = Poincare::Expression::Parse(word, nullptr);
if (expr.isUninitialized()) {
expr = Poincare::Undefined::Builder();
if (*endOfWord == '$') {
startOfWord = endOfWord - 1;
while (*startOfWord != '$') {
if (startOfWord < text()) {
break; // File isn't rightly formated
}
startOfWord --;
}
Poincare::Layout layout = Shared::PoincareHelpers::CreateLayout(expr);
textSize = layout.layoutSize();
startOfWord --;
TexParser parser = TexParser(startOfWord + 1, endOfWord - 2);
Poincare::Layout layout = parser.getLayout();
textSize = layout.layoutSize();
}
else {
textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
if (*startOfWord == '\\' || *(startOfWord + 1) == '$') {
textSize = m_font->stringSizeUntil(startOfWord + 1, endOfWord);
}
else {
textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
}
}
KDPoint textStartPosition = KDPoint(textEndPosition.x()-textSize.width(), textEndPosition.y());
@@ -109,7 +119,7 @@ void WordWrapTextView::previousPage() {
m_pageOffset = 0;
}
else {
m_pageOffset = UTF8Helper::EndOfWord(startOfWord) - text() + 1;
m_pageOffset = EndOfPrintableWord(startOfWord, endOfFile) - text() + 1;
}
markRectAsDirty(bounds());
}
@@ -119,7 +129,12 @@ void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
const char * endOfFile = text() + m_length;
const char * startOfWord = text() + m_pageOffset;
const char * endOfWord = EndOfPrintableWord(startOfWord, endOfFile);
const char * endOfWord;
if (*startOfWord != '$') {
endOfWord = EndOfPrintableWord(startOfWord, endOfFile);
} // Else we don't need to update endOfWord
KDPoint textPosition(k_margin, k_margin);
const int wordMaxLength = 128;
@@ -152,18 +167,26 @@ void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
continue;
}
}
if (*startOfWord == '$' && *(endOfWord-1) == '$') { // Look for expression
stringNCopy(word, wordMaxLength, startOfWord + 1, endOfWord-startOfWord-2);
Poincare::Expression expr = Poincare::Expression::Parse(word, nullptr);
if (expr.isUninitialized()) {
expr = Poincare::Undefined::Builder();
if (*startOfWord == '$') { // Look for expression
endOfWord = startOfWord + 1;
while (*endOfWord != '$') {
if (endOfWord > endOfFile) {
break; // If we are here, it's bad...
}
endOfWord ++;
}
layout = Shared::PoincareHelpers::CreateLayout(expr);
endOfWord ++;
TexParser parser = TexParser(startOfWord + 1, endOfWord - 1);
layout = parser.getLayout();
textSize = layout.layoutSize();
toDraw = ToDraw::Expression;
}
else {
if (*startOfWord == '\\' || *(startOfWord + 1) == '$') {
startOfWord ++;
}
textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
stringNCopy(word, wordMaxLength, startOfWord, endOfWord-startOfWord);
toDraw = ToDraw::Text;
@@ -222,7 +245,10 @@ void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
}
textPosition = nextTextPosition;
endOfWord = EndOfPrintableWord(startOfWord+1, endOfFile);
if (*startOfWord != '$') {
endOfWord = EndOfPrintableWord(startOfWord+1, endOfFile);
} // Else we don't need to update endOfWord
}
m_nextPageOffset = startOfWord - text();

View File

@@ -25,8 +25,6 @@ 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)"

View File

@@ -15,17 +15,13 @@ 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)};
constexpr SettingsMessageTree s_contributorsChildren[23] = {SettingsMessageTree(I18n::Message::Developers), SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::SandraSimmons), SettingsMessageTree(I18n::Message::David), SettingsMessageTree(I18n::Message::DamienNicolet), SettingsMessageTree(I18n::Message::EvannDreumont), SettingsMessageTree(I18n::Message::SzaboLevente), SettingsMessageTree(I18n::Message::VenceslasDuet), SettingsMessageTree(I18n::Message::CharlotteThomas), SettingsMessageTree(I18n::Message::AntoninLoubiere), SettingsMessageTree(I18n::Message::CyprienMejat), SettingsMessageTree(I18n::Message::BetaTesters), SettingsMessageTree(I18n::Message::TimeoArnouts), SettingsMessageTree(I18n::Message::JulieC), SettingsMessageTree(I18n::Message::LelahelHideux), SettingsMessageTree(I18n::Message::Madil), SettingsMessageTree(I18n::Message::HilaireLeRoux), SettingsMessageTree(I18n::Message::HectorNussbaumer), SettingsMessageTree(I18n::Message::RaphaelDyda), SettingsMessageTree(I18n::Message::ThibautC)};
// Code Settings
#ifdef HAS_CODE
constexpr SettingsMessageTree s_codeChildren[2] = {SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren), SettingsMessageTree(I18n::Message::Autocomplete)};
#endif
constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)};
@@ -43,8 +39,7 @@ MainController::MainController(Responder * parentResponder, InputEventHandlerDel
m_codeOptionsController(this),
m_examModeController(this),
m_aboutController(this),
m_preferencesController(this),
m_usbInfoController(this)
m_preferencesController(this)
{
for (int i = 0; i < k_numberOfSimpleChevronCells; i++) {
m_cells[i].setMessageFont(KDFont::LargeFont);
@@ -114,8 +109,6 @@ 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 {

View File

@@ -12,7 +12,6 @@
#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 {
@@ -29,8 +28,6 @@ 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 {
@@ -79,7 +76,6 @@ private:
ExamModeController m_examModeController;
AboutController m_aboutController;
PreferencesController m_preferencesController;
UsbInfoController m_usbInfoController;
};
}

View File

@@ -13,12 +13,9 @@ constexpr SettingsMessageTree s_modelMenu[] =
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::Country),
SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
#ifdef HAS_CODE
SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
#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);

View File

@@ -1,30 +1,26 @@
#include <apps/i18n.h>
#include "../exam_mode_configuration.h"
#include "main_controller.h"
#include "../exam_mode_configuration.h"
#include <apps/i18n.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),
#ifdef HAS_CODE
SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
#endif
SettingsMessageTree(I18n::Message::UsbSetting, s_usbSteps),
SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren),
SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)};
{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::CodeApp, s_codeChildren),
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
}

View File

@@ -13,12 +13,9 @@ constexpr SettingsMessageTree s_modelMenu[] =
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::Country),
SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
#ifdef HAS_CODE
SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
#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);

View File

@@ -100,22 +100,6 @@ bool AboutController::handleEvent(Ion::Events::Event event) {
return true;
}
if(childLabel == I18n::Message::Battery){
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
char batteryLevel[15];
if(strchr(myCell->accessoryText(), '%') == NULL){
int batteryLen = Poincare::Integer((int) ((Ion::Battery::voltage() - 3.6) * 166)).serialize(batteryLevel, 15);
batteryLevel[batteryLen] = '%';
batteryLevel[batteryLen+1] = '\0';
}else{
int batteryLen = Poincare::Number::FloatNumber(Ion::Battery::voltage()).serialize(batteryLevel, 15, Poincare::Preferences::PrintFloatMode::Decimal, 3);
batteryLevel[batteryLen] = 'V';
batteryLevel[batteryLen+1] = '\0';
}
myCell->setAccessoryText(batteryLevel);
return true;
}
}
return false;
}

View File

@@ -25,7 +25,7 @@ bool AccessibilityController::handleEvent(Ion::Events::Event event) {
int redGamma, greenGamma, blueGamma;
KDIonContext::sharedContext()->gamma.gamma(redGamma, greenGamma, blueGamma);
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) && (selectedRow() <= 2)) {
if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
if (selectedRow() == 0) {
invertEnabled = !invertEnabled;
}

View File

@@ -10,8 +10,12 @@ CodeOptionsController::CodeOptionsController(Responder * parentResponder) :
GenericSubController(parentResponder),
m_preferencesController(this)
{
m_chevronCell.setMessageFont(KDFont::LargeFont);
m_switchCell.setMessageFont(KDFont::LargeFont);
for (int i = 0; i < k_totalNumberOfCell; i++) {
m_cells[i].setMessageFont(KDFont::LargeFont);
}
for (int i = 0; i < k_totalNumberOfSwitchCells; i++) {
m_switchCells[i].setMessageFont(KDFont::LargeFont);
}
}
bool CodeOptionsController::handleEvent(Ion::Events::Event event) {
@@ -40,10 +44,7 @@ bool CodeOptionsController::handleEvent(Ion::Events::Event event) {
HighlightCell * CodeOptionsController::reusableCell(int index, int type) {
assert(type == 0);
assert(index >= 0 && index < k_totalNumberOfCell);
if (index == 0) {
return &m_chevronCell;
}
return &m_switchCell;
return &m_cells[index];
}
int CodeOptionsController::reusableCellCount(int type) {
@@ -61,14 +62,11 @@ void CodeOptionsController::willDisplayCellForIndex(HighlightCell * cell, int in
GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont
? myTextCell->setSubtitle(I18n::Message::LargeFont)
: myTextCell->setSubtitle(I18n::Message::SmallFont);
}
#ifdef HAS_CODE
else if (thisLabel == I18n::Message::Autocomplete) {
} else if (thisLabel == I18n::Message::Autocomplete) {
MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell;
SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView();
mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->autocomplete());
}
#endif
}
}

View File

@@ -14,10 +14,11 @@ public:
int reusableCellCount(int type) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
private:
constexpr static int k_totalNumberOfCell = 2;
constexpr static int k_totalNumberOfCell = 1;
constexpr static int k_totalNumberOfSwitchCells = 1;
PreferencesController m_preferencesController;
MessageTableCellWithChevronAndMessage m_chevronCell;
MessageTableCellWithSwitch m_switchCell;
MessageTableCellWithChevronAndMessage m_cells[k_totalNumberOfCell];
MessageTableCellWithSwitch m_switchCells[k_totalNumberOfCell];
};
}

View File

@@ -1,134 +0,0 @@
#include "usb_info_controller.h"
#include <apps/i18n.h>
#include <apps/settings/main_controller.h>
#include <assert.h>
#include <ion/storage.h>
#include <poincare/preferences.h>
#include <cmath>
#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());
}
}
}

View File

@@ -1,36 +0,0 @@
#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

View File

@@ -1,77 +0,0 @@
#include "usb_protection_level_controller.h"
#include <apps/i18n.h>
#include <assert.h>
#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

View File

@@ -1,24 +0,0 @@
#ifndef SETTINGS_USB_PROTECTION_LEVEL_CONTROLLER_H
#define SETTINGS_USB_PROTECTION_LEVEL_CONTROLLER_H
#include "generic_sub_controller.h"
#include <escher.h>
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

View File

@@ -99,15 +99,3 @@ 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!"

View File

@@ -99,15 +99,3 @@ 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 !"

View File

@@ -99,15 +99,3 @@ 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!"

View File

@@ -99,15 +99,3 @@ 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 !"

View File

@@ -99,15 +99,3 @@ 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!"

View File

@@ -99,15 +99,3 @@ 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 !"

View File

@@ -99,15 +99,3 @@ 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!"

View File

@@ -99,15 +99,3 @@ 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!"

View File

@@ -458,11 +458,6 @@ 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"

View File

@@ -24,13 +24,13 @@ void AbstractScrollableMultipleExpressionsView::ContentCell::setHighlighted(bool
// Do not call HighlightCell::setHighlighted to avoid marking all cell as dirty
m_highlighted = highlight;
KDColor defaultColor = backgroundColor();
KDColor color = highlight && m_selectedSubviewPosition == SubviewPosition::Center ? Palette::Select : defaultColor;
KDColor color = highlight && m_selectedSubviewPosition == SubviewPosition::Center ? Palette::ExpressionInputBackground : defaultColor;
m_centeredExpressionView.setBackgroundColor(color);
color = highlight && m_selectedSubviewPosition == SubviewPosition::Right ? Palette::Select : defaultColor;
color = highlight && m_selectedSubviewPosition == SubviewPosition::Right ? Palette::ExpressionInputBackground : defaultColor;
m_rightExpressionView.setBackgroundColor(color);
m_approximateSign.setBackgroundColor(defaultColor);
if (leftExpressionView()) {
color = highlight && m_selectedSubviewPosition == SubviewPosition::Left ? Palette::Select : defaultColor;
color = highlight && m_selectedSubviewPosition == SubviewPosition::Left ? Palette::ExpressionInputBackground : defaultColor;
leftExpressionView()->setBackgroundColor(color);
}
}

View File

@@ -1,7 +1,6 @@
app_usb_src = $(addprefix apps/usb/,\
app.cpp \
usb_connected_controller.cpp \
usb_view.cpp \
)
apps_src += $(app_usb_src)

View File

@@ -27,7 +27,6 @@ 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;
}

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -4,10 +4,4 @@ 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."
DfuStatus1 = "Estado de la calculadora:"
DfuStatusProtected = "PROTEGIDO"
DfuStatusUnProtected = "DESABRIGADO"
USBProtectionLevel0 = "Protección predeterminada"
USBProtectionLevel1 = "Protección Omega"
USBProtectionLevel2 = "Protección del sistema"
ConnectedMessage6 = "desconectarla."

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -5,9 +5,3 @@ 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"

View File

@@ -1,140 +1,42 @@
#include "usb_connected_controller.h"
#include <apps/i18n.h>
#include "../global_preferences.h"
namespace USB
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)
{
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;
// }
}
}

View File

@@ -2,7 +2,7 @@
#define USB_USB_CONNECTED_CONTROLLER_H
#include <escher.h>
#include "usb_view.h"
#include "../shared/message_view.h"
namespace USB {
@@ -10,12 +10,9 @@ class USBConnectedController : public ViewController {
public:
USBConnectedController();
View * view() override { return &m_messageView; }
USBView * getMessageView() {return &m_messageView; }
bool handleEvent(Ion::Events::Event event) override { return false; };
bool handleEvent(Ion::Events::Event event) override { return false; }
private:
int step;
bool already_init;
USBView m_messageView;
MessageView m_messageView;
};
}

View File

@@ -1,56 +0,0 @@
#include "usb_view.h"
#include <assert.h>
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);
}
}
}

View File

@@ -1,30 +0,0 @@
#ifndef USB_VIEW_H
#define USB_VIEW_H
#include <escher.h>
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

View File

@@ -14,6 +14,6 @@ EPSILON_I18N ?= en fr nl pt it de es hu
EPSILON_COUNTRIES ?= WW CA DE ES FR GB IT NL PT US
EPSILON_GETOPT ?= 0
ESCHER_LOG_EVENTS_BINARY ?= 0
THEME_NAME ?= upsilon_light
THEME_NAME ?= omega_light
THEME_REPO ?= local
INCLUDE_ULAB ?= 1

View File

@@ -1,29 +0,0 @@
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!")

View File

@@ -27,11 +27,11 @@ $(BUILD_DIR)/%.map: $(BUILD_DIR)/%.elf
@echo "LDMAP $@"
$(Q) $(LD) $^ $(LDFLAGS) -Wl,-M -Wl,-Map=$@ -o /dev/null
.PHONY: mapfile
mapfile:
$(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: openocd
openocd:
@@ -45,6 +45,7 @@ $(BUILD_DIR)/flasher.verbose.$(EXE): $(call flavored_object_for,$(flasher_src),u
$(BUILD_DIR)/flasher.verbose.flash.$(EXE): $(call flavored_object_for,$(flasher_src))
$(BUILD_DIR)/flasher.%.$(EXE): LDFLAGS += -Lion/src/$(PLATFORM)/flasher
$(BUILD_DIR)/flasher.%.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/shared/ram.ld
$(BUILD_DIR)/flasher.%.$(EXE): RASTERIZER_CFLAGS += -DISBUILDINGFLASHER
$(BUILD_DIR)/flasher.%.flash.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/$(MODEL)/internal_flash.ld
#TODO Do not build all apps... Put elsewhere?
@@ -72,4 +73,3 @@ 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

View File

@@ -30,7 +30,7 @@ void ModalViewEmptyController::ModalViewEmptyView::setMessages(I18n::Message * m
void ModalViewEmptyController::ModalViewEmptyView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(bounds(), k_backgroundColor);
drawBorderOfRect(ctx, bounds(), Palette::ListCellBorder);
drawBorderOfRect(ctx, bounds(), Palette::GrayBright);
}
int ModalViewEmptyController::ModalViewEmptyView::numberOfSubviews() const {

View File

@@ -8,7 +8,7 @@ bool isPlugged();
bool isEnumerated(); // Speed-enumerated, to be accurate
void clearEnumerationInterrupt();
void DFU(bool exitWithKeyboard = true, bool unlocked = false, int level = 0);
void DFU(bool exitWithKeyboard = true);
void enable();
void disable();

View File

@@ -11,6 +11,6 @@ void ion_main(int argc, const char * const argv[]) {
Ion::USB::enable();
while (!Ion::USB::isEnumerated()) {
}
Ion::USB::DFU(false, false, 0);
Ion::USB::DFU(false);
}
}

View File

@@ -30,9 +30,7 @@ void initMPU() {
Cache::dmb();
// 1.2 Disable fault exceptions
CORTEX.SHCRS()->setMEMFAULTENA(true);
CORTEX.SHCRS()->setBUSFAULTENA(true);
CORTEX.SHCRS()->setUSGFAULTENA(true);
CORTEX.SHCRS()->setMEMFAULTENA(false);
// 1.3 Disable the MPU and clear the control register
MPU.CTRL()->setENABLE(false);
@@ -123,7 +121,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);

View File

@@ -63,14 +63,6 @@ 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)
@@ -97,123 +89,6 @@ 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)
@@ -238,49 +113,7 @@ 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) : {

View File

@@ -18,11 +18,11 @@ ISR InitialisationVector[INITIALISATION_VECTOR_SIZE]
= {
(ISR)&_stack_start, // Stack start
start, // Reset service routine,
nmi_abort, // NMI service routine,
0, // NMI service routine,
abort, // HardFault service routine,
0, // MemManage service routine,
bf_abort, // BusFault service routine,
uf_abort, // UsageFault service routine,
0, // BusFault service routine,
0, // UsageFault service routine,
0, 0, 0, 0, // Reserved
0, // SVCall service routine,
0, // DebugMonitor service routine,

View File

@@ -5,14 +5,6 @@
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();

View File

@@ -1,52 +1,45 @@
#include <drivers/battery.h>
#include <drivers/cache.h>
#include <drivers/external_flash.h>
#include <drivers/led.h>
#include <drivers/power.h>
#include <drivers/reset.h>
#include <drivers/usb.h>
#include <drivers/wakeup.h>
#include <ion.h>
#include <ion/battery.h>
#include <ion/led.h>
#include <ion/rtc.h>
#include <ion/usb.h>
#include <kandinsky.h>
#include <regs/config/pwr.h>
#include <regs/config/rcc.h>
#include <regs/regs.h>
#include "isr.h"
#include <stdint.h>
#include <string.h>
#include <ion.h>
#include "../drivers/board.h"
#include "../drivers/reset.h"
#include "../drivers/rtc.h"
#include "../drivers/reset.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;
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
}
/* 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:
@@ -68,155 +61,7 @@ static void __attribute__((noinline)) external_flash_start() {
* internal flash to the external flash. */
static void __attribute__((noinline)) jump_to_external_flash() {
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");
external_flash_start();
}
/* When 'start' is executed, the external flash is supposed to be shutdown. We
@@ -224,27 +69,27 @@ void __attribute__((noinline)) uf_abort() {
* (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++
@@ -252,30 +97,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;
}

View File

@@ -7,11 +7,10 @@ namespace Ion {
namespace Device {
namespace USB {
void Calculator::PollAndReset(bool exitWithKeyboard, bool unlock, int level) {
void Calculator::PollAndReset(bool exitWithKeyboard) {
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. */
@@ -20,10 +19,6 @@ void Calculator::PollAndReset(bool exitWithKeyboard, bool unlock, int level) {
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() &&

View File

@@ -25,7 +25,7 @@ namespace USB {
class Calculator : public Device {
public:
static void PollAndReset(bool exitWithKeyboard, bool unlocked, int level)
static void PollAndReset(bool exitWithKeyboard)
__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

View File

@@ -1,518 +1,286 @@
#include "dfu_interface.h"
#include <drivers/config/external_flash.h>
#include <drivers/config/internal_flash.h>
#include <drivers/external_flash.h>
#include <drivers/flash.h>
#include <drivers/internal_flash.h>
#include <ion/led.h>
#include <ion/storage.h>
#include <ion/timing.h>
#include <string.h>
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<uint8_t *>(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
#include "dfu_interface.h"
#include <string.h>
#include <drivers/flash.h>
#include <ion/timing.h>
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<uint8_t *>(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();
}
}
}
}

View File

@@ -8,217 +8,173 @@
#include "stack/endpoint0.h"
#include "stack/setup_packet.h"
#include "stack/streamable.h"
#include <drivers/config/internal_flash.h>
#include <drivers/config/external_flash.h>
namespace Ion
{
namespace Device
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 USB
{
}
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; }
class DFUInterface : public Interface
{
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;
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; }
private:
// DFU Request Codes
enum class DFURequest {
Detach = 0,
Download = 1,
Upload = 2,
GetStatus = 3,
ClearStatus = 4,
GetState = 5,
Abort = 6
};
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;
// DFU Download Commmand Codes
enum class DFUDownloadCommand {
GetCommand = 0x00,
SetAddressPointer = 0x21,
Erase = 0x41,
ReadUnprotect = 0x92
};
private:
// DFU Request Codes
enum class DFURequest
{
Detach = 0,
Download = 1,
Upload = 2,
GetStatus = 3,
ClearStatus = 4,
GetState = 5,
Abort = 6
};
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
};
// DFU Download Commmand Codes
enum class DFUDownloadCommand
{
GetCommand = 0x00,
SetAddressPointer = 0x21,
Erase = 0x41,
ReadUnprotect = 0x92
};
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
};
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
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)
{
}
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;
};
protected:
void push(Channel *c) const override;
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
};
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
/* 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_ExternalBorderAddress = 0x90200000;
constexpr static uint32_t k_sramStartAddress = 0x20000000;
constexpr static uint32_t k_sramEndAddress = 0x20040000;
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
// 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
* 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 reset_custom_vars() {m_temp_is_valid = true; m_last_memoryFlashed = -1; m_lastPageErased = -1;}
void willErase() { m_isErasingAndWriting = true; }
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;
};
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;
};
}
}
}
}
}
#endif

View File

@@ -11,9 +11,9 @@ extern char _dfu_bootloader_flash_end;
namespace Ion {
namespace USB {
typedef void (*PollFunctionPointer)(bool exitWithKeyboard, bool unlocked, int level);
typedef void (*PollFunctionPointer)(bool exitWithKeyboard);
void DFU(bool exitWithKeyboard, bool unlocked, int level) {
void DFU(bool exitWithKeyboard) {
/* 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, bool unlocked, int level) {
* add-symbol-file ion/src/device/usb/dfu.elf 0x20038000
*/
dfu_bootloader_entry(exitWithKeyboard, unlocked, level);
dfu_bootloader_entry(exitWithKeyboard);
/* 5- Restore interrupts */
Device::Timing::init();

View File

@@ -3,8 +3,8 @@
namespace Ion {
namespace USB {
void DFU(bool exitWithKeyboard, bool unlocked, int level) {
Ion::Device::USB::Calculator::PollAndReset(exitWithKeyboard, unlocked, level);
void DFU(bool exitWithKeyboard) {
Ion::Device::USB::Calculator::PollAndReset(exitWithKeyboard);
}
}

View File

@@ -14,7 +14,7 @@ bool isEnumerated() {
void clearEnumerationInterrupt() {
}
void DFU(bool, bool, int) {
void DFU(bool) {
}
void enable() {

View File

@@ -1,7 +1,7 @@
BasicInfo:
Title : Upsilon
Title : Omega
CompanyCode : "00"
ProductCode : CTR-E-Upsilon
ProductCode : CTR-E-OMEGA
Logo : Homebrew # Nintendo / Licensed / Distributed / iQue / iQueForSystem
RomFs:

Some files were not shown because too many files have changed in this diff Show More