XR4-display / src / main.cpp
main.cpp
Raw
#include "XRConfig.h"
#include "XRDisplay.h"
#include "XRSequenceInstrumentTrack.h"
#include "XRSequenceInstrumentTrackProgram.h"

#include <Arduino.h>

EXTMEM ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
EXTMEM elapsedMillis runtime;

DMAMEM DynamicJsonDocument doc(10000);

std::vector<SequenceInstrumentTrack *> unmarshalInstrumentTracks();
SequenceInstrumentTrack * unmarshalInstrumentTrack();
SequenceInstrumentTrackProgram * unmarshalInstrumentTrackProgram();

void handleDisplayState(int displayState);

void setup() {
    Serial.begin(BAUD_RATE);
    Serial5.begin(250000);

    delay(2000);

    Serial.println("Display intro...");
    Display::init(tft);

    // set backlight
    pinMode(7, OUTPUT);
    analogWrite(7, 30);

    Display::drawIntroScreen(tft);
}

void loop() {
    if (Serial5.available()) {
        Serial.println("command received");

        DeserializationError err = deserializeJson(doc, Serial5);

        if (err == DeserializationError::Ok) {
            Serial.println("command OK");

            int drawDisplayState = doc["drawDisplayState"].as<int>();

            Serial.print("JSON doc memory usage: ");
            Serial.println(doc.memoryUsage());

            handleDisplayState(drawDisplayState);

            doc.clear();
        } else {
            // Print error to the "debug" serial port
            Serial.print("deserializeJson() returned ");
            Serial.println(err.c_str());

            // Flush all bytes in the "TX" serial port buffer
            while (Serial5.available() > 0) {
                Serial5.read();
            }
        }
    }
}

void handleDisplayState (int displayState)
{
    Serial.print("displayState: ");
    Serial.println(displayState);

    switch (displayState) {
        case DISPLAY_STATE_MAIN:
        case DISPLAY_STATE_MAIN_REFRESH_PRG:
        case DISPLAY_STATE_MAIN_REFRESH_PRG_CURSOR:
        case DISPLAY_STATE_MAIN_REFRESH_PRG_CURSOR_RUNNING:
        {
            std::vector<SequenceInstrumentTrack *> trks = unmarshalInstrumentTracks();

            Display::drawMainScreen(
                tft,
                doc["currInstrument"].as<unsigned int>(),
                trks,
                (displayState == DISPLAY_STATE_MAIN_REFRESH_PRG ||
                 displayState == DISPLAY_STATE_MAIN_REFRESH_PRG_CURSOR ||
                 displayState == DISPLAY_STATE_MAIN_REFRESH_PRG_CURSOR_RUNNING),
                doc["tempo"].as<uint16_t>(),
                doc["selProgram"].as<unsigned int>(),
                (displayState == DISPLAY_STATE_MAIN_REFRESH_PRG_CURSOR),
                doc["isSequencerRunning"].as<bool>()
            );

            for (auto trk : trks) {
                delete trk;
            }

            break;
        }
        case DISPLAY_STATE_INSTRUMENT_CONFIG_OPEN:
        {
            SequenceInstrumentTrack *trk = unmarshalInstrumentTrack();

            Display::drawInstrumentConfigWindow(
                tft,
                trk,
                doc["currConfigPropIdx"].as<unsigned int>()
            );

            delete trk;

            break;
        }
        case DISPLAY_STATE_INSTRUMENT_CONFIG_PAGE_RIGHT:
        {
            SequenceInstrumentTrack *trk = unmarshalInstrumentTrack();

            Display::drawInstrumentConfigPropWindow(
                tft,
                trk,
                doc["currConfigPropIdx"].as<unsigned int>(),
                doc["currConfigPropSettingIdx"].as<unsigned int>()
            );

            delete trk;

            break;
        }
        case DISPLAY_STATE_PROGRAM_CONFIG_OPEN:
        {
            SequenceInstrumentTrackProgram *prg = unmarshalInstrumentTrackProgram();

            Display::drawProgramConfigWindow(
                tft,
                prg,
                doc["currInstrument"].as<unsigned int>(),
                doc["currCursoredProgramIdx"].as<unsigned int>(),
                doc["currPrgConfigPropIdx"].as<unsigned int>()
            );

            delete prg;

            break;
        }
        case DISPLAY_STATE_PROGRAM_CONFIG_PAGE_RIGHT:
        {
            SequenceInstrumentTrackProgram *prg = unmarshalInstrumentTrackProgram();

            Display::drawProgramConfigPropWindow(
                tft,
                prg,
                doc["currPrgConfigPropIdx"].as<unsigned int>(),
                doc["currPrgConfigPropSettingIdx"].as<unsigned int>()
            );

            delete prg;

            break;
        }
        case DISPLAY_STATE_TEMPO_SCREEN:
            Display::drawTempoScreen(tft, doc["tempo"].as<uint16_t>());
            break;
        case DISPLAY_STATE_WARN:
            Display::drawWarn(tft, doc["warnMsg"].as<const char*>());
            break;
        default:
            break;
    }
}

