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"} }, ]; });