/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


//
// Include common source code for RawMemoryCard test application
//
#define ECXX_TEST_INCLUDED_FROM_SLOT_FS_COMMON_H
#include "../CommonCode/RawMemoryCard_Common.h"


//
// Instantiate a slot-based file system
//
static eCxx::SlotFS slotFS;


//
// Helper functions
//
template <typename UART_T>
static inline void printPreTextSlotUserID(UART_T& uart, eCxx::PGMCharPointer preText, eCxx::PGMCharPointer userID)
{
    uart.writeString( preText                           );
    uart.writeString( PGM_STR(" slot with user ID \" ") );
    uart.writeString( userID                            );
    uart.writeString( PGM_STR("\" ... "               ) );
}


template <typename UART_T>
static inline void printResultFindSlot(UART_T& uart, eCxx::uint16_t slotNumber, bool haltIfNotFound)
{
    // Yield first
    App::yield();

    // Found
    if(slotNumber != eCxx::SlotFS::InvalidSlotNumber) {
        uart.writeString   ( PGM_STR("FOUND at #") );
        uart.writeDecString( slotNumber            );
        uart.write         ('\n'                   );
        return;
    }

    // Not found
    uart.writeStringln( PGM_STR("NOT FOUND") );

    // Halt as needed
    if(haltIfNotFound) {
        uart.writeStringln( PGM_STR("Halting here!\n") );
        App::halt();
    }
}


