Skip to content

Commit

Permalink
VGA Shell example for Selenium board.
Browse files Browse the repository at this point in the history
  • Loading branch information
nthnn committed May 13, 2024
1 parent 0501015 commit a19a0cb
Showing 1 changed file with 196 additions and 0 deletions.
196 changes: 196 additions & 0 deletions examples/vga_shell/vga_shell.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* This file is part of the Rishka distribution (https://github.com/rishka-esp32/rishka).
* Copyright (c) 2024 Nathanne Isip.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* This example initializes a VGA display using FabGL library, loads a font for a terminal,
* initializes an SD card using SPI, initializes a Rishka virtual machine, loads the specified
* file into the Rishka VM, executes it, and then waits for the next input.
*/

#include <fabgl.h>
#include <rishka.h>
#include <SD.h>
#include <SPI.h>

#define SD_CS 13 // SD card chip select pin
#define SD_SCK 14 // SD card SPI clock pin
#define SD_MOSI 12 // SD card SPI MOSI pin
#define SD_MISO 35 // SD card SPI MISO pin

// TFT display controller, PS/2 keyboard controller,
// and Terminal instance
fabgl::VGAController DisplayController;
fabgl::PS2Controller PS2Controller;
fabgl::Terminal Terminal;

// SPI instance for SD card
SPIClass sdSpi(HSPI);

// Rishka virtual machine instance
RishkaVM* vm;

// This function utilizes a LineEditor instance to read a line
// from the terminal input. It then returns the read line as a String.
static inline String readLine() {
fabgl::LineEditor line(&Terminal);
line.edit();

return String(line.get());
}

// This function splits a given input string into tokens based on space characters.
// It also handles quotes to allow space characters within quoted strings.
void splitString(const String& input, char** tokens, int maxTokens, int &count) {
int tokenCount = 0, tokenStart = 0;
bool inQuotes = false;

// Iterate over each character in the input string
for(int i = 0; i < input.length(); i++) {
// Check if the current character is a quotation mark
if(input[i] == '"')
// Toggle the inQuotes flag to handle quoted strings
inQuotes = !inQuotes;
else if(input[i] == ' ' && !inQuotes) {
// If the current character is a space and not inside quotes,
// extract the token from the input string
if(tokenCount < maxTokens) {
// Extract the substring between tokenStart and i
// and copy it into the tokens array
input.substring(tokenStart, i)
.toCharArray(tokens[tokenCount], i - tokenStart + 1);

// Null-terminate the token string
tokens[tokenCount++][i - tokenStart] = '\0';
tokenStart = i + 1;
count++;
}
else break; // Break if maximum token count reached
}
}

// Handle the case where there are remaining characters after the last space
if(tokenCount < maxTokens && tokenStart < input.length()) {
// Extract the substring starting from tokenStart to the end of the input string
// and copy it into the tokens array
input.substring(tokenStart).toCharArray(tokens[tokenCount], input.length() - tokenStart + 1);
tokens[tokenCount++][input.length() - tokenStart] = '\0';
count++;
}
}

void setup() {
Serial.begin(115200);
PS2Controller.begin(PS2Preset::KeyboardPort0);

// Initialize VGA display
DisplayController.begin();
DisplayController.setResolution(VGA_640x240_60Hz);

// Initialize terminal
Terminal.begin(&DisplayController);
Terminal.loadFont(&fabgl::FONT_8x14);
Terminal.setBackgroundColor(Color::Black);
Terminal.setForegroundColor(Color::White);
Terminal.connectLocally();
Terminal.clear();
Terminal.enableCursor(true);

// Initialize SD card
sdSpi.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
if(!SD.begin(SD_CS, sdSpi, 80000000)) {
Terminal.println("Cannot \e[94mInitialize\e[97m SD card.");

do sdSpi.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
while(!SD.begin(SD_CS, sdSpi, 80000000));

Terminal.clear();
}

// Initialize PSRAM
if(!psramInit()) {
Terminal.println("\e[94mCannot\e[97m initialize PSRAM.");
while(true);
}

// Initialize the Rishka VM instance.
vm = new RishkaVM();
vm->initialize(&Terminal);

// Virtual key listener to halt program
Terminal.onVirtualKeyItem = [&](VirtualKeyItem * vkItem) {
if(vkItem->CTRL && vkItem->vk == VirtualKey::VK_c && vm->isRunning()) {
// Stop the VM if CTRL+C was pressed
vm->stopVM();
vm->reset();

Terminal.println("^C");
}
};

// Print prompt
Terminal.print("\e[32m[\e[97m" + vm->getWorkingDirectory() + "\e[97m\e[32m]~\e[97m ");
}

void loop() {
// Read input from PS/2 keyboard
String input = readLine();

// Skip if input is empty
if(input == "") {
// Print prompt
Terminal.print(String("\e[32m[\e[97m") +
vm->getWorkingDirectory() + "\e[97m\e[32m]~\e[97m ");
return;
}

char* tokens[10];
int count = 0;

// Split input string as argument tokens
for(int i = 0; i < 10; i++)
tokens[i] = (char*) malloc(50 * sizeof(char));
splitString(input, tokens, 10, count);

// Attempt to load specified file into Rishka virtual machine
if(!vm->loadFile(tokens[0])) {
char message[50];

// If loading file fails, print error message and return
sprintf(message, "Failed to \e[94mload\e[97m specified file: %s", tokens[0]);
vm->panic(message);

// Print prompt
Terminal.print(String("\e[32m[\e[97m") +
vm->getWorkingDirectory() + "\e[97m\e[32m]~\e[97m ");
vm->reset();

return;
}

// Run loaded program on Rishka virtual machine
vm->run(count, tokens);
// Reset Rishka virtual machine for next execution
vm->reset();

// Free all tokens in memory
for(int i = 0; i < 10; i++)
free(tokens[i]);

// Print prompt for next input
Terminal.print(String("\e[32m[\e[97m") +
vm->getWorkingDirectory() + "\e[97m\e[32m]~\e[97m ");
}

0 comments on commit a19a0cb

Please sign in to comment.