From f763563834be83ffae397e047191a86fc59703b3 Mon Sep 17 00:00:00 2001 From: Damien Nicolet Date: Fri, 13 Dec 2019 01:02:14 +0100 Subject: [PATCH 1/3] Memory optimisation --- apps/code/editor_controller.cpp | 18 +++++++++++++++++- apps/code/editor_controller.h | 4 +++- ion/include/ion/storage.h | 2 +- poincare/include/poincare/tree_pool.h | 2 +- poincare/src/trigonometry_cheat_table.cpp | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index aba355959..c799d8ff8 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -18,6 +18,22 @@ EditorController::EditorController(MenuController * menuController, App * python m_editorView.setTextAreaDelegates(this, this); } +#ifdef MAX_SCRIPTSIZE +void EditorController::setScript(Script script) { + m_script = script; + Script::Data scriptData = m_script.value(); + size_t s=scriptData.size,ms=sizeof(m_areaBuffer); + if (s>ms) + s=ms; + size_t availableScriptSize = s + Ion::Storage::sharedStorage()->availableSize(); + if (availableScriptSize>ms) + availableScriptSize=ms; + // assert(sizeof(m_areaBuffer) >= availableScriptSize); + // We cannot use strlcpy as the first char reprensenting the importation status can be 0. + memcpy(m_areaBuffer, (const char *)scriptData.buffer, s); + m_editorView.setText(m_areaBuffer+1, availableScriptSize-1); // 1 char is taken by the importation status flag +} +#else void EditorController::setScript(Script script) { m_script = script; Script::Data scriptData = m_script.value(); @@ -27,7 +43,7 @@ void EditorController::setScript(Script script) { memcpy(m_areaBuffer, (const char *)scriptData.buffer, scriptData.size); m_editorView.setText(m_areaBuffer+1, availableScriptSize-1); // 1 char is taken by the importation status flag } - +#endif // TODO: this should be done in textAreaDidFinishEditing maybe?? bool EditorController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home) { diff --git a/apps/code/editor_controller.h b/apps/code/editor_controller.h index 284bf1af3..d5b948d4e 100644 --- a/apps/code/editor_controller.h +++ b/apps/code/editor_controller.h @@ -1,6 +1,8 @@ #ifndef CODE_EDITOR_CONTROLLER_H #define CODE_EDITOR_CONTROLLER_H +#define MAX_SCRIPTSIZE 12288 + #include #include "script.h" #include "editor_view.h" @@ -39,7 +41,7 @@ private: /* m_areaBuffer first character is dedicated to the importation status. * Thereby, we avoid wasteful copy while adding the Script to the storage * (in order to add the importation status char before the areaBuffer). */ - char m_areaBuffer[Ion::Storage::k_storageSize]; // this could be slightly optimize + char m_areaBuffer[Ion::Storage::k_storageSize>MAX_SCRIPTSIZE?MAX_SCRIPTSIZE:Ion::Storage::k_storageSize]; // this could be slightly optimize Script m_script; MenuController * m_menuController; }; diff --git a/ion/include/ion/storage.h b/ion/include/ion/storage.h index 41c7001de..5138c1b76 100644 --- a/ion/include/ion/storage.h +++ b/ion/include/ion/storage.h @@ -16,7 +16,7 @@ class StorageDelegate; class Storage { public: typedef uint16_t record_size_t; - constexpr static size_t k_storageSize = 16384; + constexpr static size_t k_storageSize = 20480; static Storage * sharedStorage(); constexpr static char k_dotChar = '.'; diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index a124964e3..8e6a3d6f4 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -49,7 +49,7 @@ public: int numberOfNodes() const; private: - constexpr static int BufferSize = 32768; + constexpr static int BufferSize = 16384; constexpr static int MaxNumberOfNodes = BufferSize/sizeof(TreeNode); static TreePool * SharedStaticPool; diff --git a/poincare/src/trigonometry_cheat_table.cpp b/poincare/src/trigonometry_cheat_table.cpp index eac4f3a4b..9eae9bc33 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -82,7 +82,7 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: * For instance, when simplfy a Cosine, we always compute the value for an angle * in the top right trigonometric quadrant. */ const TrigonometryCheatTable * TrigonometryCheatTable::Table() { - static Row sTableRows[] = { + const Row sTableRows[] = { Row(Row::Pair("-90", -90.0f), Row::Pair("π*(-2)^(-1)", -1.5707963267948966f), Row::Pair("-100", -100.0f), From 2700098c0864dd25ae00e4cb554fa7af21d817e4 Mon Sep 17 00:00:00 2001 From: Damien Nicolet Date: Fri, 13 Dec 2019 01:02:14 +0100 Subject: [PATCH 2/3] External application launcher app --- apps/external/Makefile | 30 +++++ apps/external/app.cpp | 44 +++++++ apps/external/app.h | 37 ++++++ apps/external/app/sample.c | 6 + apps/external/app/sources.mak | 3 + apps/external/archive.cpp | 141 ++++++++++++++++++++++ apps/external/archive.h | 27 +++++ apps/external/base.de.i18n | 4 + apps/external/base.en.i18n | 4 + apps/external/base.es.i18n | 4 + apps/external/base.fr.i18n | 4 + apps/external/base.pt.i18n | 4 + apps/external/extapp_api.cpp | 85 +++++++++++++ apps/external/extapp_api.h | 76 ++++++++++++ apps/external/external_icon.png | Bin 0 -> 10728 bytes apps/external/main_controller.cpp | 98 +++++++++++++++ apps/external/main_controller.h | 34 ++++++ apps/external/pointer_text_table_cell.cpp | 38 ++++++ apps/external/pointer_text_table_cell.h | 20 +++ build/config.mak | 2 +- 20 files changed, 660 insertions(+), 1 deletion(-) create mode 100644 apps/external/Makefile create mode 100644 apps/external/app.cpp create mode 100644 apps/external/app.h create mode 100644 apps/external/app/sample.c create mode 100644 apps/external/app/sources.mak create mode 100644 apps/external/archive.cpp create mode 100644 apps/external/archive.h create mode 100644 apps/external/base.de.i18n create mode 100644 apps/external/base.en.i18n create mode 100644 apps/external/base.es.i18n create mode 100644 apps/external/base.fr.i18n create mode 100644 apps/external/base.pt.i18n create mode 100644 apps/external/extapp_api.cpp create mode 100644 apps/external/extapp_api.h create mode 100644 apps/external/external_icon.png create mode 100644 apps/external/main_controller.cpp create mode 100644 apps/external/main_controller.h create mode 100644 apps/external/pointer_text_table_cell.cpp create mode 100644 apps/external/pointer_text_table_cell.h diff --git a/apps/external/Makefile b/apps/external/Makefile new file mode 100644 index 000000000..b767dad8d --- /dev/null +++ b/apps/external/Makefile @@ -0,0 +1,30 @@ +apps += External::App +app_headers += apps/external/app.h + +app_external_src = $(addprefix apps/external/,\ + app.cpp \ + extapp_api.cpp \ + archive.cpp \ + main_controller.cpp \ + pointer_text_table_cell.cpp \ +) + +SFLAGS += -Iapps/external/ + +ifeq ($(PLATFORM),device) + SFLAGS += -DDEVICE +else + include apps/external/app/sources.mak +endif + +app_src += $(app_external_src) + +i18n_files += $(addprefix apps/external/,\ + base.de.i18n\ + base.en.i18n\ + base.es.i18n\ + base.fr.i18n\ + base.pt.i18n\ +) + +$(eval $(call depends_on_image,apps/external/app.cpp,apps/external/external_icon.png)) diff --git a/apps/external/app.cpp b/apps/external/app.cpp new file mode 100644 index 000000000..ac0f6141c --- /dev/null +++ b/apps/external/app.cpp @@ -0,0 +1,44 @@ +#include "app.h" +#include "external_icon.h" +#include + +namespace External { + +I18n::Message App::Descriptor::name() { + return I18n::Message::ExternalApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::ExternalAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::ExternalIcon; +} + +App * App::Snapshot::unpack(Container * container) { + return new (container->currentAppBuffer()) App(this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +void App::didBecomeActive(Window * window) { + ::App::didBecomeActive(window); + m_window = window; +} + +void App::redraw() { + m_window->redraw(true); +} + +App::App(Snapshot * snapshot) : + ::App(snapshot, &m_stackViewController), + m_mainController(&m_stackViewController, this), + m_stackViewController(&m_modalViewController, &m_mainController) +{ +} + +} diff --git a/apps/external/app.h b/apps/external/app.h new file mode 100644 index 000000000..e1dd47043 --- /dev/null +++ b/apps/external/app.h @@ -0,0 +1,37 @@ +#ifndef EXTERNAL_APP_H +#define EXTERNAL_APP_H + +#include +#include "main_controller.h" + +namespace External { + +class App : public ::App { +public: + class Descriptor : public ::App::Descriptor { + public: + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + }; + void redraw(); + virtual void didBecomeActive(Window * window); + int heapSize() { return k_externalHeapSize; } + char * heap() { return m_externalHeap; } +private: + App(Snapshot * snapshot); + MainController m_mainController; + StackViewController m_stackViewController; + Window * m_window; + static constexpr int k_externalHeapSize = 131072; + char m_externalHeap[k_externalHeapSize]; +}; + +} + +#endif diff --git a/apps/external/app/sample.c b/apps/external/app/sample.c new file mode 100644 index 000000000..dbc13fd95 --- /dev/null +++ b/apps/external/app/sample.c @@ -0,0 +1,6 @@ +#include + +void extapp_main() { + extapp_pushRectUniform(10, 10, LCD_WIDTH-20, LCD_HEIGHT-20, 0); + extapp_msleep(1000); +} diff --git a/apps/external/app/sources.mak b/apps/external/app/sources.mak new file mode 100644 index 000000000..3f285e23a --- /dev/null +++ b/apps/external/app/sources.mak @@ -0,0 +1,3 @@ +app_external_src += $(addprefix apps/external/app/,\ + sample.c \ +) \ No newline at end of file diff --git a/apps/external/archive.cpp b/apps/external/archive.cpp new file mode 100644 index 000000000..aaa89373a --- /dev/null +++ b/apps/external/archive.cpp @@ -0,0 +1,141 @@ +#include "archive.h" +#include "extapp_api.h" + +#include +#include + +namespace External { +namespace Archive { + +#ifdef DEVICE + +struct TarHeader +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[8]; /* 257 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char padding[167]; /* 345 */ +} __attribute__((packed)); + +static_assert(sizeof(TarHeader) == 512); + +bool isSane(const TarHeader* tar) { + return !memcmp(tar->magic, "ustar ", 8) && tar->name[0] != '\x00' && tar->name[0] != '\xFF'; +} + +bool fileAtIndex(size_t index, File &entry) { + const TarHeader* tar = reinterpret_cast(0x90200000); + unsigned size = 0; + + // Sanity check. + if (!isSane(tar)) { + return false; + } + + /** + * TAR files are comprised of a set of records aligned to 512 bytes boundary + * followed by data. + */ + while (index-- > 0) { + size = 0; + for (int i = 0; i < 11; i++) + size = size * 8 + (tar->size[i] - '0'); + + // Move to the next TAR header. + unsigned stride = (sizeof(TarHeader) + size + 511); + stride = (stride >> 9) << 9; + tar = reinterpret_cast(reinterpret_cast(tar) + stride); + + // Sanity check. + if (!isSane(tar)) { + return false; + } + } + + // File entry found, copy data out. + entry.name = tar->name; + entry.data = reinterpret_cast(tar) + sizeof(TarHeader); + entry.dataLength = size; + entry.isExecutable = (tar->mode[4] & 0x01) == 1; + + return true; +} + +extern "C" void (* const apiPointers[])(void); +typedef uint32_t (*entrypoint)(const uint32_t, const void *, void *, const uint32_t); + +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) { + File entry; + if(fileAtIndex(indexFromName(name), entry)) { + if(!entry.isExecutable) { + return 0; + } + uint32_t ep = *reinterpret_cast(entry.data); + if(ep >= 0x90200000 && ep < 0x90800000) { + return ((entrypoint)ep)(API_VERSION, apiPointers, heap, heapSize); + } + } + return -1; +} + +int indexFromName(const char *name) { + File entry; + + for (int i = 0; fileAtIndex(i, entry); i++) { + if (strcmp(name, entry.name) == 0) { + return i; + } + } + + return -1; +} + +size_t numberOfFiles() { + File dummy; + size_t count; + + for (count = 0; fileAtIndex(count, dummy); count++); + + return count; +} + +#else + +bool fileAtIndex(size_t index, File &entry) { + entry.name = "App"; + entry.data = NULL; + entry.dataLength = 0; + entry.isExecutable = true; + return true; +} + +extern "C" void extapp_main(void); + +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) { + extapp_main(); + return 0; +} + +int indexFromName(const char *name) { + return 0; +} + +size_t numberOfFiles() { + return 1; +} + +#endif + +} +} diff --git a/apps/external/archive.h b/apps/external/archive.h new file mode 100644 index 000000000..80b71d0e1 --- /dev/null +++ b/apps/external/archive.h @@ -0,0 +1,27 @@ +#ifndef EXTERNAL_ARCHIVE_H +#define EXTERNAL_ARCHIVE_H + +#include +#include + +namespace External { +namespace Archive { + +constexpr int MaxNameLength = 40; + +struct File { + const char *name; + const uint8_t *data; + size_t dataLength; + bool isExecutable; +}; + +bool fileAtIndex(size_t index, File &entry); +int indexFromName(const char *name); +size_t numberOfFiles(); +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize); + +} +} + +#endif diff --git a/apps/external/base.de.i18n b/apps/external/base.de.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.de.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.en.i18n b/apps/external/base.en.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.en.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.es.i18n b/apps/external/base.es.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.es.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.fr.i18n b/apps/external/base.fr.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.fr.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.pt.i18n b/apps/external/base.pt.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.pt.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/extapp_api.cpp b/apps/external/extapp_api.cpp new file mode 100644 index 000000000..1e7fd7aeb --- /dev/null +++ b/apps/external/extapp_api.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include "extapp_api.h" + +#include + +extern "C" { + #include +} + +uint64_t extapp_millis() { + return Ion::Timing::millis(); +} + +void extapp_msleep(uint32_t ms) { + Ion::Timing::msleep(ms); +} + +uint64_t extapp_scanKeyboard() { + return Ion::Keyboard::scan(); +} + +void extapp_pushRect(int16_t x, int16_t y, uint16_t w, uint16_t h, const uint16_t * pixels) { + KDRect rect(x, y, w, h); + + Ion::Display::pushRect(rect, reinterpret_cast(pixels)); +} + +void extapp_pushRectUniform(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t color) { + KDRect rect(x, y, w, h); + + Ion::Display::pushRectUniform(rect, KDColor::RGB16(color)); +} + +int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg) { + KDPoint point(x, y); + + auto ctx = KDIonContext::sharedContext(); + ctx->setClippingRect(KDRect(0,0,320,240)); + ctx->setOrigin(KDPoint(0,0)); + ctx->drawString(text, point, KDFont::LargeFont, KDColor::RGB16(fg), KDColor::RGB16(bg)); + + return point.x(); +} + +int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg) { + KDPoint point(x, y); + + auto ctx = KDIonContext::sharedContext(); + ctx->setClippingRect(KDRect(0,0,320,240)); + ctx->setOrigin(KDPoint(0,0)); + ctx->drawString(text, point, KDFont::SmallFont, KDColor::RGB16(fg), KDColor::RGB16(bg)); + + return point.x(); +} + +void extapp_waitForVBlank() { + Ion::Display::waitForVBlank(); +} + +void extapp_clipboardStore(const char *text) { + Clipboard::sharedClipboard()->store(text); +} + +const char * extapp_clipboardText() { + return Clipboard::sharedClipboard()->storedText(); +} + +extern "C" void (* const apiPointers[])(void) = { + (void (*)(void)) extapp_millis, + (void (*)(void)) extapp_msleep, + (void (*)(void)) extapp_scanKeyboard, + (void (*)(void)) extapp_pushRect, + (void (*)(void)) extapp_pushRectUniform, + (void (*)(void)) extapp_drawTextLarge, + (void (*)(void)) extapp_drawTextSmall, + (void (*)(void)) extapp_waitForVBlank, + (void (*)(void)) extapp_clipboardStore, + (void (*)(void)) extapp_clipboardText, + (void (*)(void)) nullptr +}; diff --git a/apps/external/extapp_api.h b/apps/external/extapp_api.h new file mode 100644 index 000000000..12ae53ba6 --- /dev/null +++ b/apps/external/extapp_api.h @@ -0,0 +1,76 @@ +#ifndef EXTERNAL_API_H +#define EXTERNAL_API_H + +#include + +#define API_VERSION 1 + +#ifdef __cplusplus +#define EXTERNC extern "C" +#else +#define EXTERNC +#endif + +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 + +#define KEY_Left ((uint64_t)1 << 0) +#define KEY_Up ((uint64_t)1 << 1) +#define KEY_Down ((uint64_t)1 << 2) +#define KEY_Right ((uint64_t)1 << 3) +#define KEY_OK ((uint64_t)1 << 4) +#define KEY_Back ((uint64_t)1 << 5) +#define KEY_Home ((uint64_t)1 << 6) +#define KEY_OnOff (((uint64_t)1 << 7) || ((uint64_t)1 << 8)) +#define KEY_Shift ((uint64_t)1 << 12) +#define KEY_Alpha ((uint64_t)1 << 13) +#define KEY_XNT ((uint64_t)1 << 14) +#define KEY_Var ((uint64_t)1 << 15) +#define KEY_Toolbox ((uint64_t)1 << 16) +#define KEY_Backspace ((uint64_t)1 << 17) +#define KEY_Exp ((uint64_t)1 << 18) +#define KEY_Ln ((uint64_t)1 << 19) +#define KEY_Log ((uint64_t)1 << 20) +#define KEY_Imaginary ((uint64_t)1 << 21) +#define KEY_Comma ((uint64_t)1 << 22) +#define KEY_Power ((uint64_t)1 << 23) +#define KEY_Sine ((uint64_t)1 << 24) +#define KEY_Cosine ((uint64_t)1 << 25) +#define KEY_Tangent ((uint64_t)1 << 26) +#define KEY_Pi ((uint64_t)1 << 27) +#define KEY_Sqrt ((uint64_t)1 << 28) +#define KEY_Square ((uint64_t)1 << 29) +#define KEY_Seven ((uint64_t)1 << 30) +#define KEY_Eight ((uint64_t)1 << 31) +#define KEY_Nine ((uint64_t)1 << 32) +#define KEY_LeftParenthesis ((uint64_t)1 << 33) +#define KEY_RightParenthesis ((uint64_t)1 << 34) +#define KEY_Four ((uint64_t)1 << 36) +#define KEY_Five ((uint64_t)1 << 37) +#define KEY_Six ((uint64_t)1 << 38) +#define KEY_Multiplication ((uint64_t)1 << 39) +#define KEY_Division ((uint64_t)1 << 40) +#define KEY_One ((uint64_t)1 << 42) +#define KEY_Two ((uint64_t)1 << 43) +#define KEY_Three ((uint64_t)1 << 44) +#define KEY_Plus ((uint64_t)1 << 45) +#define KEY_Minus ((uint64_t)1 << 46) +#define KEY_Zero ((uint64_t)1 << 48) +#define KEY_Dot ((uint64_t)1 << 49) +#define KEY_EE ((uint64_t)1 << 50) +#define KEY_Ans ((uint64_t)1 << 51) +#define KEY_EXE ((uint64_t)1 << 52) +#define KEY_None ((uint64_t)1 << 54) + +EXTERNC uint64_t extapp_millis(); +EXTERNC void extapp_msleep(uint32_t ms); +EXTERNC uint64_t extapp_scanKeyboard(); +EXTERNC void extapp_pushRect(int16_t x, int16_t y, uint16_t w, uint16_t h, const uint16_t * pixels); +EXTERNC void extapp_pushRectUniform(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t color); +EXTERNC int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg); +EXTERNC int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg); +EXTERNC void extapp_waitForVBlank(); +EXTERNC void extapp_clipboardStore(const char *text); +EXTERNC const char * extapp_clipboardText(); + +#endif diff --git a/apps/external/external_icon.png b/apps/external/external_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..297dc31c6cc743585cee6e411c74e158a91a2949 GIT binary patch literal 10728 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 a@&6BvAL9gKturJ50000 +#include +#include +#include "archive.h" +#include "app.h" + +using namespace Poincare; + +namespace External { + +using namespace Archive; + +MainController::MainController(Responder * parentResponder, ::App * app) : + ViewController(parentResponder), + m_selectableTableView(this) +{ + m_app = app; +} + +View * MainController::view() { + return &m_selectableTableView; +} + +void MainController::didBecomeFirstResponder() { + if (selectedRow() < 0) { + selectCellAtLocation(0, 0); + } + Container::activeApp()->setFirstResponder(&m_selectableTableView); +} + +bool MainController::handleEvent(Ion::Events::Event event) { + if (numberOfRows() > 0 && (event == Ion::Events::OK || event == Ion::Events::EXE)) { + uint32_t res = executeFile(m_cells[selectedRow()].text(), ((App *)m_app)->heap(), ((App *)m_app)->heapSize()); + ((App*)m_app)->redraw(); + switch(res) { + case 0: + break; + case 1: + Container::activeApp()->displayWarning(I18n::Message::ExternalAppApiMismatch); + break; + case 2: + Container::activeApp()->displayWarning(I18n::Message::StorageMemoryFull1); + break; + default: + Container::activeApp()->displayWarning(I18n::Message::ExternalAppExecError); + break; + } + return true; + } + return false; +} + +int MainController::numberOfRows() const { + return k_numberOfCells; +}; + +KDCoordinate MainController::rowHeight(int j) { + return Metric::ParameterCellHeight; +} + +KDCoordinate MainController::cumulatedHeightFromIndex(int j) { + return j*rowHeight(0); +} + +int MainController::indexFromCumulatedHeight(KDCoordinate offsetY) { + return offsetY/rowHeight(0); +} + +HighlightCell * MainController::reusableCell(int index, int type) { + assert(index < k_numberOfCells); + return &m_cells[index]; +} + +int MainController::reusableCellCount(int type) { + return k_numberOfCells; +} + +int MainController::typeAtLocation(int i, int j) { + return 0; +} + +void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { + PointerTextTableCell * myTextCell = (PointerTextTableCell *)cell; + struct File f; + if(fileAtIndex(index, f)) { + myTextCell->setText(f.name); + myTextCell->setTextColor(f.isExecutable ? KDColorBlack : Palette::GreyDark); + } +} + +void MainController::viewWillAppear() { + int count = numberOfFiles(); + k_numberOfCells = count <= k_maxNumberOfCells ? count : k_maxNumberOfCells; + m_selectableTableView.reloadData(); +} + +} diff --git a/apps/external/main_controller.h b/apps/external/main_controller.h new file mode 100644 index 000000000..bdb6d275b --- /dev/null +++ b/apps/external/main_controller.h @@ -0,0 +1,34 @@ +#ifndef EXTERNAL_MAIN_CONTROLLER_H +#define EXTERNAL_MAIN_CONTROLLER_H + +#include +#include "pointer_text_table_cell.h" + +namespace External { + +class MainController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource { +public: + MainController(Responder * parentResponder, App * app); + View * view() override; + bool handleEvent(Ion::Events::Event event) override; + void didBecomeFirstResponder() override; + int numberOfRows() const override; + KDCoordinate rowHeight(int j) override; + KDCoordinate cumulatedHeightFromIndex(int j) override; + int indexFromCumulatedHeight(KDCoordinate offsetY) override; + HighlightCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + int typeAtLocation(int i, int j) override; + void willDisplayCellForIndex(HighlightCell * cell, int index) override; + void viewWillAppear() override; +private: + App * m_app; + SelectableTableView m_selectableTableView; + int k_numberOfCells = 1; + constexpr static int k_maxNumberOfCells = 16; + PointerTextTableCell m_cells[k_maxNumberOfCells]; +}; + +} + +#endif diff --git a/apps/external/pointer_text_table_cell.cpp b/apps/external/pointer_text_table_cell.cpp new file mode 100644 index 000000000..00967fafb --- /dev/null +++ b/apps/external/pointer_text_table_cell.cpp @@ -0,0 +1,38 @@ +#include "pointer_text_table_cell.h" +#include +#include +#include + +PointerTextTableCell::PointerTextTableCell(const char * text, const KDFont * font, Layout layout) : + TableCell(layout), + m_pointerTextView(font, text, 0, 0.5, KDColorBlack, KDColorWhite) +{ +} + +View * PointerTextTableCell::labelView() const { + return (View *)&m_pointerTextView; +} + +const char * PointerTextTableCell::text() const { + return m_pointerTextView.text(); +} + +void PointerTextTableCell::setHighlighted(bool highlight) { + HighlightCell::setHighlighted(highlight); + KDColor backgroundColor = highlight? Palette::ListCellBackgroundSelected : Palette::ListCellBackground; + m_pointerTextView.setBackgroundColor(backgroundColor); +} + +void PointerTextTableCell::setText(const char * text) { + m_pointerTextView.setText(text); + layoutSubviews(); +} + +void PointerTextTableCell::setTextColor(KDColor color) { + m_pointerTextView.setTextColor(color); +} + +void PointerTextTableCell::setTextFont(const KDFont * font) { + m_pointerTextView.setFont(font); + layoutSubviews(); +} diff --git a/apps/external/pointer_text_table_cell.h b/apps/external/pointer_text_table_cell.h new file mode 100644 index 000000000..be011b76e --- /dev/null +++ b/apps/external/pointer_text_table_cell.h @@ -0,0 +1,20 @@ +#ifndef ESCHER_POINTER_TEXT_TABLE_CELL_H +#define ESCHER_POINTER_TEXT_TABLE_CELL_H + +#include +#include + +class PointerTextTableCell : public TableCell { +public: + PointerTextTableCell(const char * text = "", const KDFont * font = KDFont::SmallFont, Layout layout = Layout::Horizontal); + View * labelView() const override; + const char * text() const override; + virtual void setHighlighted(bool highlight) override; + void setText(const char * text); + virtual void setTextColor(KDColor color); + void setTextFont(const KDFont * font); +private: + PointerTextView m_pointerTextView; +}; + +#endif diff --git a/build/config.mak b/build/config.mak index 8de2af89d..a59637cc0 100644 --- a/build/config.mak +++ b/build/config.mak @@ -7,7 +7,7 @@ EPSILON_VERSION ?= 12.0.0 EPSILON_CUSTOM_VERSION ?= 1.18.0-0 # USERNAME ?= N/A # Valid values are "none", "update", "beta" -EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings +EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings external EPSILON_I18N ?= en fr es de pt EPSILON_GETOPT ?= 0 ESCHER_LOG_EVENTS_BINARY ?= 0 From 472929c0284a2ac6a7e1d8881a91cec4510fa0fe Mon Sep 17 00:00:00 2001 From: Damien Nicolet Date: Fri, 13 Dec 2019 01:02:14 +0100 Subject: [PATCH 3/3] External API for KhiCAS --- apps/external/extapp_api.cpp | 82 +++ ion/include/ion/events.h | 24 +- .../ion/keyboard/layout_B2/layout_events.h | 16 +- .../ion/keyboard/layout_B3/layout_events.h | 12 +- ion/include/ion/storage.h | 1 - kandinsky/include/kandinsky/color.h | 2 +- kandinsky/include/kandinsky/context.h | 5 +- kandinsky/include/kandinsky/ion_context.h | 1 - python/port/genhdr/qstrdefs.in.h | 2 + python/port/helpers.cpp | 3 + python/port/mod/kandinsky/modkandinsky.cpp | 139 ++++- python/port/mod/kandinsky/modkandinsky.h | 2 + .../port/mod/kandinsky/modkandinsky_table.c | 4 + python/port/port.cpp | 498 +++++++++++++++++- python/port/port.h | 208 ++++++++ 15 files changed, 958 insertions(+), 41 deletions(-) diff --git a/apps/external/extapp_api.cpp b/apps/external/extapp_api.cpp index 1e7fd7aeb..03cbef00a 100644 --- a/apps/external/extapp_api.cpp +++ b/apps/external/extapp_api.cpp @@ -81,5 +81,87 @@ extern "C" void (* const apiPointers[])(void) = { (void (*)(void)) extapp_waitForVBlank, (void (*)(void)) extapp_clipboardStore, (void (*)(void)) extapp_clipboardText, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + (void (*)(void)) nullptr, + + // khicas from here, subject to change + (void (*)(void)) numworks_draw_string, + (void (*)(void)) numworks_draw_string_small, + (void (*)(void)) numworks_set_pixel, + (void (*)(void)) numworks_fill_rect, + (void (*)(void)) numworks_get_pixel, + (void (*)(void)) numworks_hide_graph, + (void (*)(void)) numworks_wait_1ms, + (void (*)(void)) waitforvblank, + (void (*)(void)) statuslinemsg, + (void (*)(void)) statusline, + (void (*)(void)) getkey, + (void (*)(void)) GetKey, + (void (*)(void)) alphawasactive, + (void (*)(void)) lock_alpha, + (void (*)(void)) reset_kbd, + (void (*)(void)) back_key_pressed, + (void (*)(void)) enable_back_interrupt, + (void (*)(void)) disable_back_interrupt, + (void (*)(void)) os_set_angle_unit, + (void (*)(void)) os_get_angle_unit, + (void (*)(void)) os_file_browser, + (void (*)(void)) file_exists, + (void (*)(void)) erase_file, + (void (*)(void)) read_file, + (void (*)(void)) write_file, + (void (*)(void)) mp_hal_input, (void (*)(void)) nullptr }; diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 92905e9ca..ec55f9ea4 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -138,6 +138,25 @@ constexpr Event Arctangent = Event::ShiftKey(Keyboard::Key::Tangent); constexpr Event Equal = Event::ShiftKey(Keyboard::Key::Pi); constexpr Event Lower = Event::ShiftKey(Keyboard::Key::Sqrt); constexpr Event Greater = Event::ShiftKey(Keyboard::Key::Square); +constexpr Event shiftans = Event::ShiftKey(Keyboard::Key::Ans); +constexpr Event shiftplus = Event::ShiftKey(Keyboard::Key::Plus); +constexpr Event shiftfois = Event::ShiftKey(Keyboard::Key::Multiplication); +constexpr Event shiftdiv = Event::ShiftKey(Keyboard::Key::Division); +constexpr Event shiftminus = Event::ShiftKey(Keyboard::Key::Minus); +constexpr Event shift1 = Event::ShiftKey(Keyboard::Key::One); +constexpr Event shift2 = Event::ShiftKey(Keyboard::Key::Two); +constexpr Event shift3 = Event::ShiftKey(Keyboard::Key::Three); +constexpr Event shift4 = Event::ShiftKey(Keyboard::Key::Four); +constexpr Event shift5 = Event::ShiftKey(Keyboard::Key::Five); +constexpr Event shift6 = Event::ShiftKey(Keyboard::Key::Six); +constexpr Event shift7 = Event::ShiftKey(Keyboard::Key::Seven); +constexpr Event shift8 = Event::ShiftKey(Keyboard::Key::Eight); +constexpr Event shift9 = Event::ShiftKey(Keyboard::Key::Nine); +constexpr Event shift0 = Event::ShiftKey(Keyboard::Key::Zero); +constexpr Event shiftdot = Event::ShiftKey(Keyboard::Key::Dot); +constexpr Event shiftee = Event::ShiftKey(Keyboard::Key::EE); +constexpr Event shiftlp = Event::ShiftKey(Keyboard::Key::LeftParenthesis); +constexpr Event shiftrp = Event::ShiftKey(Keyboard::Key::RightParenthesis); constexpr Event BrightnessPlus = Event::ShiftKey(Keyboard::Key::Plus); constexpr Event BrightnessMinus = Event::ShiftKey(Keyboard::Key::Minus); @@ -161,7 +180,6 @@ constexpr Event ShiftThree = Event::ShiftKey(Keyboard::Key::Three); constexpr Event Colon = Event::AlphaKey(Keyboard::Key::XNT); constexpr Event SemiColon = Event::AlphaKey(Keyboard::Key::Var); constexpr Event DoubleQuotes = Event::AlphaKey(Keyboard::Key::Toolbox); -constexpr Event Percent = Event::AlphaKey(Keyboard::Key::Backspace); constexpr Event LowerA = Event::AlphaKey(Keyboard::Key::Exp); constexpr Event LowerB = Event::AlphaKey(Keyboard::Key::Ln); @@ -197,8 +215,11 @@ constexpr Event Space = Event::AlphaKey(Keyboard::Key::Minus); constexpr Event Question = Event::AlphaKey(Keyboard::Key::Zero); constexpr Event Exclamation = Event::AlphaKey(Keyboard::Key::Dot); +constexpr Event alphaans = Event::AlphaKey(Keyboard::Key::Ans); // Shift + Alpha +constexpr Event Percent = Event::ShiftAlphaKey(Keyboard::Key::Back); +constexpr Event SimpleQuote = Event::ShiftAlphaKey(Keyboard::Key::Toolbox); constexpr Event UpperA = Event::ShiftAlphaKey(Keyboard::Key::Exp); constexpr Event UpperB = Event::ShiftAlphaKey(Keyboard::Key::Ln); @@ -231,6 +252,7 @@ constexpr Event UpperX = Event::ShiftAlphaKey(Keyboard::Key::Two); constexpr Event UpperY = Event::ShiftAlphaKey(Keyboard::Key::Three); constexpr Event UpperZ = Event::ShiftAlphaKey(Keyboard::Key::Plus); +constexpr Event shiftalphaans = Event::ShiftAlphaKey(Keyboard::Key::Ans); // Special constexpr Event None = Event::Special(0); diff --git a/ion/include/ion/keyboard/layout_B2/layout_events.h b/ion/include/ion/keyboard/layout_B2/layout_events.h index 3a1f75260..01338d947 100644 --- a/ion/include/ion/keyboard/layout_B2/layout_events.h +++ b/ion/include/ion/keyboard/layout_B2/layout_events.h @@ -25,30 +25,30 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { U(), U(), TL(), TL(), TL(), TL(), T("["), T("]"), T("{"), T("}"), T("_"), T("→"), T("asin(\x11)"), T("acos(\x11)"), T("atan(\x11)"), T("="), T("<"), T(">"), - TL(), TL(), TL(), T("(\x11)"), U(), U(), - TL(), TL(), TL(), U(), U(), U(), - TL(), TL(), TL(), TL(), TL(), U(), - U(), U(), U(), U(), U(), U(), + T("17"), T("18"), T("19"), T("20"), T("21"), U(), + T("14"), T("15"), T("16"), T("factor(\x11)"), T("%"), U(), + T("11"), T("12"), T("13"), T("normal(\x11)"), T("\\"), U(), + T("10"), T("11"), T("12"), T("20"), U(), U(), // Alpha U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), - U(), U(), T(":"), T(";"), T("\""), T("%"), + U(), U(), T(":"), T(";"), T("\""), U(), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), T("g"), T("h"), T("i"), T("j"), T("k"), T("l"), T("m"), T("n"), T("o"), T("p"), T("q"), U(), T("r"), T("s"), T("t"), T("u"), T("v"), U(), T("w"), T("x"), T("y"), T("z"), T(" "), U(), - T("?"), T("!"), U(), U(), U(), U(), + T("?"), T("!"), U(), TL(), U(), U(), // Shift+Alpha U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), - U(), U(), U(), U(), U(), U(), + U(), U(), U(), U(), T("'"), T("%"), T("A"), T("B"), T("C"), T("D"), T("E"), T("F"), T("G"), T("H"), T("I"), T("J"), T("K"), T("L"), T("M"), T("N"), T("O"), T("P"), T("Q"), U(), T("R"), T("S"), T("T"), T("U"), T("V"), U(), T("W"), T("X"), T("Y"), T("Z"), U(), U(), - U(), U(), U(), U(), U(), U(), + U(), U(), U(), TL(), U(), U(), }; #if DEBUG diff --git a/ion/include/ion/keyboard/layout_B3/layout_events.h b/ion/include/ion/keyboard/layout_B3/layout_events.h index a1f9502fa..fc9f20fe2 100644 --- a/ion/include/ion/keyboard/layout_B3/layout_events.h +++ b/ion/include/ion/keyboard/layout_B3/layout_events.h @@ -25,14 +25,14 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { U(), U(), TL(), TL(), TL(), TL(), T("["), T("]"), T("{"), T("}"), T("_"), T("→"), T("asin(\x11)"), T("acos(\x11)"), T("atan(\x11)"), T("="), T("<"), T(">"), - TL(), TL(), TL(), U(), U(), U(), - TL(), TL(), TL(), U(), U(), U(), - TL(), TL(), TL(), TL(), TL(), U(), - U(), U(), U(), U(), U(), U(), + T("17"), T("18"), T("19"), T("20"), T("21"), U(), + T("14"), T("15"), T("16"), T("factor(\x11)"), T("%"), U(), + T("11"), T("12"), T("13"), T("normal(\x11)"), T("\\"), U(), + T("10"), T("11"), T("12"), T("20"), U(), U(), // Alpha U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), - U(), U(), T(":"), T(";"), T("\""), T("%"), + U(), U(), T(":"), T(";"), T("\""), U(), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), T("g"), T("h"), T("i"), T("j"), T("k"), T("l"), T("m"), T("n"), T("o"), T("p"), T("q"), U(), @@ -42,7 +42,7 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { // Shift+Alpha U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), - U(), U(), U(), U(), U(), U(), + U(), U(), U(), U(), T("'"), T("%"), T("A"), T("B"), T("C"), T("D"), T("E"), T("F"), T("G"), T("H"), T("I"), T("J"), T("K"), T("L"), T("M"), T("N"), T("O"), T("P"), T("Q"), U(), diff --git a/ion/include/ion/storage.h b/ion/include/ion/storage.h index 5138c1b76..fedd6ba35 100644 --- a/ion/include/ion/storage.h +++ b/ion/include/ion/storage.h @@ -115,7 +115,6 @@ public: void destroyRecordWithBaseNameAndExtension(const char * baseName, const char * extension); void destroyRecordsWithExtension(const char * extension); -private: constexpr static uint32_t Magic = 0xEE0BDDBA; constexpr static size_t k_maxRecordSize = (1 << sizeof(record_size_t)*8); diff --git a/kandinsky/include/kandinsky/color.h b/kandinsky/include/kandinsky/color.h index 8e1cafa50..d15835ae7 100644 --- a/kandinsky/include/kandinsky/color.h +++ b/kandinsky/include/kandinsky/color.h @@ -34,8 +34,8 @@ public: static KDColor blend(KDColor first, KDColor second, uint8_t alpha); KDColor invert() const { return KDColor(~m_value); } operator uint16_t() const { return m_value; } -private: constexpr KDColor(uint16_t value) : m_value(value) {} +private: uint16_t m_value; }; diff --git a/kandinsky/include/kandinsky/context.h b/kandinsky/include/kandinsky/context.h index bcfc4ee74..9e267cea0 100644 --- a/kandinsky/include/kandinsky/context.h +++ b/kandinsky/include/kandinsky/context.h @@ -33,13 +33,10 @@ public: void fillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer); void blendRectWithMask(KDRect rect, KDColor color, const uint8_t * mask, KDColor * workingBuffer); void strokeRect(KDRect rect, KDColor color); - + KDContext(KDPoint origin, KDRect clippingRect); virtual void pushRect(KDRect, const KDColor * pixels) = 0; virtual void pushRectUniform(KDRect rect, KDColor color) = 0; virtual void pullRect(KDRect rect, KDColor * pixels) = 0; -protected: - KDContext(KDPoint origin, KDRect clippingRect); -private: KDRect absoluteFillRect(KDRect rect); KDPoint pushOrPullString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxByteLength, bool push, int * result = nullptr); KDPoint m_origin; diff --git a/kandinsky/include/kandinsky/ion_context.h b/kandinsky/include/kandinsky/ion_context.h index 5cfd6cd9e..0dc1774fb 100644 --- a/kandinsky/include/kandinsky/ion_context.h +++ b/kandinsky/include/kandinsky/ion_context.h @@ -27,7 +27,6 @@ public: bool zoomInhibit; bool gammaEnabled; int zoomPosition; -private: KDIonContext(); void pushRect(KDRect rect, const KDColor * pixels) override; void pushRectUniform(KDRect rect, KDColor color) override; diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 58c36bc71..5b96067ed 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -129,6 +129,8 @@ Q(.) Q(EE) Q(Ans) Q(EXE) +Q(get_key) +Q(Pause) // Turtle QSTRs Q(turtle) diff --git a/python/port/helpers.cpp b/python/port/helpers.cpp index 438f7ca47..71fb5e879 100644 --- a/python/port/helpers.cpp +++ b/python/port/helpers.cpp @@ -1,5 +1,8 @@ #include "helpers.h" #include +#ifdef SIMULATOR +#include +#endif extern "C" { #include "mphalport.h" } diff --git a/python/port/mod/kandinsky/modkandinsky.cpp b/python/port/mod/kandinsky/modkandinsky.cpp index 469fdb86b..6b8a3db5c 100644 --- a/python/port/mod/kandinsky/modkandinsky.cpp +++ b/python/port/mod/kandinsky/modkandinsky.cpp @@ -8,19 +8,22 @@ extern "C" { #include "port.h" static KDColor ColorForTuple(mp_obj_t tuple) { - size_t len; - mp_obj_t * elem; + if (MP_OBJ_IS_SMALL_INT(tuple)) // BP change: accept int for color + return MP_OBJ_SMALL_INT_VALUE(tuple); - mp_obj_get_array(tuple, &len, &elem); - if (len != 3) { - mp_raise_TypeError("color needs 3 components"); - } + size_t len; + mp_obj_t * elem; - return KDColor::RGB888( - mp_obj_get_int(elem[0]), - mp_obj_get_int(elem[1]), - mp_obj_get_int(elem[2]) - ); + mp_obj_get_array(tuple, &len, &elem); + if (len != 3) { + mp_raise_TypeError("color needs 3 components"); + } + + return KDColor::RGB888( + mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), + mp_obj_get_int(elem[2]) + ); } static mp_obj_t TupleForRGB(uint8_t r, uint8_t g, uint8_t b) { @@ -179,3 +182,117 @@ mp_obj_t modkandinsky_get_keys() { return result; } + +/* C-- SDK (c) B. Parisse, 2019 */ +mp_obj_t modkandinsky_Pause(mp_obj_t x) { + double d=mp_obj_get_float(x); + numworks_wait_1ms(d*1000); + return mp_const_none; +} + +#define LCD_WIDTH_PX 320 +#define LCD_HEIGHT_PX 222 + +void numworks_set_pixel(int x, int y, int color) { + if (x<0 || x>=LCD_WIDTH_PX || y<0 || y>=LCD_HEIGHT_PX) + return; + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,0,320,240)); + ctx->setOrigin(KDPoint(0,0)); + KDColor c(color); + KDPoint point(x,y+18); + KDIonContext::sharedContext()->pushRect(KDRect(point, 1, 1), &c); + ctx->setClippingRect(save); + ctx->setOrigin(o); +} + +void numworks_fill_rect(int x,int y,int w,int h,int c){ + KDColor color = c; + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,0,320,240)); + ctx->setOrigin(KDPoint(0,0)); +#if 1 + if (x<0){ + w += x; + x=0; + } + if (y<0){ + h += y; + y=0; + } + if (h+y>=LCD_HEIGHT_PX) + h=LCD_HEIGHT_PX-y; + if (x+w>=LCD_WIDTH_PX) + w=LCD_WIDTH_PX-x; + if (h<=0 || w<=0) + return; + KDRect rect(x,y+18,w,h); + KDIonContext::sharedContext()->pushRectUniform(rect,color); +#else + KDRect rect(x,y,w,h); + KDIonContext::sharedContext()->fillRect(rect, color); +#endif + ctx->setClippingRect(save); + ctx->setOrigin(o); +} + +int numworks_get_pixel(int x, int y) { + KDPoint point(x,y); + KDColor c = KDIonContext::sharedContext()->getPixel(point); + return c; +} + +int numworks_draw_string(int x,int y,int c,int bg,const char * text,bool fake){ + auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + KDPoint point(x,y); + if (ptr) + ptr->displaySandbox(); + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,18,320,fake?0:222)); + ctx->setOrigin(KDPoint(0,18)); + point=KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, c, bg); + ctx->setClippingRect(save); + ctx->setOrigin(o); + return point.x(); +} + +int numworks_draw_string_small(int x,int y,int c,int bg,const char * text,bool fake){ + auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + KDPoint point(x,y); + if (ptr) + ptr->displaySandbox(); + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,18,320,fake?0:222)); + ctx->setOrigin(KDPoint(0,18)); + point=ctx->drawString(text, point, KDFont::SmallFont, c, bg); + ctx->setClippingRect(save); + ctx->setOrigin(o); + return point.x(); +} + +void numworks_hide_graph(){ + auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + if (ptr) + ptr->hideSandbox(); +} + +void numworks_show_graph(){ + auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + if (ptr) + ptr->displaySandbox(); +} + +// Python module get_key() addition +mp_obj_t modkandinsky_get_key() { + micropython_port_interrupt_if_needed(); + int key=getkey(false); // no suspend + return mp_obj_new_int(key); +} diff --git a/python/port/mod/kandinsky/modkandinsky.h b/python/port/mod/kandinsky/modkandinsky.h index 4191155bc..15bc28a31 100644 --- a/python/port/mod/kandinsky/modkandinsky.h +++ b/python/port/mod/kandinsky/modkandinsky.h @@ -7,3 +7,5 @@ mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t *args); mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t *args); mp_obj_t modkandinsky_wait_vblank(); mp_obj_t modkandinsky_get_keys(); +mp_obj_t modkandinsky_get_key(); +mp_obj_t modkandinsky_Pause(mp_obj_t x) ; diff --git a/python/port/mod/kandinsky/modkandinsky_table.c b/python/port/mod/kandinsky/modkandinsky_table.c index 253f856a7..cf8490c6f 100644 --- a/python/port/mod/kandinsky/modkandinsky_table.c +++ b/python/port/mod/kandinsky/modkandinsky_table.c @@ -7,6 +7,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_string_obj, 3, 5, m STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_fill_rect_obj, 5, 5, modkandinsky_fill_rect); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_wait_vblank_obj, modkandinsky_wait_vblank); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_get_keys_obj, modkandinsky_get_keys); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_get_key_obj, modkandinsky_get_key); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modkandinsky_Pause_obj, modkandinsky_Pause); STATIC const mp_rom_map_elem_t modkandinsky_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_kandinsky) }, @@ -17,6 +19,8 @@ STATIC const mp_rom_map_elem_t modkandinsky_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_fill_rect), (mp_obj_t)&modkandinsky_fill_rect_obj }, { MP_ROM_QSTR(MP_QSTR_wait_vblank), (mp_obj_t)&modkandinsky_wait_vblank_obj }, { MP_ROM_QSTR(MP_QSTR_get_keys), (mp_obj_t)&modkandinsky_get_keys_obj }, + { MP_ROM_QSTR(MP_QSTR_get_key), (mp_obj_t)&modkandinsky_get_key_obj }, + { MP_ROM_QSTR(MP_QSTR_Pause), (mp_obj_t)&modkandinsky_Pause_obj }, }; STATIC MP_DEFINE_CONST_DICT(modkandinsky_module_globals, modkandinsky_module_globals_table); diff --git a/python/port/port.cpp b/python/port/port.cpp index 163aefd24..0a1735bdd 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -1,6 +1,14 @@ +#ifdef SIMULATOR +#include +#endif +#include #include "port.h" -#include +#include +#include +#include +#include "../../apps/apps_container.h" +#include "../../apps/global_preferences.h" #include #include @@ -78,9 +86,9 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) { /* End of mp_obj_print_exception. */ } - assert(sCurrentExecutionEnvironment == this); - sCurrentExecutionEnvironment = nullptr; -} + assert(sCurrentExecutionEnvironment == this); + sCurrentExecutionEnvironment = nullptr; + } void MicroPython::ExecutionEnvironment::interrupt() { mp_keyboard_interrupt(); @@ -197,11 +205,485 @@ mp_import_stat_t mp_import_stat(const char *path) { } void mp_hal_stdout_tx_strn_cooked(const char * str, size_t len) { - assert(sCurrentExecutionEnvironment != nullptr); - sCurrentExecutionEnvironment->printText(str, len); + if (sCurrentExecutionEnvironment != nullptr) + sCurrentExecutionEnvironment->printText(str, len); } const char * mp_hal_input(const char * prompt) { - assert(sCurrentExecutionEnvironment != nullptr); - return sCurrentExecutionEnvironment->inputText(prompt); + if (sCurrentExecutionEnvironment != nullptr) + return sCurrentExecutionEnvironment->inputText(prompt); + return 0; } + +/* C-- SDK , (c) B. Parisse 2019 */ + +const char * read_file(const char * filename){ +#if 1 + Ion::Storage * s=Ion::Storage::sharedStorage(); + const Ion::Storage::Record r=s->recordNamed(filename); + if (r.isNull()) + return 0; + Ion::Storage::Record::Data d=r.value(); + const char * ptr=(const char *)d.buffer; + if (ptr) + return ptr+1; + else + return 0; +#endif + if (sScriptProvider != nullptr) + return sScriptProvider->contentOfScript(filename); + return "undef"; +} + +bool write_file(const char * filename,const char * content,size_t len){ + Ion::Storage * s=Ion::Storage::sharedStorage(); + auto res=s->createRecordWithFullName(filename,content,strlen(content)+1); + if (res==Ion::Storage::Record::ErrorStatus::NameTaken){ + auto r=s->recordNamed(filename); + Ion::Storage::Record::Data d; + d.buffer=content; + d.size=(len?len:strlen(content))+1; + return r.setValue(d)==Ion::Storage::Record::ErrorStatus::None; + } + if (res==Ion::Storage::Record::ErrorStatus::None) + return write_file(filename,content,len); + return false; +} + +bool file_exists(const char * filename){ + Ion::Storage * s=Ion::Storage::sharedStorage(); + return s->isFullNameTaken(filename); +} + +bool erase_file(const char * filename){ + Ion::Storage * s=Ion::Storage::sharedStorage(); + auto r= s->recordNamed(filename); + if (r.isNull()) + return false; + r.destroy(); + return true; +} + + +#if 1 +int os_file_browser(const char ** filenames,int maxrecords,const char * extension){ + Ion::Storage * s=Ion::Storage::sharedStorage(); + int n=s->numberOfRecordsWithExtension(extension); + if (!n) return 0; + if (n>maxrecords) n=maxrecords; + for (int i=0;irecordWithExtensionAtIndex(extension, i); + filenames[i]=r.fullName(); + } + filenames[n]=0; + return n; +} + // const char * ptr=(const char *)r.value().buffer; + /* storage.h + Ion::Storage::Record::Data structure avec 2 membres + const void * buffer et size_t size + + Record(const char * fullName = nullptr); + Record(const char * basename, const char * extension); + Data value(); + Ion::Storage::Record::ErrorStatus setValue(Ion::Storage::Record::Data); + void destroy(void); + + // Record creation + Record::ErrorStatus createRecordWithFullName(const char * fullName, const void * data, size_t size); + Record::ErrorStatus createRecordWithExtension(const char * baseName, const char * extension, const void * data, size_t size); + + // Record getters + Record recordWithExtensionAtIndex(const char * extension, int index); + Record recordNamed(const char * fullName); + Record recordBaseNamedWithExtension(const char * baseName, const char * extension); + Record recordBaseNamedWithExtensions(const char * baseName, const char * const extension[], size_t numberOfExtensions); + + // Record destruction + void destroyAllRecords(); + void destroyRecordWithBaseNameAndExtension(const char * baseName, const char * extension); + void destroyRecordsWithExtension(const char * extension); + + + */ +#endif + +void statuslinemsg(const char * msg){ + AppsContainer::sharedAppsContainer()->reloadTitleBarView(); + auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + if (ptr) + ptr->displaySandbox(); + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,0,280,18)); + ctx->setOrigin(KDPoint(0,0)); + KDRect rect(0,0,280,18); + KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/); + if (strlen(msg)>25) + ctx->drawString(msg, KDPoint(0,0), KDFont::SmallFont, 0, 64934); + else + ctx->drawString(msg, KDPoint(0,0), KDFont::LargeFont, 0, 64934); + ctx->setClippingRect(save); + ctx->setOrigin(o); +} + +bool os_set_angle_unit(int mode){ + Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); + if (mode==0){ // rad + preferences->setAngleUnit(Poincare::Preferences::AngleUnit::Radian); + return true; + } + if (mode==1){ // deg + preferences->setAngleUnit(Poincare::Preferences::AngleUnit::Degree); + return true; + } + return false; + if (mode==2){ // grad + return true; + } +} + +int os_get_angle_unit(){ + Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); + if (preferences->angleUnit()==Poincare::Preferences::AngleUnit::Radian) + return 0; + if (preferences->angleUnit()==Poincare::Preferences::AngleUnit::Degree) + return 1; + return 2; +} + +#ifdef SIMULATOR +#define TICKS_PER_MINUTE 60000 +#else +#define TICKS_PER_MINUTE 11862 +extern const void * _stack_start; +extern const void * _heap_start; +#endif +//int time_shift=0; // set it via time() command in KhiCAS +void statusline(int mode, size_t heap){ + AppsContainer::sharedAppsContainer()->reloadTitleBarView(); + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,0,320,18)); + ctx->setOrigin(KDPoint(0,0)); + KDRect rect(0,0,mode==1?320:280,18); + KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/); + const char * text=0; + Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); + if (preferences->angleUnit() == Poincare::Preferences::AngleUnit::Radian) + text="rad"; + else + text="deg"; + // ctx->drawString(text, KDPoint(5,1), KDFont::SmallFont, 0, 63488 /* Palette::Red*/); + ctx->drawString(text, KDPoint(5,1), KDFont::SmallFont, 0, 64934); +#ifdef GIAC_LINKED + if (khicas_eval) + text="KHICAS"; + else + text="PYTHON"; +#else + text="KHICAS"; +#endif + ctx->drawString(text, KDPoint(70,1), KDFont::SmallFont, 0, 64934); + char bufheap[16]; +#if 0 //ndef SIMULATOR +#endif + int x; + x=(heap&0xf0000000)>>28; + bufheap[0]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf000000)>>24; + bufheap[1]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf00000)>>20; + bufheap[2]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf0000)>>16; + bufheap[3]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf000)>>12; + bufheap[4]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf00)>>8; + bufheap[5]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf0)>>4; + bufheap[6]=(x>9?'a'+(x-10):'0'+x); + x=(heap&0xf); + bufheap[7]=(x>9?'a'+(x-10):'0'+x); + bufheap[8]=0; + if(heap != 0) ctx->drawString(bufheap,KDPoint(130,1),KDFont::SmallFont, 0, 64934); +#ifdef GIAC_SHOWTIME + int d=(Ion::Timing::millis()/TICKS_PER_MINUTE +time_shift) % (24*60); // minutes + char buf[32]={0,0,0,0}; + int h=d/60; + buf[0]='0'+h/10; + buf[1]='0'+(h%10); + buf[2]=':'; + ctx->drawString(buf, KDPoint(148,1), KDFont::SmallFont, 0, 64934); + int mn=d%60; + buf[0]='0'+mn/10; + buf[1]='0'+(mn%10); + buf[2]=0; + ctx->drawString(buf, KDPoint(168,1), KDFont::SmallFont, 0, 64934); +#endif + text=" "; + if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::Shift) + text="shift "; + else { + if (Ion::Events::isAlphaActive()){ + if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::AlphaLock) + text="alphal"; + if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::ShiftAlphaLock) + text="ALPHAL"; + if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::Alpha) + text="1alpha"; + if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::ShiftAlpha) + text="1ALPHA"; + } + } + ctx->drawString(text, KDPoint(232,1), KDFont::SmallFont, 0, 64934 /* Palette::YellowDark*/); + if (mode==1){ + if (Ion::USB::isPlugged()) + text="charge"; + else { + auto c=Ion::Battery::level(); + if (c==Ion::Battery::Charge::EMPTY) + text="empty "; + if (c==Ion::Battery::Charge::LOW) + text="low "; + if (c==Ion::Battery::Charge::FULL) + text="full "; + } + ctx->drawString(text, KDPoint(280,1), KDFont::SmallFont, 0, 64934 /* Palette::YellowDark*/); + } + ctx->setClippingRect(save); + ctx->setOrigin(o); +} + +bool isalphaactive(){ + return Ion::Events::isAlphaActive(); +} + +void lock_alpha(){ + Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock); + statusline(0,0); +} + +void reset_kbd(){ + Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default); + statusline(0,0); +} + +bool alphawasactive_=false; +bool alphawasactive(){ + return alphawasactive_; +} + +bool waitforvblank(){ + return Ion::Display::waitForVBlank(); +} + +bool back_key_pressed() { + static int c = 0; + + ++c ; + if (c<400 || (c & 0xf)!= 0) { + return false; + } +#ifdef SIMULATOR + Fl::wait(0.00001); +#endif + + Ion::Keyboard::State scan = Ion::Keyboard::scan(); + // if (scan!=16) std::cerr << scan << '\n'; + Ion::Keyboard::Key interruptKey = static_cast(mp_interrupt_char); + if (scan.keyDown(interruptKey) + // || scan.keyDown(static_cast(16)) + ) + return true; + return false; +} + +int getkey_raw(bool allow_suspend){ + int key=-1; + size_t t1=Ion::Timing::millis(); + for (;;){ + int timeout=10000; + alphawasactive_=Ion::Events::isAlphaActive(); + Ion::Events::Event event=Ion::Events::getEvent(&timeout); + auto ctx=KDIonContext::sharedContext(); + KDRect save=ctx->m_clippingRect; + KDPoint o=ctx->m_origin; + ctx->setClippingRect(KDRect(0,0,320,240)); + ctx->setOrigin(KDPoint(0,18)); + KDRect rect(90,63,140,75); + if (event==Ion::Events::None){ + size_t t2=Ion::Timing::millis(); + if (t2-t1>2*TICKS_PER_MINUTE){ + // KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/); + event=Ion::Events::OnOff; + } + } + else + t1=Ion::Timing::millis(); + if (event == Ion::Events::USBPlug) { + statusline(0,0); + // KDIonContext::sharedContext()->pushRectUniform(rect,33333); + if (Ion::USB::isPlugged()) { + if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + Ion::LED::setColor(KDColorBlack); + Ion::LED::updateColorWithPlugAndCharge(); + GlobalPreferences::sharedGlobalPreferences()->setExamMode(false); + // displayExamModePopUp(false); + } else { + Ion::USB::enable(); + } + Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()); + } else { + Ion::USB::disable(); + } + } + if (event == Ion::Events::USBEnumeration || event == Ion::Events::USBPlug || event == Ion::Events::BatteryCharging) { + Ion::LED::updateColorWithPlugAndCharge(); + } + if (event == Ion::Events::USBEnumeration + ) { + KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/); + if (Ion::USB::isPlugged()) { + /* 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 + * event loop, we update the battery state "manually" here. + * We do it before switching to USB application to redraw the battery + * pictogram. */ + // updateBatteryState(); + KDIonContext::sharedContext()->pushRectUniform(rect,22222); + auto ctx=KDIonContext::sharedContext(); + int y=58; + ctx->drawString("Connecte ! ", KDPoint(100,y), KDFont::LargeFont, 65535, 0); + y+=18; + ctx->drawString(" DFU mode ", KDPoint(100,y), KDFont::LargeFont, 65535, 0); + y+=18; + ctx->drawString("Back quitte", KDPoint(100,y), KDFont::LargeFont, 65535, 0); + y-=18; + Ion::USB::DFU(); + KDIonContext::sharedContext()->pushRectUniform(rect,44444); + ctx->drawString("Deconnecte!", KDPoint(100,y), KDFont::LargeFont, 65535, 0); + // Update LED when exiting DFU mode + Ion::LED::updateColorWithPlugAndCharge(); + } else { + /* Sometimes, the device gets an ENUMDNE interrupts when being unplugged + * from a non-USB communicating host (e.g. a USB charger). The interrupt + * must me cleared: if not the next enumeration attempts will not be + * detected. */ + Ion::USB::clearEnumerationInterrupt(); + } + } + if (event.isKeyboardEvent()) { + // m_backlightDimmingTimer.reset(); + // m_suspendTimer.reset(); + Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()); + } + ctx->setClippingRect(save); + ctx->setOrigin(o); + + if (event==Ion::Events::Shift || event==Ion::Events::Alpha){ + statusline(0,0); + continue; + } + if (event.isKeyboardEvent()){ + key=event.id(); + if (key==17 || key==4 || key==5 || key==52) + reset_kbd(); + if (allow_suspend && (key==7 || key==8) ){ // power + Ion::Power::suspend(true); + numworks_fill_rect(0,0,320,240,65535); + Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()); + AppsContainer::sharedAppsContainer()->reloadTitleBarView(); + //AppsContainer::sharedAppsContainer()->redrawWindow(); + statusline(1,0); + //continue; + } + else + statusline(0,0); + break; + } + } + return key; +} + +const short int translated_keys[]= + { + // non shifted + KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_XTT,KEY_CTRL_VARS,KEY_CTRL_CATALOG,KEY_CTRL_DEL, + KEY_CHAR_EXPN,KEY_CHAR_LN,KEY_CHAR_LOG,KEY_CHAR_IMGNRY,',',KEY_CHAR_POW, + KEY_CHAR_SIN,KEY_CHAR_COS,KEY_CHAR_TAN,KEY_CHAR_PI,KEY_CHAR_ROOT,KEY_CHAR_SQUARE, + '7','8','9','(',')',-1, + '4','5','6','*','/',-1, + '1','2','3','+','-',-1, + '0','.',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, + // shifted + KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_CUT,KEY_CTRL_CLIP,KEY_CTRL_PASTE,KEY_CTRL_AC, + KEY_CHAR_LBRCKT,KEY_CHAR_RBRCKT,KEY_CHAR_LBRACE,KEY_CHAR_RBRACE,'_',KEY_CHAR_STORE, + KEY_CHAR_ASIN,KEY_CHAR_ACOS,KEY_CHAR_ATAN,'=','<','>', + KEY_CTRL_F7,KEY_CTRL_F8,KEY_CTRL_F9,KEY_CTRL_F13,KEY_CTRL_F14,-1, + KEY_CTRL_F4,KEY_CTRL_F5,KEY_CTRL_F6,KEY_CHAR_FACTOR,'%',-1, + KEY_CTRL_F1,KEY_CTRL_F2,KEY_CTRL_F3,KEY_CHAR_NORMAL,'\\',-1, + KEY_CTRL_F10,KEY_CTRL_F11,KEY_CTRL_F12,KEY_SHIFT_ANS,KEY_CTRL_EXE,-1, + // alpha + KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','"',KEY_CTRL_DEL, + 'a','b','c','d','e','f', + 'g','h','i','j','k','l', + 'm','n','o','p','q',-1, + 'r','s','t','u','v',-1, + 'w','x','y','z',' ',-1, + '?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, + // alpha shifted + KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','\'','%', + 'A','B','C','D','E','F', + 'G','H','I','J','K','L', + 'M','N','O','P','Q',-1, + 'R','S','T','U','V',-1, + 'W','X','Y','Z',' ',-1, + '?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, + }; + +int getkey(bool allow_suspend){ + int k=getkey_raw(allow_suspend); + // translate + return translated_keys[k]; +} + +// Casio prototype +void GetKey(int * key){ + *key=getkey(true); +} + + +void numworks_wait_1ms(int ms){ + for (int i=0;i(Ion::Keyboard::Key::Back); + if (scan.keyDown(interruptKey)) + return; + Ion::Timing::msleep(128); + } + Ion::Timing::msleep(ms % 128); +} + +void enable_back_interrupt(){ + mp_interrupt_char = (int)Ion::Keyboard::Key::Back; +} + +void disable_back_interrupt(){ + mp_interrupt_char = -1; +} + diff --git a/python/port/port.h b/python/port/port.h index f0b3a0407..869b6f937 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -36,4 +36,212 @@ void registerScriptProvider(ScriptProvider * s); }; +extern "C" { +/* + basic SDK for direct control of the calculator like in KhiCAS + */ + bool waitforvblank(); + int os_file_browser(const char ** filenames,int maxrecords,const char * extension); + void numworks_hide_graph(); + void numworks_show_graph(); + void enable_back_interrupt(); + void disable_back_interrupt(); + int os_get_angle_unit(); + bool os_set_angle_unit(int mode); + const char * read_file(const char * filename); + bool write_file(const char * filename,const char * content,size_t len); +int getkey_raw(bool allow_suspend); // Numworks scan code +int getkey(bool allow_suspend); // transformed +void GetKey(int * key); // Casio like +bool isalphaactive(); +bool alphawasactive(); // alpha status before getkey +bool back_key_pressed() ; +void lock_alpha(); +void reset_kbd(); +void statusline(int mode=0, size_t=0); // display status line +void statuslinemsg(const char * msg); // display a message in statusline +void numworks_fill_rect(int x,int y,int w,int h,int c); // y=0 is automatically translated by 18 for statusline +void numworks_set_pixel(int x,int y,int c); +int numworks_get_pixel(int x,int y); +/* draw_string returns new x position, use fake=true to compute without drawing */ +int numworks_draw_string(int x,int y,int c,int bg,const char * s,bool fake=false); +int numworks_draw_string_small(int x,int y,int c,int bg,const char * s,bool fake=false); +// scriptstore +bool file_exists(const char * filename); +bool erase_file(const char * filename); +const char * read_file(const char * filename); +bool write_file(const char * filename,const char * s,size_t len=0); +int giac_filebrowser(char * filename,const char * extension,const char * title); +void numworks_wait_1ms(int ms); +//double millis(); +//extern int time_shift; // shift for the clock + + +// Character codes +#define KEY_CHAR_0 0x30 +#define KEY_CHAR_1 0x31 +#define KEY_CHAR_2 0x32 +#define KEY_CHAR_3 0x33 +#define KEY_CHAR_4 0x34 +#define KEY_CHAR_5 0x35 +#define KEY_CHAR_6 0x36 +#define KEY_CHAR_7 0x37 +#define KEY_CHAR_8 0x38 +#define KEY_CHAR_9 0x39 +#define KEY_CHAR_DP 0x2e +#define KEY_CHAR_EXP 0x0f +#define KEY_CHAR_PMINUS 30200 +#define KEY_CHAR_PLUS 43 +#define KEY_CHAR_MINUS 45 +#define KEY_CHAR_MULT 42 +#define KEY_CHAR_DIV 47 +#define KEY_CHAR_FRAC 0xbb +#define KEY_CHAR_LPAR 0x28 +#define KEY_CHAR_RPAR 0x29 +#define KEY_CHAR_COMMA 0x2c +#define KEY_CHAR_STORE 0x0e +#define KEY_CHAR_LOG 0x95 +#define KEY_CHAR_LN 0x85 +#define KEY_CHAR_SIN 0x81 +#define KEY_CHAR_COS 0x82 +#define KEY_CHAR_TAN 0x83 +#define KEY_CHAR_SQUARE 0x8b +#define KEY_CHAR_POW 0xa8 +#define KEY_CHAR_IMGNRY 0x7f50 +#define KEY_CHAR_LIST 0x7f51 +#define KEY_CHAR_MAT 0x7f40 +#define KEY_CHAR_EQUAL 0x3d +#define KEY_CHAR_PI 0xd0 +#define KEY_CHAR_ANS 0xc0 +#define KEY_SHIFT_ANS 0xc1 +#define KEY_CHAR_LBRCKT 0x5b +#define KEY_CHAR_RBRCKT 0x5d +#define KEY_CHAR_LBRACE 0x7b +#define KEY_CHAR_RBRACE 0x7d +#define KEY_CHAR_CR 0x0d +#define KEY_CHAR_CUBEROOT 0x96 +#define KEY_CHAR_RECIP 0x9b +#define KEY_CHAR_ANGLE 0x7f54 +#define KEY_CHAR_EXPN10 0xb5 +#define KEY_CHAR_EXPN 0xa5 +#define KEY_CHAR_ASIN 0x91 +#define KEY_CHAR_ACOS 0x92 +#define KEY_CHAR_ATAN 0x93 +#define KEY_CHAR_ROOT 0x86 +#define KEY_CHAR_POWROOT 0xb8 +#define KEY_CHAR_SPACE 0x20 +#define KEY_CHAR_DQUATE 0x22 +#define KEY_CHAR_VALR 0xcd +#define KEY_CHAR_THETA 0xce +#define KEY_CHAR_FACTOR 0xda +#define KEY_CHAR_NORMAL 0xdb +#define KEY_CHAR_A 0x41 +#define KEY_CHAR_B 0x42 +#define KEY_CHAR_C 0x43 +#define KEY_CHAR_D 0x44 +#define KEY_CHAR_E 0x45 +#define KEY_CHAR_F 0x46 +#define KEY_CHAR_G 0x47 +#define KEY_CHAR_H 0x48 +#define KEY_CHAR_I 0x49 +#define KEY_CHAR_J 0x4a +#define KEY_CHAR_K 0x4b +#define KEY_CHAR_L 0x4c +#define KEY_CHAR_M 0x4d +#define KEY_CHAR_N 0x4e +#define KEY_CHAR_O 0x4f +#define KEY_CHAR_P 0x50 +#define KEY_CHAR_Q 0x51 +#define KEY_CHAR_R 0x52 +#define KEY_CHAR_S 0x53 +#define KEY_CHAR_T 0x54 +#define KEY_CHAR_U 0x55 +#define KEY_CHAR_V 0x56 +#define KEY_CHAR_W 0x57 +#define KEY_CHAR_X 0x58 +#define KEY_CHAR_Y 0x59 +#define KEY_CHAR_Z 0x5a + + +// Control codes +#define KEY_CTRL_NOP 30202 +#define KEY_CTRL_EXE 30201 +#define KEY_CTRL_DEL 30025 +#define KEY_CTRL_AC 30070 +#define KEY_CTRL_FD 30046 +#define KEY_CTRL_UNDO 30045 +#define KEY_CTRL_XTT 30001 +#define KEY_CTRL_EXIT 5 +#define KEY_CTRL_OK 4 +#define KEY_CTRL_SHIFT 30006 +#define KEY_CTRL_ALPHA 30007 +#define KEY_CTRL_OPTN 30008 +#define KEY_CTRL_VARS 30030 +#define KEY_CTRL_UP 1 +#define KEY_CTRL_DOWN 2 +#define KEY_CTRL_LEFT 0 +#define KEY_CTRL_RIGHT 3 +#define KEY_CTRL_F1 30009 +#define KEY_CTRL_F2 30010 +#define KEY_CTRL_F3 30011 +#define KEY_CTRL_F4 30012 +#define KEY_CTRL_F5 30013 +#define KEY_CTRL_F6 30014 +#define KEY_CTRL_F7 30015 +#define KEY_CTRL_F8 30016 +#define KEY_CTRL_F9 30017 +#define KEY_CTRL_F10 30018 +#define KEY_CTRL_F11 30019 +#define KEY_CTRL_F12 30020 +#define KEY_CTRL_F13 30021 +#define KEY_CTRL_F14 30022 +#define KEY_CTRL_CATALOG 30100 +#define KEY_CTRL_CAPTURE 30055 +#define KEY_CTRL_CLIP 30050 +#define KEY_CTRL_CUT 30250 +#define KEY_CTRL_PASTE 30036 +#define KEY_CTRL_INS 30033 +#define KEY_CTRL_MIXEDFRAC 30054 +#define KEY_CTRL_FRACCNVRT 30026 +#define KEY_CTRL_QUIT 30029 +#define KEY_CTRL_PRGM 30028 +#define KEY_CTRL_SETUP 30037 +#define KEY_CTRL_PAGEUP 30052 +#define KEY_CTRL_PAGEDOWN 30053 +#define KEY_CTRL_MENU 30003 +#define KEY_SHIFT_OPTN 30059 +#define KEY_CTRL_RESERVE1 30060 +#define KEY_CTRL_RESERVE2 30061 +#define KEY_SHIFT_LEFT 30062 +#define KEY_SHIFT_RIGHT 30063 + +#define KEY_PRGM_ACON 10 +#define KEY_PRGM_DOWN 37 +#define KEY_PRGM_EXIT 47 +#define KEY_PRGM_F1 79 +#define KEY_PRGM_F2 69 +#define KEY_PRGM_F3 59 +#define KEY_PRGM_F4 49 +#define KEY_PRGM_F5 39 +#define KEY_PRGM_F6 29 +#define KEY_PRGM_LEFT 38 +#define KEY_PRGM_NONE 0 +#define KEY_PRGM_RETURN 31 +#define KEY_PRGM_RIGHT 27 +#define KEY_PRGM_UP 28 +#define KEY_PRGM_1 72 +#define KEY_PRGM_2 62 +#define KEY_PRGM_3 52 +#define KEY_PRGM_4 73 +#define KEY_PRGM_5 63 +#define KEY_PRGM_6 53 +#define KEY_PRGM_7 74 +#define KEY_PRGM_8 64 +#define KEY_PRGM_9 54 +#define KEY_PRGM_A 76 +#define KEY_PRGM_F 26 +#define KEY_PRGM_ALPHA 77 +#define KEY_PRGM_SHIFT 78 +#define KEY_PRGM_MENU 48 +} #endif