static void eCxx_user_init_slotfsInitAndTest(bool stopAfterMountTest = false)
{
    // Initialize UART
    auto& u = App::uart();
    u.begin(115200);

    // Initialize the slot-based file system
    u.writeString( PGM_STR("Initializing SPI, memory card, and SlotFS ... ") );
    auto rc = slotFS.begin();
    printRMCResultCodeString(u, rc);
    u.write('\n');

    //
    // ===== Format and mount tests =====
    //

    // Try to mount and format as needed
    u.writeString( PGM_STR("Mounting memory card ... ") );
    bool br = slotFS.mount();
    printResultBool(u, br, false);
    if(!br) {
        // Format
        u.writeString( PGM_STR("Formatting memory card ... [") );
        br = slotFS.format(
            PGM_STR("=== Formatted by eCxx SlotFS Test Application ==="),
            [](eCxx::uint16_t p) {
                     if(p == 0x0000) App::uart().write('0');
                else if(p == 0xFFFF) App::uart().write('#');
                else                 App::uart().write('-');
            }
        );
        u.write(']');
        u.write(' ');
        printResultBool(u, br, true);
#if 1
        // Peek the result
        u.writeString( PGM_STR("Read one block #0 ... ") );
        eCxx::uint8_t buff[eCxx::SlotFS::SectorSize];
        rc = slotFS.rmc().readOneBlock( 0, buff, sizeof(buff) );
        printRMCResultCodeString(u, rc);
        printHexSeqStringln128x4(u, buff);
#endif
        // Try mount again
        u.writeString( PGM_STR("Mounting memory card ... ") );
        br = slotFS.mount();
        printResultBool(u, br, true);
    }

    // Print some information about the file system
    u.writeString( PGM_STR("    Sector count : ") ); u.writeDecStringln( slotFS.getSectorCount() );
    u.writeString( PGM_STR("    Slot   size  : ") ); u.writeDecStringln( slotFS.getSlotSize   () );
    u.writeString( PGM_STR("    Slot   count : ") ); u.writeDecStringln( slotFS.getSlotCount  () );
    u.writeString( PGM_STR("    User   desc  : ") );
    App::yield();
    {
        char buff[eCxx::SlotFS::FSUserDescLen];
        if( slotFS.getUserDesc(buff) ) {
            u.write('"');
            for(eCxx::uint16_t i = 0; i < sizeof(buff); ++i) {
                if(!buff[i]) break;
                u.write(buff[i]);
            }
            u.write('"');
        }
        else {
            u.writeString( PGM_STR("<<< ERROR >>>") );
        }
    }
    u.write('\n');
    u.write('\n');
    App::yield();

    //
    // ===== Simple tests =====
    //
    u.writeStringln( PGM_STR("================================================================================\n" ) );

    if(stopAfterMountTest) return;

    // ----- Test 1st file -----

    eCxx::PGMCharPointer myFile1 = PGM_STR("MyFile01");
    eCxx::PGMCharPointer myDesc1 = PGM_STR("This is my 1st file");

    // Open and write
    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile1);
    eCxx::uint16_t slotNumber = slotFS.findFirstSlotNumberByUserID(myFile1);
    printResultFindSlot(u, slotNumber, false);
    u.write('\n');
    App::yield();

    eCxx::SlotFS::SlotHandle handle;
    if(slotNumber == eCxx::SlotFS::InvalidSlotNumber) {
        printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile1);
        handle = slotFS.slotWriteNew(myFile1, myDesc1);
    }
    else {
        printPreTextSlotUserID(u, PGM_STR("Open for writing to existing"), myFile1);
        handle = slotFS.slotWriteOpenTruncate(slotNumber, 0);
    }
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile1);
    eCxx::uint8_t buff[eCxx::SlotFS::SectorSize] = { 'A', 'b', 'c' };
    br = ( slotFS.slotWritePut(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile1);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    // Open and read
    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile1);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile1);
    printResultFindSlot(u, slotNumber, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Open for reading from"), myFile1);
    handle = slotFS.slotReadOpen(slotNumber);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile1);
    eCxx::uint32_t num = slotFS.slotReadRemainingBytesAvailable(handle);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Reading bytes from"), myFile1);
    memset( buff, 0, sizeof(buff) );
    br = ( slotFS.slotReadGet(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    u.writeString( PGM_STR("    " ) );
    u.writeChrSeqString(buff, 3, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile1);
    num = slotFS.slotReadRemainingBytesAvailable(handle);
    u.writeDecStringln(num);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile1);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    // Delete
    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile1);
    br = slotFS.freeSlot(slotNumber);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();


    // ----- Test 1st and 2nd files -----

    eCxx::PGMCharPointer myFile2 = PGM_STR("MyFile02");
    eCxx::PGMCharPointer myDesc2 = PGM_STR("This is my 2nd file");

    // Open and write
    printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile1);
    handle = slotFS.slotWriteNew(myFile1, myDesc1);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile1);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile2);
    handle = slotFS.slotWriteNew(myFile2, myDesc2);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile2);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    // List
    u.writeString( PGM_STR("Begin listing for occupied slots ... ") );
    br = slotFS.listOccupiedSlotNumberBegin();
    printResultBool(u, br, true);
    for(;;) {
        // Get and check the slot number
        slotNumber = slotFS.listOccupiedSlotNumberGet();
        if(slotNumber == eCxx::SlotFS::InvalidSlotNumber) break;
        // Get and print the user ID and description
        char userID  [eCxx::SlotFS::SDUserIDLen  ];
        char userDesc[eCxx::SlotFS::SDUserDescLen];
        slotFS.getSlotUserID  (slotNumber, userID  );
        slotFS.getSlotUserDesc(slotNumber, userDesc);
        u.writeString  ( PGM_STR("    \"" )         );
        u.writeString  ( userID,   sizeof(userID  ) );
        u.writeString  ( PGM_STR("\" : \"" )        );
        u.writeString  ( userDesc, sizeof(userDesc) );
        u.write        ( '"'                        );
        u.write        ( '\n'                       );
        App::yield();
    }
    slotFS.listOccupiedSlotNumberEnd();
    u.write('\n');
    App::yield();

    // Delete
    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile1);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile1);
    printResultFindSlot(u, slotNumber, true);
    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile1);
    br = slotFS.freeSlot(slotNumber);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile2);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile2);
    printResultFindSlot(u, slotNumber, true);
    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile2);
    br = slotFS.freeSlot(slotNumber);
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile2);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile2);
    printResultFindSlot(u, slotNumber, false);
    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile2);
    br = slotFS.freeSlot(slotNumber);
    printResultBool(u, br, false);
    u.write('\n');
    App::yield();

    // Unmount
    u.writeString( PGM_STR("Unmounting memory card ... ") );
    slotFS.unmount();
    u.writeStringln( PGM_STR("DONE\n") );
    App::yield();

    //
    // ===== Multiple-file-open tests =====
    //
    u.writeStringln( PGM_STR("================================================================================\n" ) );

    // Mount again
    u.writeString( PGM_STR("Mounting memory card ... ") );
    br = slotFS.mount();
    printResultBool(u, br, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile1);
    eCxx::SlotFS::SlotHandle handle1 = slotFS.slotWriteNew(myFile1, myDesc1);
    printResultBool(u, !!handle, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile2);
    eCxx::SlotFS::SlotHandle handle2 = slotFS.slotWriteNew(myFile2, myDesc2);
    printResultBool(u, !!handle, true);
    App::yield();

    u.write('\n');

    for(eCxx::uint8_t i = 1; i <= 7; ++i) {
        printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile1);
        memset(buff, 100 + i, 128);
        br = ( slotFS.slotWritePut(handle1, buff, 128) == 128 );
        printResultBool(u, br, true);
        App::yield();
        printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile2);
        memset(buff, 200 + i, 128);
        br = ( slotFS.slotWritePut(handle2, buff, 128) == 128 );
        printResultBool(u, br, true);
        App::yield();
    }

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile1);
    br = slotFS.slotClose(handle1);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile2);
    br = slotFS.slotClose(handle2);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile1);
    eCxx::uint16_t slotNumber1 = slotFS.findFirstSlotNumberByUserID(myFile1);
    printResultFindSlot(u, slotNumber1, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile2);
    eCxx::uint16_t slotNumber2 = slotFS.findFirstSlotNumberByUserID(myFile2);
    printResultFindSlot(u, slotNumber2, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Get data size of"), myFile1);
    num = slotFS.getSlotDataSize(slotNumber1);
    u.writeDecStringln(num);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Get data size of"), myFile2);
    num = slotFS.getSlotDataSize(slotNumber2);
    u.writeDecStringln(num);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Open for writing to existing"), myFile1);
    handle1 = slotFS.slotWriteOpenTruncate(slotNumber1, 0);
    printResultBool(u, !!handle, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Open for reading from"), myFile2);
    handle2 = slotFS.slotReadOpen(slotNumber2);
    printResultBool(u, !!handle, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Available bytes to write to"), myFile1);
    num = slotFS.slotWriteRemainingBytesAvailable(handle1);
    u.writeDecStringln(num);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile1);
    memset(buff, 101, 128);
    br = ( slotFS.slotWritePut(handle1, buff, 128) == 128 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Reading bytes from"), myFile2);
    br = ( slotFS.slotReadGet(handle2, buff, 128) == 128 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile1);
    br = ( slotFS.slotWritePut(handle1, buff, 128) == 128 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to write to"), myFile1);
    num = slotFS.slotWriteRemainingBytesAvailable(handle1);
    u.writeDecStringln(num);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Read seek to #0 in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 0); // (default = eCxx::SlotFS::SeekMode::Beg)
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #101 in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 101); // (default = eCxx::SlotFS::SeekMode::Beg)
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #END in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 0, eCxx::SlotFS::SeekMode::End);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #(END-1) in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 1, eCxx::SlotFS::SeekMode::End);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #(END-2) in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 2, eCxx::SlotFS::SeekMode::End);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #(CUR+1) in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 1, eCxx::SlotFS::SeekMode::Cur);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Read seek to #(CUR+2) in"), myFile2);
    br = slotFS.slotReadSeek(handle2, 2, eCxx::SlotFS::SeekMode::Cur);
    printResultBool(u, br, false);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile2);
    num = slotFS.slotReadRemainingBytesAvailable(handle2);
    u.writeDecStringln(num);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile1);
    br = slotFS.slotClose(handle1);
    printResultBool(u, br, true);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile2);
    br = slotFS.slotClose(handle2);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile1);
    slotNumber1 = slotFS.findFirstSlotNumberByUserID(myFile1);
    printResultFindSlot(u, slotNumber1, false);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile2);
    slotNumber2 = slotFS.findFirstSlotNumberByUserID(myFile2);
    printResultFindSlot(u, slotNumber2, false);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile1);
    br = slotFS.freeSlot(slotNumber1);
    printResultBool(u, br, false);
    App::yield();
    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile2);
    br = slotFS.freeSlot(slotNumber2);
    printResultBool(u, br, false);
    App::yield();

    u.write('\n');

    //
    // ===== Non-trivial write tests =====
    //
    u.writeStringln( PGM_STR("================================================================================\n" ) );

    eCxx::PGMCharPointer myFile3 = PGM_STR("MyFile03");
    eCxx::PGMCharPointer myDesc3 = PGM_STR("This is my 3rd file");

    printPreTextSlotUserID(u, PGM_STR("Open for writing to new"), myFile3);
    handle = slotFS.slotWriteNew(myFile3, myDesc3);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile3);
    buff[0] = 'D';
    buff[1] = 'e';
    buff[2] = 'f';
    br = ( slotFS.slotWritePut(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile3);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile3);
    printResultFindSlot(u, slotNumber, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Open for reading from"), myFile3);
    handle = slotFS.slotReadOpen(slotNumber);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile3);
    num = slotFS.slotReadRemainingBytesAvailable(handle);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Reading bytes from"), myFile3);
    memset( buff, 0, sizeof(buff) );
    br = ( slotFS.slotReadGet(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    u.writeString( PGM_STR("    " ) );
    u.writeChrSeqString(buff, 3, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Open for appending to existing"), myFile3);
    handle = slotFS.slotWriteOpenAppend(slotNumber);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile3);
    buff[0] = '1';
    buff[1] = '2';
    buff[2] = '3';
    br = ( slotFS.slotWritePut(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Open for reading from"), myFile3);
    handle = slotFS.slotReadOpen(slotNumber);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile3);
    num = slotFS.slotReadRemainingBytesAvailable(handle);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Reading bytes from"), myFile3);
    memset( buff, 0, sizeof(buff) );
    br = ( slotFS.slotReadGet(handle, buff, 6) == 6 );
    printResultBool(u, br, true);
    u.writeString( PGM_STR("    " ) );
    u.writeChrSeqString(buff, 6, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Open for writing with truncation to existing"), myFile3);
    handle = slotFS.slotWriteOpenTruncate(slotNumber, 2);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Writing bytes to"), myFile3);
    buff[0] = '5';
    buff[1] = '6';
    buff[2] = '7';
    br = ( slotFS.slotWritePut(handle, buff, 3) == 3 );
    printResultBool(u, br, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Open for reading from"), myFile3);
    handle = slotFS.slotReadOpen(slotNumber);
    printResultBool(u, !!handle, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Available bytes to read from"), myFile3);
    num = slotFS.slotReadRemainingBytesAvailable(handle);
    u.writeDecStringln(num);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Reading bytes from"), myFile3);
    memset( buff, 0, sizeof(buff) );
    br = ( slotFS.slotReadGet(handle, buff, 5) == 5 );
    printResultBool(u, br, true);
    u.writeString( PGM_STR("    " ) );
    u.writeChrSeqString(buff, 5, true);
    u.write('\n');
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Closing"), myFile3);
    br = slotFS.slotClose(handle);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    //
    // ===== Other tests =====
    //
    u.writeStringln( PGM_STR("================================================================================\n" ) );

    printPreTextSlotUserID(u, PGM_STR("Searching for"), myFile3);
    slotNumber = slotFS.findFirstSlotNumberByUserID(myFile3);
    printResultFindSlot(u, slotNumber, true);
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Getting ID and description from"), myFile3);
    u.write('\n');
    char userID  [eCxx::SlotFS::SDUserIDLen  ];
    char userDesc[eCxx::SlotFS::SDUserDescLen];
    slotFS.getSlotUserID  (slotNumber, userID  );
    slotFS.getSlotUserDesc(slotNumber, userDesc);
    u.writeString  ( PGM_STR("    \"" )         );
    u.writeStringln( userID,   sizeof(userID  ) );
    u.writeString  ( PGM_STR("    \"" )         );
    u.writeStringln( userDesc, sizeof(userDesc) );
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Changing ID and description of"), myFile3);
    u.write('\n');
    slotFS.slotChangeUserID  ( slotNumber, PGM_STR("Rename03")                    );
    slotFS.slotChangeUserDesc( slotNumber, PGM_STR("This is my renamed 3rd file") );
    App::yield();

    printPreTextSlotUserID(u, PGM_STR("Getting ID and description from"), myFile3);
    u.write('\n');
    slotFS.getSlotUserID  (slotNumber, userID  );
    slotFS.getSlotUserDesc(slotNumber, userDesc);
    u.writeString  ( PGM_STR("    \"" )         );
    u.writeString  ( userID,   sizeof(userID  ) );
    u.writeString  ( PGM_STR("\"\n    \"" )     );
    u.writeString  ( userDesc, sizeof(userDesc) );
    u.write        ( '"'  );
    u.write        ( '\n' );
    App::yield();

    u.write('\n');

    u.writeStringln( PGM_STR("Getting slot usage ...") );
    u.writeString( PGM_STR("    Empty    slot : ") ); u.writeDecStringln( slotFS.numberOfEmptySlots   () );
    u.writeString( PGM_STR("    Occupied slot : ") ); u.writeDecStringln( slotFS.numberOfOccupiedSlots() );
    App::yield();

    u.write('\n');

    printPreTextSlotUserID(u, PGM_STR("Freeing"), myFile3);
    br = slotFS.freeSlot(slotNumber);
    printResultBool(u, br, true);
    App::yield();

    u.write('\n');

    u.writeStringln( PGM_STR("Getting slot usage ...") );
    u.writeString( PGM_STR("    Empty    slot : ") ); u.writeDecStringln( slotFS.numberOfEmptySlots   () );
    u.writeString( PGM_STR("    Occupied slot : ") ); u.writeDecStringln( slotFS.numberOfOccupiedSlots() );
    App::yield();

    u.write('\n');

    u.writeString( PGM_STR("Unmounting memory card ... ") );
    slotFS.unmount();
    u.writeStringln( PGM_STR("DONE\n") );
    App::yield();

#if 1
    // Format again
    u.writeString( PGM_STR("Formatting memory card again ... ") );
    br = slotFS.format(
        PGM_STR("=== Formatted by eCxx SlotFS Test Application (Again!) ==="),
        nullptr
    );
    printResultBool(u, br, true);
    u.write('\n');
    u.write('\n');
    App::yield();
#endif

    u.writeStringln( PGM_STR("================================================================================" ) );
    u.writeStringln( PGM_STR("================================================================================" ) );
    u.writeStringln( PGM_STR("================================================================================" ) );
    u.write('\n');
    u.write('\n');
}