std::vector<SequenceInstrumentTrack *> unmarshalInstrumentTracks()
{
    std::vector<SequenceInstrumentTrack *> instrumentTracks;

    if (!doc["instrumentTracks"].isNull()) {
        JsonArray instrumentTracksArr = doc["instrumentTracks"].as<JsonArray>();

        instrumentTracks.reserve(INSTRUMENT_TRACK_LIMIT);

        int idx = 1;
        for (unsigned int i = 0; i < instrumentTracksArr.size(); ++i) {
            std::vector<SequenceInstrumentTrackProgram *> instrumentTrackPrograms;

            JsonObject instrumentTrackObj = instrumentTracksArr.getElement(i);

            auto *instrumentTrack = new SequenceInstrumentTrack (idx);

            instrumentTrack->deviceActive = instrumentTrackObj["deviceActive"];
            instrumentTrack->stopped = instrumentTrackObj["stopped"];
            instrumentTrack->barsElapsed = instrumentTrackObj["barsElapsed"];
            instrumentTrack->device = instrumentTrackObj["device"];
            instrumentTrack->loop = instrumentTrackObj["loop"];

            instrumentTrack->currentTrackProgramNum = instrumentTrackObj["currentTrackProgramNum"];
            instrumentTrack->currentTrackProgramIndex = instrumentTrackObj["currentTrackProgramIndex"];

            if (!instrumentTrackObj["instrumentTrackPrograms"].isNull()) {
                JsonArray instrumentTrackProgramsArr = instrumentTrackObj["instrumentTrackPrograms"];

                instrumentTrackPrograms.reserve(instrumentTrackProgramsArr.size());

                int prIdx = 1;
                for (int j = 0; j < instrumentTrackProgramsArr.size(); ++j) {
                    JsonObject instrumentTrackProgramObj = instrumentTrackProgramsArr.getElement(j);

                    auto *instrumentTrackProgram = new SequenceInstrumentTrackProgram (idx, prIdx);

                    instrumentTrackProgram->trackIndex = instrumentTrackProgramObj["trackIndex"];
                    instrumentTrackProgram->pIndex = instrumentTrackProgramObj["pIndex"];

                    instrumentTrackProgram->bankNumber = instrumentTrackProgramObj["bankNumber"];
                    instrumentTrackProgram->programNumber = instrumentTrackProgramObj["programNumber"];
                    instrumentTrackProgram->barLength = instrumentTrackProgramObj["barLength"];
                    instrumentTrackProgram->state = instrumentTrackProgramObj["state"];
                    //instrumentTrackProgram->lastStep = instrumentTrackProgramObj["lastStep"];

                    instrumentTrackPrograms.push_back(instrumentTrackProgram);
                    ++prIdx;
                }
            }

            instrumentTrack->instrumentTrackPrograms = instrumentTrackPrograms;

            // TODO: remove this, used for debugging
//            Serial.print("instrumentTrackPrograms size: ");
//            Serial.println(instrumentTrack->instrumentTrackPrograms.size());

            instrumentTracks.push_back(instrumentTrack);
            ++idx;
        }

        // TODO: remove this, used for debugging
//        Serial.print("instrumentTracksArr size (get element count): ");
//        Serial.println(instrumentTracksArr.size());
    }

    return instrumentTracks;
}

