2021-09-19 19:16:41 -04:00
|
|
|
/**
|
|
|
|
* Implementation of the command line interface
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
2021-09-25 17:26:23 -04:00
|
|
|
#include "log.h"
|
2021-09-19 19:16:41 -04:00
|
|
|
#include "types.h"
|
2021-10-05 15:51:53 -04:00
|
|
|
#include "simpleio.h"
|
2021-09-19 19:16:41 -04:00
|
|
|
#include "syscalls.h"
|
2021-10-05 15:51:53 -04:00
|
|
|
#include "sys_general.h"
|
2021-09-19 19:16:41 -04:00
|
|
|
#include "cli/cli.h"
|
|
|
|
#include "cli/dos_cmds.h"
|
2021-09-25 19:14:29 -04:00
|
|
|
#include "cli/mem_cmds.h"
|
2021-10-05 15:51:53 -04:00
|
|
|
#include "dev/rtc.h"
|
2021-09-19 19:16:41 -04:00
|
|
|
|
|
|
|
#define MAX_COMMAND_SIZE 128
|
2021-09-25 17:26:23 -04:00
|
|
|
#define MAX_ARGC 32
|
2021-09-19 19:16:41 -04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Types
|
|
|
|
//
|
|
|
|
|
|
|
|
// Structure to hold a record about a command...
|
|
|
|
|
|
|
|
typedef struct s_cli_command {
|
|
|
|
char *name;
|
|
|
|
char *help;
|
|
|
|
cli_cmd_handler handler;
|
|
|
|
} t_cli_command, *p_cli_command;
|
|
|
|
|
2021-10-05 15:51:53 -04:00
|
|
|
extern short cmd_gettime(short channel, int argc, char * argv[]);
|
|
|
|
extern short cmd_settime(short channel, int argc, char * argv[]);
|
|
|
|
extern short cmd_sysinfo(short channel, int argc, char * argv[]);
|
|
|
|
|
2021-09-19 19:16:41 -04:00
|
|
|
/*
|
2021-09-30 13:39:39 -04:00
|
|
|
* Variables
|
2021-09-19 19:16:41 -04:00
|
|
|
*/
|
|
|
|
|
2021-09-30 13:39:39 -04:00
|
|
|
short g_current_channel = 0;
|
2021-09-19 19:16:41 -04:00
|
|
|
|
|
|
|
const t_cli_command g_cli_commands[] = {
|
2021-09-24 19:49:13 -04:00
|
|
|
{ "?", "? -- print this helpful message", cmd_help },
|
|
|
|
{ "HELP", "HELP -- print this helpful message", cmd_help },
|
2021-09-19 19:16:41 -04:00
|
|
|
{ "DIR", "DIR <path> -- print directory listing", cmd_dir },
|
2021-09-25 19:14:29 -04:00
|
|
|
{ "DUMP", "DUMP <address> [<count>] -- print a memory dump", mem_cmd_dump},
|
2021-09-24 19:49:13 -04:00
|
|
|
{ "LOAD", "LOAD <path> -- load a file into memory", cmd_load },
|
2021-09-25 19:14:29 -04:00
|
|
|
{ "PEEK8", "PEEK8 <address> -- print the byte at the address in memory", mem_cmd_peek8},
|
|
|
|
{ "PEEK16", "PEEK16 <address> -- print the 16-bit word at the address in memory", mem_cmd_peek16},
|
|
|
|
{ "PEEK32", "PEEK32 <address> -- print the 32-bit long word at the address in memory", mem_cmd_peek32},
|
|
|
|
{ "POKE8", "POKE8 <address> <value> -- write the byte value to the address in memory", mem_cmd_poke8},
|
|
|
|
{ "POKE16", "POKE16 <address> <value> -- write the 16-bit word value to the address in memory", mem_cmd_poke16},
|
|
|
|
{ "POKE32", "POKE32 <address> <value> -- write the 32-bit long word value to the address in memory", mem_cmd_poke32},
|
2021-09-30 13:39:39 -04:00
|
|
|
{ "RUN", "RUN <path> -- execute a binary file", cmd_run },
|
2021-10-05 15:51:53 -04:00
|
|
|
{ "GETTIME", "GETTIME -- prints the current time", cmd_gettime },
|
|
|
|
{ "SETTIME", "SETTIME -- prints the current time", cmd_settime },
|
|
|
|
{ "SYSINFO", "SYSINFO -- prints information about the system", cmd_sysinfo },
|
|
|
|
{ "TESTIDE", "TESTIDE -- fetches and prints the IDE MBR repeatedly", cmd_testide},
|
2021-09-24 12:05:45 -04:00
|
|
|
{ "TYPE", "TYPE <path> -- print the contents of a text file", cmd_type },
|
2021-09-19 19:16:41 -04:00
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
2021-09-30 13:39:39 -04:00
|
|
|
//
|
|
|
|
// List all the commands
|
|
|
|
//
|
|
|
|
int cmd_help(short channel, int argc, char * argv[]) {
|
|
|
|
p_cli_command command;
|
|
|
|
|
|
|
|
for (command = g_cli_commands; (command != 0) && (command->name != 0); command++) {
|
|
|
|
sys_chan_write(channel, command->help, strlen(command->help));
|
|
|
|
sys_chan_write(channel, "\n", 2);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-05 15:51:53 -04:00
|
|
|
/*
|
|
|
|
* Display information about the system
|
|
|
|
*/
|
|
|
|
short cmd_sysinfo(short channel, int argc, char * argv[]) {
|
|
|
|
t_sys_info info;
|
|
|
|
|
|
|
|
sys_get_info(&info);
|
|
|
|
print(channel, "System information:\nModel: ");
|
|
|
|
print(channel, info.model_name);
|
|
|
|
|
|
|
|
print(channel, "\nCPU: ");
|
|
|
|
print(channel, info.cpu_name);
|
|
|
|
|
|
|
|
print(channel, "\nGABE version: ");
|
|
|
|
print_hex_16(channel, info.gabe_number);
|
|
|
|
print(channel, ".");
|
|
|
|
print_hex_16(channel, info.gabe_version);
|
|
|
|
print(channel, ".");
|
|
|
|
print_hex_16(channel, info.gabe_subrev);
|
|
|
|
|
|
|
|
print(channel, "\nVICKY version: ");
|
|
|
|
print_hex_16(channel, info.vicky_rev);
|
|
|
|
|
|
|
|
print(channel, "\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
short cmd_gettime(short channel, int argc, char * argv[]) {
|
|
|
|
char time_string[128];
|
|
|
|
t_time time;
|
|
|
|
|
|
|
|
rtc_get_time(&time);
|
|
|
|
sprintf(time_string, "%04d-%02d-%02d %02d:%02d:%02d\n", time.year, time.month, time.day, time.hour, time.minute, time.second);
|
|
|
|
print(channel, time_string);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
short cmd_settime(short channel, int argc, char * argv[]) {
|
|
|
|
t_time time;
|
|
|
|
|
|
|
|
time.year = 2021;
|
|
|
|
time.month = 10;
|
|
|
|
time.day = 4;
|
|
|
|
time.hour = 9;
|
|
|
|
time.minute = 15;
|
|
|
|
time.second = 0;
|
|
|
|
time.is_24hours = 0;
|
|
|
|
time.is_pm = 1;
|
|
|
|
|
|
|
|
rtc_set_time(&time);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-19 19:16:41 -04:00
|
|
|
//
|
|
|
|
// Attempt to execute a command
|
|
|
|
//
|
|
|
|
// Inputs:
|
|
|
|
// command = the upper case name of the command (first word of the command line)
|
|
|
|
// parameters = the string of parameters to be passed to the command
|
|
|
|
//
|
2021-09-25 17:26:23 -04:00
|
|
|
short cli_exec(short channel, char * command, int argc, char * argv[]) {
|
2021-09-19 19:16:41 -04:00
|
|
|
const char * cmd_not_found = "Command not found.\n";
|
2021-09-25 17:26:23 -04:00
|
|
|
p_cli_command commands = g_cli_commands;
|
2021-09-19 19:16:41 -04:00
|
|
|
|
2021-09-25 17:26:23 -04:00
|
|
|
log3(LOG_INFO, "cli_exec: '", argv[0], "'");
|
|
|
|
log_num(LOG_INFO, "argc = ", argc);
|
2021-09-19 19:16:41 -04:00
|
|
|
|
|
|
|
while ((commands != 0) && (commands->name != 0)) {
|
|
|
|
// Does the command match the name?
|
|
|
|
if (strcmp(commands->name, command) == 0) {
|
|
|
|
// Found it, execute the handler
|
2021-09-25 17:26:23 -04:00
|
|
|
return commands->handler(channel, argc, argv);
|
2021-09-19 19:16:41 -04:00
|
|
|
} else {
|
|
|
|
// No match, keep checking...
|
|
|
|
commands++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Built in command not found..
|
|
|
|
// TODO: search the current drive for an executable file
|
|
|
|
sys_chan_write(channel, cmd_not_found, strlen(cmd_not_found));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-09-25 17:26:23 -04:00
|
|
|
char * strtok_r(char * source, const char * delimiter, char ** saveptr) {
|
|
|
|
char * x = *saveptr;
|
|
|
|
char * y;
|
|
|
|
|
|
|
|
/* Skip over leading delimiters */
|
|
|
|
for (x = *saveptr; *x && (*x == delimiter[0]); x++) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we reached the end of the string, return NULL */
|
|
|
|
if (*x == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (y = x; *y && (*y != delimiter[0]); y++) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we reached the end of the string, return x */
|
|
|
|
if (*y == 0) {
|
|
|
|
*saveptr = y;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise, make that position in the source string NULL, and return x */
|
|
|
|
*y = 0;
|
|
|
|
*saveptr = y + 1;
|
|
|
|
return x;
|
|
|
|
}
|
2021-09-19 19:16:41 -04:00
|
|
|
|
2021-09-30 13:39:39 -04:00
|
|
|
short cli_rerepl() {
|
|
|
|
while (1) {
|
|
|
|
cli_repl(g_current_channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-19 19:16:41 -04:00
|
|
|
//
|
|
|
|
// Enter the CLI's read-eval-print loop
|
|
|
|
//
|
|
|
|
short cli_repl(short channel) {
|
2021-09-25 17:26:23 -04:00
|
|
|
char command_line[MAX_COMMAND_SIZE];
|
|
|
|
char * arg;
|
|
|
|
char * token_save;
|
|
|
|
char * delim = " ";
|
|
|
|
int argc = 0;
|
|
|
|
char * argv[MAX_ARGC];
|
2021-09-19 19:16:41 -04:00
|
|
|
|
2021-09-30 13:39:39 -04:00
|
|
|
g_current_channel = channel;
|
2021-09-19 19:16:41 -04:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
sys_chan_write(channel, "\n> ", 3); // Print our prompt
|
|
|
|
sys_chan_readline(channel, command_line, MAX_COMMAND_SIZE); // Attempt to read line
|
|
|
|
sys_chan_write(channel, "\n", 1);
|
|
|
|
|
2021-09-25 17:26:23 -04:00
|
|
|
for (argc = 0, token_save = command_line; argc < MAX_ARGC; argc++) {
|
|
|
|
arg = strtok_r(command_line, delim, &token_save);
|
|
|
|
if (arg != 0) {
|
|
|
|
argv[argc] = arg;
|
|
|
|
} else {
|
|
|
|
break;
|
2021-09-19 19:16:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 17:26:23 -04:00
|
|
|
if (argc > 0) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < strlen(argv[0]); i++) {
|
|
|
|
argv[0][i] = toupper(argv[0][i]);
|
|
|
|
}
|
2021-09-19 19:16:41 -04:00
|
|
|
|
2021-09-25 17:26:23 -04:00
|
|
|
// Try to execute the command
|
|
|
|
cli_exec(channel, argv[0], argc, argv);
|
2021-09-19 19:16:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-25 19:14:29 -04:00
|
|
|
long cli_eval_dec(const char * arg) {
|
|
|
|
long n = 0;
|
|
|
|
|
|
|
|
TRACE("cli_eval_dec");
|
|
|
|
|
|
|
|
while (*arg) {
|
|
|
|
if (*arg == ':') {
|
|
|
|
arg++;
|
|
|
|
continue;
|
|
|
|
} else if (isdigit(*arg)) {
|
|
|
|
n *= 10;
|
|
|
|
n += *arg - '0';
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
long cli_eval_hex(const char * arg) {
|
|
|
|
long n = 0;
|
|
|
|
|
|
|
|
TRACE("cli_eval_hex");
|
|
|
|
|
|
|
|
while (*arg) {
|
|
|
|
if (*arg == ':') {
|
|
|
|
arg++;
|
|
|
|
continue;
|
|
|
|
} else if (isdigit(*arg)) {
|
|
|
|
n *= 16;
|
|
|
|
n += *arg - '0';
|
|
|
|
} else if ((*arg >= 'a') && (*arg <= 'f')) {
|
|
|
|
n *= 16;
|
|
|
|
n += *arg - 'a' + 10;
|
|
|
|
} else if ((*arg >= 'A') && (*arg <= 'F')) {
|
|
|
|
n *= 16;
|
|
|
|
n += *arg - 'A' + 10;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
long cli_eval_bin(const char * arg) {
|
|
|
|
long n = 0;
|
|
|
|
|
|
|
|
TRACE("cli_eval_bin");
|
|
|
|
|
|
|
|
while (*arg) {
|
|
|
|
if (*arg == ':') {
|
|
|
|
arg++;
|
|
|
|
continue;
|
|
|
|
} else if ((*arg == '0') || (*arg == '1')) {
|
|
|
|
n *= 2;
|
|
|
|
n += *arg - '0';
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Evaluate an argument to a number
|
|
|
|
*/
|
|
|
|
long cli_eval_number(const char * arg) {
|
|
|
|
int len = strlen(arg);
|
|
|
|
|
|
|
|
TRACE("cli_eval_number");
|
|
|
|
|
|
|
|
if (len > 2) {
|
|
|
|
if (arg[0] == '0') {
|
|
|
|
if (arg[1] == 'x') {
|
|
|
|
return cli_eval_hex(&arg[2]);
|
|
|
|
} else if (arg[1] == 'b') {
|
|
|
|
return cli_eval_bin(&arg[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > 1) {
|
|
|
|
if (arg[0] == '$') {
|
|
|
|
return cli_eval_hex(&arg[1]);
|
|
|
|
} else if (arg[0] == '%') {
|
|
|
|
return cli_eval_bin(&arg[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cli_eval_dec(arg);
|
|
|
|
}
|
|
|
|
|
2021-09-19 19:16:41 -04:00
|
|
|
//
|
|
|
|
// Initialize the CLI
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
// 0 on success, negative number on error
|
|
|
|
//
|
|
|
|
short cli_init() {
|
|
|
|
return 0;
|
|
|
|
}
|