Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
b1fb36c56This file is pinned to the selected release. Download the original to open it in your design tool.
/*
Shell inspired by the SD Card and FAT32 development testbed sdcard.asm
Direct interaction with the Monitor functions, the C library is not
used for any file or directory related functionality.
You can also use this as a reference implementation of how to use
the Monitor functions.
done by sy2002 in October 2016
*/
#ifndef __QNICE__
#error This program only runs on QNICE.
#endif
#if __STDC_VERSION__ != 199901L
#error This program needs C99 to compile. Use the -c99 VBCC switch.
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "qmon.h" // QNICE Monitor wrapper functions
#include "sysdef.h" // QNICE definitions and hardware registers
fat32_device_handle dh;
fat32_file_handle fh;
fat32_dir_entry de;
char* input_str;
char* split_str = 0;
//Print help, i.e. all commands and their parameters
void print_help()
{
puts(" navigate: dir and cd <path> (use / as a path separator)");
puts(" list files (complex names are allowed, use / as path separator):");
puts(" cat <filename> and cathex <filename>");
puts(" for seeking within the file, add a number (decimal or hex as 0x...)");
puts(" separated by a : after the filename, e.g. <filename>:1234");
puts(" print this info: help");
puts(" end program: exit\n");
}
//In case of an error, output the error code and terminate the program
void execute(int error)
{
if (error != 0)
{
if ((error & 0xFF00) != 0xEE00)
error &= 0x00FF;
printf("fatal error: 0x%04X\n", error);
exit(error);
}
}
//In case malloc failed, output an error and terminate the program
void malloc_check(void* p, char* context)
{
if (p == 0)
{
printf("fatal error: not enough heap for %s.\n", context);
exit(-1);
}
}
/* Extract filename and, if applicable seek position from prm and
execute the cat operation. If cathex == 0, then ASCII mode is
done, while accepting CR, LF and CR/LF. Otherwise a hexdump is done. */
void perform_cat(char* prm, int cathex)
{
unsigned long seek_pos = 0;
char* file_name;
//extract seek position, if any
char* argv;
int argc = qmon_split_str(prm, ':', &argv);
malloc_check(argv, "argv");
if (argc == 2)
{
char* dummy;
file_name = argv + 1;
seek_pos = strtoul(argv + ((int) *argv) + 2, &dummy, 0);
}
else
file_name = prm;
int ret = fat32_open_file(dh, fh, file_name);
if (ret == 0)
{
int seek_res = 0;
if (seek_pos)
seek_res = fat32_seek_file(fh, seek_pos);
if (seek_res == 0)
{
int read_byte, res;
int was_cr = 0; //was the byte of the last iteration a CR
int hex_counter = 0;
char recent[17];
recent[16] = 0;
while ((res = fat32_read_file(fh, &read_byte)) == 0)
{
//perform ASCII cat
if (cathex == 0)
{
//handle CR, LF and CR/LF
if (read_byte == CHR_CR || read_byte == CHR_LF)
{
//if LF after CF, then skip LF as we already
//printed a CR/LF when we read the CF
if (!(was_cr && read_byte == CHR_LF))
putc('\n', stdout);
}
else
//print character
putc(read_byte, stdout);
was_cr = read_byte == CHR_CR;
}
//perform hexdump
else
{
printf("%02X ", (unsigned char) read_byte);
recent[hex_counter] = iscntrl(read_byte) ? '.' : read_byte;
if (++hex_counter == 16)
{
printf(" %s\n", recent);
hex_counter = 0;
}
}
}
//every return value other than EOF is a fatal error
if (res != FAT32_EOF)
execute(ret);
//in hexdump mode: print the last few bytes
else if (cathex && hex_counter)
{
recent[hex_counter] = 0;
for (int i = 0; i < 16 - hex_counter; i++)
printf(" ");
printf(" %s\n", recent);
}
putc('\n', stdout);
}
else if (seek_res == FAT23_ERR_SEEKTOOLARGE)
printf("error: seek position is larger than file: %lu\n", seek_pos);
else
execute(seek_res); //fatal error, end program
}
else if (ret == FAT32_ERR_FILENOTFOUND)
printf("error: file not found: %s\n", file_name);
else
execute(ret); //fatal error, end program
free(argv);
}
int main()
{
puts("SD Card Shell Demo - done by sy2002 in October 2016\n");
print_help();
//mount partition #1 of built-in SD Card as FAT32
execute(fat32_mount_sd(dh, 1));
//reserve memory for the input string
input_str = malloc(1024);
malloc_check(input_str, "input_str");
while (1)
{
if (split_str != 0)
free(split_str);
//show prompt and read input string
printf("SDCARD> ");
fflush(stdout);
qmon_gets(input_str);
puts("");
//split input string into command and parameter
int input_amount = qmon_split_str(input_str, ' ', &split_str);
//sanity checks: empty string and no heap memory
if (input_amount == 0)
continue;
malloc_check(split_str, "split_str");
/* see the documentation of qmon_split_str in
c/qnice/monitor-lib/include/qmon.h to understand, how this works */
char* cmd = split_str + 1;
char* prm = split_str + ((int) *split_str) + 2;
qmon_str2upper(cmd);
//debug helper: check if malloc/free works
//printf("split_str = %u\n", (unsigned int) split_str);
//EXIT: end program
if (strcmp(cmd, "EXIT") == 0)
{
free(input_str);
free(split_str);
return 0;
}
//HELP: show help text
else if (strcmp(cmd, "HELP") == 0)
print_help();
//DIR: list current directory's content
else if (strcmp(cmd, "DIR") == 0)
{
execute(fat32_open_dir(dh, fh));
int entry_valid = 1;
while (entry_valid)
{
execute(fat32_list_dir(fh, de, FAT32_FA_DEFAULT, &entry_valid));
if (entry_valid)
fat32_print_dir_entry(de, FAT32_PRINT_DEFAULT);
}
}
//CD: change current directory
else if (strcmp(cmd, "CD") == 0)
{
char* path = input_str + 3;
int ret = fat32_change_dir(dh, path);
if (ret != 0)
{
if (ret == FAT32_ERR_DIRNOTFOUND)
printf("error: directory not found: %s\n", path);
else
execute(ret); //fatal error, end program
}
}
//CAT: print file as ASCII (accept CR, LF, CR/LF)
else if (strcmp(cmd, "CAT") == 0 && input_amount == 2)
perform_cat(prm, 0);
//CATHEX: print file as hexdump
else if (strcmp(cmd, "CATHEX") == 0 && input_amount == 2)
perform_cat(prm, 1);
//ILLEGAL COMMAND
else
puts("illegal command");
}
}