SequenceInstrumentTrack* unmarshalInstrumentTrack()
{
    auto instrumentTrack = new SequenceInstrumentTrack(doc["instrumentTrack"]["tIndex"].as<unsigned int>());

//    Serial.print("instrumentTrack->tIndex: ");
//    Serial.println(instrumentTrack->tIndex);

    std::vector<SequenceInstrumentTrackProgram *> instrumentTrackPrograms;

    if (!doc["instrumentTrack"].isNull()) {
        JsonObject instrumentTrackObj = doc["instrumentTrack"];

        instrumentTrack->deviceActive = instrumentTrackObj["deviceActive"];
        instrumentTrack->trackActive = instrumentTrackObj["trackActive"];
        instrumentTrack->stopped = instrumentTrackObj["stopped"];

        instrumentTrack->barsElapsed = instrumentTrackObj["barsElapsed"];
        instrumentTrack->currLastStep = instrumentTrackObj["currLastStep"];

        instrumentTrack->device = instrumentTrackObj["device"];
        instrumentTrack->channel = instrumentTrackObj["channel"];
        instrumentTrack->cue = instrumentTrackObj["cue"];
        instrumentTrack->loop = instrumentTrackObj["loop"];
        instrumentTrack->force = instrumentTrackObj["force"];

        instrumentTrack->currentTrackProgramNum = instrumentTrackObj["currentTrackProgramNum"];
        instrumentTrack->currentTrackProgramIndex = instrumentTrackObj["currentTrackProgramIndex"];
        instrumentTrack->currentTrackStepIndex = instrumentTrackObj["currentTrackStepIndex"];
        instrumentTrack->currentTrackStepPreciseIndex = instrumentTrackObj["currentTrackStepPreciseIndex"];

        if (!instrumentTrackObj["instrumentTrackPrograms"].isNull()) {
            JsonArray instrumentTrackProgramsArr = instrumentTrackObj["instrumentTrackPrograms"];

            instrumentTrackPrograms.reserve(instrumentTrackProgramsArr.size());

            int prIdx = 1;
            for (int j = 0; j < instrumentTrackProgramsArr.size(); ++j) {
                JsonObject instrumentTrackProgramObj = instrumentTrackProgramsArr.getElement(j);

                auto *instrumentTrackProgram = new SequenceInstrumentTrackProgram(
                    instrumentTrackObj["tIndex"],
                    prIdx
                );

                instrumentTrackProgram->trackIndex = instrumentTrackProgramObj["trackIndex"];
                instrumentTrackProgram->pIndex = instrumentTrackProgramObj["pIndex"];

                instrumentTrackProgram->bankNumber = instrumentTrackProgramObj["bankNumber"];
                instrumentTrackProgram->programNumber = instrumentTrackProgramObj["programNumber"];
                instrumentTrackProgram->barLength = instrumentTrackProgramObj["barLength"];
                instrumentTrackProgram->state = instrumentTrackProgramObj["state"];
                instrumentTrackProgram->lastStep = instrumentTrackProgramObj["lastStep"];

                instrumentTrackPrograms.push_back(instrumentTrackProgram);
                ++prIdx;
            }

            // TODO: remove this, used for debugging
//            Serial.print("instrumentTrackProgramsArr size (get element count): ");
//            Serial.println(instrumentTrackProgramsArr.size());
        }
    }

    return instrumentTrack;
}

SequenceInstrumentTrackProgram* unmarshalInstrumentTrackProgram()
{
    auto instrumentTrackProgram = new SequenceInstrumentTrackProgram(
        doc["trackIdx"].as<unsigned int>(),
        doc["prgIdx"].as<unsigned int>()
    );

    if (!doc["instrumentTrackProgram"].isNull()) {
        JsonObject instrumentTrackProgramObj = doc["instrumentTrackProgram"];

        instrumentTrackProgram->trackIndex = instrumentTrackProgramObj["trackIndex"];
        instrumentTrackProgram->pIndex = instrumentTrackProgramObj["pIndex"];

        instrumentTrackProgram->bankNumber = instrumentTrackProgramObj["bankNumber"];
        instrumentTrackProgram->programNumber = instrumentTrackProgramObj["programNumber"];
        instrumentTrackProgram->barLength = instrumentTrackProgramObj["barLength"];
        instrumentTrackProgram->state = instrumentTrackProgramObj["state"];
        instrumentTrackProgram->lastStep = instrumentTrackProgramObj["lastStep"];
    }

    return instrumentTrackProgram;
}