diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 30c98c6f4..ed1a683b6 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -77,6 +77,20 @@ jobs:
with:
name: Example-Cpp
path: Example-Cpp.tar
+ Flash2Ram:
+ runs-on: ubuntu-latest
+ steps:
+ - run: sudo apt-get update && sudo apt-get install wget gdb gcc g++ libgmp-dev libmpfr-dev libmpfi-dev libpari-dev libgsl0-dev libxext-dev libpng-dev libjpeg-dev libreadline-dev libncurses5-dev mesa-common-dev libx11-dev libxt-dev libxft-dev libntl-dev libgl1-mesa-dev libgl-dev libao-dev hevea debhelper libfltk1.3-dev build-essential git imagemagick libx11-dev libxext-dev libfreetype6-dev libpng-dev libjpeg-dev pkg-config gcc-arm-none-eabi binutils-arm-none-eabi dfu-util texinfo autoconf-archive -y
+
+ - uses: actions/checkout@v1
+ with:
+ submodules: true
+ - run: make Flash2Ram_rebuild
+ - run: ./tool/archive Flash2Ram.tar Flash2Ram
+ - uses: actions/upload-artifact@master
+ with:
+ name: Flash2Ram
+ path: Flash2Ram.tar
HexEdit:
runs-on: ubuntu-latest
steps:
diff --git a/apps/Flash2Ram/Makefile b/apps/Flash2Ram/Makefile
new file mode 100644
index 000000000..3744a1475
--- /dev/null
+++ b/apps/Flash2Ram/Makefile
@@ -0,0 +1,15 @@
+API=../../api
+CC=arm-none-eabi-gcc
+OBJCOPY=arm-none-eabi-objcopy
+AR=arm-none-eabi-ar
+CFLAGS=-DNDEBUG -ggdb3 -I$(API) -Os -mcpu=cortex-m7 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard -fno-common -fdata-sections -ffunction-sections -fno-exceptions
+LDFLAGS=-Wl,-L$(API) -Wl,--gc-sections -Wl,--entry=entrypoint --specs=nosys.specs -nostartfiles -Wl,-Ur -lapi
+
+%.o: %.cpp
+ $(CC) $(CFLAGS) -c $<
+
+app.elf: main.o peripherals.o selector.o
+ $(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS)
+
+clean:
+ rm -f *.elf *.o
diff --git a/apps/Flash2Ram/app.elf b/apps/Flash2Ram/app.elf
new file mode 100644
index 000000000..53a6b5861
Binary files /dev/null and b/apps/Flash2Ram/app.elf differ
diff --git a/apps/Flash2Ram/app.icon b/apps/Flash2Ram/app.icon
new file mode 100644
index 000000000..790c67c65
Binary files /dev/null and b/apps/Flash2Ram/app.icon differ
diff --git a/apps/Flash2Ram/icon.png b/apps/Flash2Ram/icon.png
new file mode 100644
index 000000000..303bc307d
Binary files /dev/null and b/apps/Flash2Ram/icon.png differ
diff --git a/apps/Flash2Ram/icon.svg b/apps/Flash2Ram/icon.svg
new file mode 100644
index 000000000..aeda7aba9
--- /dev/null
+++ b/apps/Flash2Ram/icon.svg
@@ -0,0 +1,48 @@
+
+
+
+
+
+
diff --git a/apps/Flash2Ram/inc/peripherals.h b/apps/Flash2Ram/inc/peripherals.h
new file mode 100644
index 000000000..e6535a381
--- /dev/null
+++ b/apps/Flash2Ram/inc/peripherals.h
@@ -0,0 +1,18 @@
+#ifndef EXAMPLE_CPP_PERIPHERALS_H_
+#define EXAMPLE_CPP_PERIPHERALS_H_
+
+#include
+
+namespace Peripherals {
+
+extern long long unsigned int keymappings[16];
+extern int keymappings_await[16];
+
+void init_display();
+void waitForKeyPressed();
+void waitForKeyReleased();
+void waitForKeyReleasedTimeout(int timeout);
+
+} // namespace Peripherals
+
+#endif // EXAMPLE_CPP_PERIPHERALS_H_
diff --git a/apps/Flash2Ram/inc/selector.h b/apps/Flash2Ram/inc/selector.h
new file mode 100644
index 000000000..9c847e2ef
--- /dev/null
+++ b/apps/Flash2Ram/inc/selector.h
@@ -0,0 +1,16 @@
+#ifndef EXAMPLE_SELECTOR_H_
+#define EXAMPLE_SELECTOR_H_
+
+namespace Selector {
+
+#define SELECTOR_COLOR_BG 0xFFFF
+#define SELECTOR_COLOR_FG 0x3333
+#define SELECTOR_COLOR_FG_SELECT 0x0000
+#define SELECTOR_COLOR_HEAD_BG 0x0000
+#define SELECTOR_COLOR_HEAD_FG 0xFFFF
+
+const char * select_file(const char * extension_to_match, int max_files);
+
+} // namespace Selector
+
+#endif // EXAMPLE_SELECTOR_H_
diff --git a/apps/Flash2Ram/main.cpp b/apps/Flash2Ram/main.cpp
new file mode 100644
index 000000000..0caddb3cc
--- /dev/null
+++ b/apps/Flash2Ram/main.cpp
@@ -0,0 +1,81 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "inc/peripherals.h"
+#include "inc/selector.h"
+
+extern "C" void extapp_main();
+
+void extapp_main(void) {
+
+ // TODO: Get top bar color
+
+ // Wait for the key to be released before starting the application
+ Peripherals::waitForKeyReleased();
+ // Draw a white background
+ Peripherals::init_display();
+
+
+ // Select a file to copy
+ const char * filename = Selector::select_file("", 100);
+ // Wait for the key to be released
+ Peripherals::waitForKeyReleased();
+
+ // Clear the screen
+ Peripherals::init_display();
+
+ // If no file was selected, exit the application
+ if (filename == NULL) {
+ Peripherals::init_display();
+ extapp_drawTextLarge("No file selected !", 0, 20 * 1, 0x0000, 0xFFFF, false);
+ extapp_drawTextLarge("Press any key to exit", 0, 20 * 2, 0x0000, 0xFFFF, false);
+ Peripherals::waitForKeyPressed();
+ Peripherals::waitForKeyReleased();
+ return;
+ }
+
+ // Show the selected file name
+ extapp_drawTextLarge("Copying :", 0, 20 * 1, 0x0000, 0xFFFF, false);
+ // If file is a Python file, we use a "hack" to add the autoimportation bit
+ // to Python files
+
+ extapp_drawTextLarge(filename, 0, 20 * 2, 0x0000, 0xFFFF, false);
+
+
+ // Initialize the file len variable that will be written by the file read function
+ size_t file_len = 0;
+ // Read the file into filecontent variable
+ const char * filecontent = extapp_fileRead(filename, &file_len, EXTAPP_FLASH_FILE_SYSTEM);
+
+ const char * extension = strrchr(filename, '.');
+ bool success = false;
+ if (strcmp(extension, "py") != 0) {
+ success = extapp_fileWrite(filename, filecontent - 1, file_len + 1, EXTAPP_RAM_FILE_SYSTEM);
+ if (success) {
+ // Here, we edit the first byte to \0
+ char * ramfilecontent = (char *)extapp_fileRead(filename, &file_len, EXTAPP_FLASH_FILE_SYSTEM);
+ ramfilecontent[0] = '\0';
+ }
+ } else {
+ success = extapp_fileWrite(filename, filecontent, file_len, EXTAPP_RAM_FILE_SYSTEM);
+ }
+
+ // Write the file
+ if (!success) {
+ Peripherals::init_display();
+ extapp_drawTextLarge("Error when copying file !", 0, 20 * 1, 0x0000, 0xFFFF, false);
+ extapp_drawTextLarge("Press any key to exit", 0, 20 * 2, 0x0000, 0xFFFF, false);
+ Peripherals::waitForKeyPressed();
+ Peripherals::waitForKeyReleased();
+ return;
+ }
+ extapp_drawTextLarge("File copied successfully !", 0, 20 * 5, 0x0000, 0xFFFF, false);
+
+ extapp_drawTextLarge("Press any key to exit", 0, 20 * 6, 0x0000, 0xFFFF, false);
+ // Wait for a key to be pressed before exiting the application
+ Peripherals::waitForKeyPressed();
+ Peripherals::waitForKeyReleased();
+}
diff --git a/apps/Flash2Ram/peripherals.cpp b/apps/Flash2Ram/peripherals.cpp
new file mode 100644
index 000000000..84a93e702
--- /dev/null
+++ b/apps/Flash2Ram/peripherals.cpp
@@ -0,0 +1,50 @@
+#include "inc/peripherals.h"
+#include "extapp_api.h"
+#include
+
+namespace Peripherals {
+
+/**
+ * init_display: clear the screen
+ */
+void init_display() {
+ // Draw a rectangle to fill all the screen
+ extapp_pushRectUniform(0, 0, 320, 240, 0xFFFF);
+}
+
+/**
+ * waitForKeyPressed: wait for a key to be pressed
+ */
+void waitForKeyPressed() {
+ // Scan the keyboard until we get a pressed key
+ while (!extapp_scanKeyboard()) {
+ // Sleep 10 milliseconds
+ extapp_msleep(10);
+ }
+}
+
+/**
+ * waitForKeyReleased: wait for no keys pressed
+ */
+void waitForKeyReleased() {
+ // Scan the keyboard until we get no keys pressed
+ while (extapp_scanKeyboard()) {
+ extapp_msleep(10);
+ }
+}
+
+/**
+ * waitForKeyReleasedTimeout: wait for no keys pressed, but with a timeout
+ * @param timeout int
+ */
+void waitForKeyReleasedTimeout(int timeout) {
+ // Scan the keyboard until we get no keys pressed, but exit if the timeout reached
+ while (extapp_scanKeyboard() && timeout > 0) {
+ // Sleep 10 milliseconds
+ extapp_msleep(10);
+ // Decrease the timeout of 10 milliseconds
+ timeout -= 10;
+ }
+}
+
+} // namespace Peripherals
\ No newline at end of file
diff --git a/apps/Flash2Ram/selector.cpp b/apps/Flash2Ram/selector.cpp
new file mode 100644
index 000000000..df06b2173
--- /dev/null
+++ b/apps/Flash2Ram/selector.cpp
@@ -0,0 +1,140 @@
+#include "inc/selector.h"
+#include "inc/peripherals.h"
+#include
+#include
+
+#define FILENAME_LENGTH_MAX 512
+
+
+namespace Selector {
+
+/**
+ * drawfileList: draw the file list
+ * @param filenames char **, the file list
+ * @param nb int, the number of files in the list
+ * @param selected_file int, the selected file to highlight
+ */
+static void drawfileList(char ** filenames, int nb, int selected_file) {
+ // Initialize the name buffer
+ char name_buffer[FILENAME_LENGTH_MAX];
+ // Iterate through the file list
+ for (int i = 0; i < nb; i++) {
+ // Copy the filename into the buffer
+ strncpy(name_buffer, filenames[i], FILENAME_LENGTH_MAX);
+ // Force the string to terminate with \0 because the filename can be longer than the length of the buffer
+ name_buffer[26] = '\0';
+ // Draw the filename, highlighted if selected
+ extapp_drawTextLarge(name_buffer, 0, (i + 1) * 20, selected_file == i ? SELECTOR_COLOR_FG_SELECT : SELECTOR_COLOR_FG, SELECTOR_COLOR_BG, false);
+ // TODO: I don't understand it
+ strncpy(name_buffer, filenames[i], FILENAME_LENGTH_MAX);
+ }
+}
+
+static char ** remove(char ** first, char ** last) {
+ char ** result = first;
+ while (first != last) {
+ if (!(*first == NULL)) {
+ *result = *first;
+ ++result;
+ }
+ ++first;
+ }
+ return result;
+}
+
+/**
+ * select_file: display a file list to let the user chose a file
+ * @param extension_to_match const char *, use an empty string to match any file extension
+ * @param max_files int, the maximum number of files to display
+ * @return const char *, the name of the selected file, or NULL if no file is selected
+ */
+const char * select_file(const char * extension_to_match, int max_files) {
+ // The file list
+ char * filenames[max_files];
+ // The selected file index in the order of the file list
+ int selected_file = 0;
+
+ // Wait for the last key to be released
+ Peripherals::waitForKeyReleased();
+
+ // Clear the display
+ extapp_pushRectUniform(0, 0, LCD_WIDTH, LCD_HEIGHT, SELECTOR_COLOR_BG);
+ // Draw title bar
+ extapp_drawTextLarge(" Select a file ", 0, 0, SELECTOR_COLOR_HEAD_FG, SELECTOR_COLOR_HEAD_BG, false);
+
+ // Get the list of files from the flash memory
+ int nb = extapp_fileListWithExtension((const char **)filenames, max_files, "", EXTAPP_FLASH_FILE_SYSTEM);
+
+ // The extension of the file
+ char * extension;
+
+ // If the extension to match isn't empty, filter the file list
+ // Checking without strcomp, because it's also a string littery when it is empty
+ if (extension_to_match[0] != '\0') {
+ // Iterate through the file list
+ for (int i = 0; i < nb; i++) {
+ // Get the file extension by splitting his name by a dot
+ extension = strrchr(filenames[i], '.');
+
+ // Get if the file's extension doesn't match the requested extension
+ if (strcmp(extension, extension_to_match) != 0) {
+ // If the extension doesn't match, delete the file from the list
+ filenames[i] = NULL;
+ }
+ }
+ // Update the number of files
+ nb = remove(filenames, filenames + nb) - filenames;
+ }
+
+ // If no files match, draw a no file found message
+ if (nb == 0) {
+ // Draw the text
+ extapp_drawTextLarge(" No file found ", 0, 120, SELECTOR_COLOR_FG, SELECTOR_COLOR_BG, false);
+ // Sleep for 10 milliseconds
+ extapp_msleep(10);
+ // Wait for a key to be pressed
+ Peripherals::waitForKeyPressed();
+ // Return nothing
+ return NULL;
+ } else {
+ // Draw the file list
+ drawfileList(filenames, nb, selected_file);
+ // Infinite loop
+ for (;;) {
+ // Sleep for 10 milliseconds
+ extapp_msleep(10);
+ // Scan the keyboard
+ uint64_t scancode = extapp_scanKeyboard();
+ // If the down arrow is pressed, select the next file
+ if (scancode & SCANCODE_Down) {
+ // Select the next file, and go to the first file if the file is out of range
+ selected_file = (selected_file + 1) % nb;
+ // Redraw the file list
+ drawfileList(filenames, nb, selected_file);
+ // Wait for the key to be released, or 200 milliseconds if the key sill pressed
+ Peripherals::waitForKeyReleasedTimeout(200);
+ } else if (scancode & SCANCODE_Up) {
+ // Select the previous file
+ selected_file = (selected_file - 1) % nb;
+ // If the file is out of range, select the last file
+ if (selected_file < 0) {
+ selected_file = nb + selected_file;
+ }
+ // Redraw the file list
+ drawfileList(filenames, nb, selected_file);
+ // Wait for the key to be released, or 200 milliseconds if the key sill pressed
+ Peripherals::waitForKeyReleasedTimeout(200);
+ } else if (scancode & (SCANCODE_OK | SCANCODE_EXE)) {
+ // If OK or EXE is pressed, exit the loop
+ break;
+ } else if (scancode & SCANCODE_Back) {
+ // If back key is pressed, exit the menu and return nothing
+ return NULL;
+ }
+ }
+ // Redraw the selected file
+ return filenames[selected_file];
+ }
+}
+
+} // namespace Selector
\ No newline at end of file
diff --git a/apps/Flash2Ram/sources.mak b/apps/Flash2Ram/sources.mak
new file mode 100644
index 000000000..45d7e6ad2
--- /dev/null
+++ b/apps/Flash2Ram/sources.mak
@@ -0,0 +1,5 @@
+app_external_src += $(addprefix $(EXTAPP_PATH)/,\
+ main.cpp \
+ peripherals.cpp \
+ selector.cpp \
+)
diff --git a/apps/apps.js b/apps/apps.js
index ac4751660..c7f714d83 100644
--- a/apps/apps.js
+++ b/apps/apps.js
@@ -11,5 +11,6 @@ angular.module('nwas').service('apps', function() {
{ name: "BadApple", description: {en: "Bad Apple demo", fr: "Démo Bad Apple"} },
{ name: "UnitCircle", description: {en: "Unit circle", fr: "Cercle trigonométrique"} },
{ name: "CHIP-8", description: {en: "CHIP-8 interpreter", fr: "Interpréteur CHIP-8"} },
+ { name: "Flash2Ram", description: {en: "Copy files from flash to RAM", fr: "Copiez des fichiers de la flash vers la RAM"} },
];
});