284 lines
7.7 KiB
C
284 lines
7.7 KiB
C
#include "commands.h"
|
|
#include "common.h"
|
|
#include "parsing.h"
|
|
#include "uart.h"
|
|
#include "eeprom.h"
|
|
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <util/delay.h>
|
|
|
|
// Mode: ASCII (false) or binary (true)
|
|
bool binary_mode = false;
|
|
|
|
// Execute a single parsed command
|
|
void executeCommand(CommandLine cmdLine) {
|
|
// Parse command
|
|
if (strcmp(cmdLine.command, "INIT") == 0) {
|
|
// INIT command: Initializes connection.
|
|
commandInit(cmdLine.arg);
|
|
}
|
|
else if (strcmp(cmdLine.command, "HELP") == 0) {
|
|
// HELP command: Print a list of supported commands.
|
|
commandHelp();
|
|
}
|
|
else if (strcmp(cmdLine.command, "READ") == 0) {
|
|
// READ command: Takes a hex address range (or single address) as argument,
|
|
// reads data and returns it in hexadecimal ASCII format.
|
|
commandRead(cmdLine.arg);
|
|
}
|
|
else if (strcmp(cmdLine.command, "WRITE") == 0) {
|
|
// WRITE command: Takes a hex address as argument, reads data from UART and writes it to the EEPROM.
|
|
commandWrite(cmdLine.arg);
|
|
}
|
|
else if (strcmp(cmdLine.command, "ERASE") == 0) {
|
|
// ERASE command: Takes a hex address range as argument and writes 0x00 bytes to the specified range.
|
|
commandErase(cmdLine.arg);
|
|
}
|
|
else if (strcmp(cmdLine.command, "TESTREAD") == 0) {
|
|
// TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format.
|
|
commandTestRead();
|
|
}
|
|
else if (strcmp(cmdLine.command, "TESTWRITE") == 0) {
|
|
// TESTWRITE command: for testing purposes, writes a few bytes
|
|
commandTestWrite(cmdLine.arg);
|
|
}
|
|
else {
|
|
// unknown command: return error message
|
|
uartPutLine("ERROR invalid command");
|
|
}
|
|
}
|
|
|
|
void commandInit(char* arg) {
|
|
// (Re-)initialize EEPROM functions
|
|
eepromInit();
|
|
|
|
// Default mode: ASCII
|
|
binary_mode = false;
|
|
|
|
if (arg != NULL) {
|
|
if (strcmp(arg, "BINARY") == 0) {
|
|
binary_mode = true;
|
|
} else if (strcmp(arg, "ASCII") == 0 || strcmp(arg, "TEXT") == 0) {
|
|
binary_mode = false;
|
|
}
|
|
}
|
|
|
|
if (binary_mode) {
|
|
uartPutLine("OK (binary mode)");
|
|
} else {
|
|
uartPutLine("OK (ASCII mode)");
|
|
}
|
|
}
|
|
|
|
void commandHelp() {
|
|
uartPutLine("HELP - Supported commands:");
|
|
uartPutLine("HELP - HELP");
|
|
uartPutLine("HELP - INIT [BINARY|ASCII]");
|
|
uartPutLine("HELP - READ 0000:0FFF");
|
|
uartPutLine("HELP - WRITE 0000");
|
|
uartPutLine("HELP - ERASE 0000:0FFF");
|
|
|
|
// TODO remove those
|
|
uartPutLine("HELP - TESTREAD (only for testing)");
|
|
uartPutLine("HELP - TESTWRITE (only for testing)");
|
|
|
|
uartPutLine("OK");
|
|
}
|
|
|
|
void commandRead(char* arg) {
|
|
if (arg == NULL) {
|
|
uartPutLine("ERROR READ needs an address or address range");
|
|
return;
|
|
}
|
|
|
|
// Parse address(es)
|
|
AddressRange range = parseAddressRange(arg);
|
|
if (!range.isValid) {
|
|
uartPutLine("ERROR invalid address format");
|
|
return;
|
|
}
|
|
|
|
uartPutLine("OK");
|
|
|
|
// Create data buffer
|
|
DataBuffer buffer;
|
|
|
|
do {
|
|
buffer.bytes = 0;
|
|
|
|
// Read a single block with up to DATA_BLOCK_SIZE bytes
|
|
Address nextAddress = eepromReadBlock(range, &buffer);
|
|
range.isValid = nextAddress.isValid;
|
|
range.from = nextAddress.value;
|
|
|
|
if (binary_mode) {
|
|
// Send block as binary "package":
|
|
// First the size of the package (1 byte) followed by the data bytes
|
|
uartPutChar(buffer.bytes);
|
|
|
|
for (uint8_t i = 0; i < buffer.bytes; i++) {
|
|
uartPutChar(buffer.data[i]);
|
|
}
|
|
} else {
|
|
// Fancy ASCII output
|
|
uartPutString("<0x");
|
|
uartPutHexByte(buffer.bytes);
|
|
uartPutChar('>');
|
|
|
|
for (uint8_t i = 0; i < buffer.bytes; i++) {
|
|
uartPutChar(' ');
|
|
uartPutHexByte(buffer.data[i]);
|
|
}
|
|
uartPutLine(NULL);
|
|
}
|
|
|
|
} while (buffer.bytes > 0);
|
|
}
|
|
|
|
void commandWrite(char* arg) {
|
|
if (arg == NULL) {
|
|
uartPutLine("ERROR WRITE needs a start address");
|
|
return;
|
|
}
|
|
|
|
// Parse address
|
|
Address startAddress = parseSingleAddress(arg);
|
|
if (!startAddress.isValid) {
|
|
uartPutLine("ERROR invalid address format");
|
|
return;
|
|
}
|
|
|
|
// Only binary mode
|
|
if (!binary_mode) {
|
|
uartPutLine("ERROR WRITE in ASCII mode is not implemented");
|
|
return;
|
|
}
|
|
|
|
// "OK" indicates that data can be sent now.
|
|
uartPutLine("OK START");
|
|
|
|
// Create data buffer
|
|
DataBuffer buffer;
|
|
|
|
Address currentAddress = startAddress;
|
|
uint8_t block_length = 0;
|
|
|
|
do {
|
|
// Reset buffer
|
|
buffer.bytes = 0;
|
|
|
|
// Read and check block length
|
|
block_length = uartGetChar();
|
|
|
|
if (block_length > DATA_BLOCK_SIZE) {
|
|
uartPutLine("ERROR maximal block size is: " STR(DATA_BLOCK_SIZE));
|
|
return;
|
|
}
|
|
|
|
// Read data bytes
|
|
while (buffer.bytes < block_length) {
|
|
buffer.data[buffer.bytes++] = uartGetChar();
|
|
}
|
|
|
|
// Write blocks to EEPROM until an "end block" (0 bytes) is received
|
|
if (buffer.bytes > 0) {
|
|
currentAddress = eepromWriteBlock(currentAddress, buffer);
|
|
|
|
if (!currentAddress.isValid) {
|
|
uartPutLine("ERROR reached end of EEPROM while writing block");
|
|
return;
|
|
}
|
|
else if (currentAddress.value == 0 || currentAddress.value >= HIGHEST_VALID_ADDRESS) {
|
|
// Block was written completely, but reached end of EEPROM now. No further data allowed (except for 0 byte "end block").
|
|
currentAddress.isValid = false;
|
|
uartPutLine("OK STOP (end of EEPROM)");
|
|
}
|
|
else {
|
|
// Next block of data can be sent now.
|
|
uartPutLine("OK CONTINUE");
|
|
}
|
|
}
|
|
|
|
} while (block_length > 0);
|
|
|
|
// WRITE completed
|
|
uartPutLine("OK END");
|
|
}
|
|
|
|
void commandErase(char* arg) {
|
|
if (arg == NULL) {
|
|
uartPutLine("ERROR ERASE needs a start address");
|
|
return;
|
|
}
|
|
|
|
// Parse address(es)
|
|
AddressRange range = parseAddressRange(arg);
|
|
if (!range.isValid || range.to < range.from) {
|
|
uartPutLine("ERROR invalid address format");
|
|
return;
|
|
}
|
|
|
|
uint32_t bytesErased = eepromEraseBlock(range);
|
|
|
|
if (bytesErased == 0) {
|
|
uartPutLine("ERROR 0 bytes erased");
|
|
} else {
|
|
char outBuffer[16];
|
|
snprintf(outBuffer, 16, "%lu", bytesErased);
|
|
uartPutString("OK erased ");
|
|
uartPutString(outBuffer);
|
|
uartPutLine(" bytes");
|
|
}
|
|
}
|
|
|
|
// TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format.
|
|
void commandTestRead() {
|
|
eepromSetReadMode();
|
|
|
|
for (uint8_t i = 0x00; i < 0x20; i++) {
|
|
uartPutString("TESTREAD 0x");
|
|
uartPutHexByte(i);
|
|
uartPutString(": ");
|
|
|
|
uint8_t byte = eepromReadByte(i);
|
|
|
|
if (byte >= 32 && byte <= 126) {
|
|
uartPutChar(byte);
|
|
} else {
|
|
uartPutChar('?');
|
|
}
|
|
|
|
uartPutString(" (0x");
|
|
uartPutHexByte(byte);
|
|
uartPutLine(")");
|
|
}
|
|
}
|
|
|
|
// TESTWRITE command: for testing purposes, writes a few bytes
|
|
void commandTestWrite(char* arg) {
|
|
char str[] = "Ohai world";
|
|
address_t addr = 0x00;
|
|
|
|
char* writeStr = str;
|
|
if (arg != NULL) {
|
|
writeStr = arg;
|
|
}
|
|
|
|
eepromSetWriteMode();
|
|
|
|
// write input line instead of static string
|
|
for (char* p = writeStr; *p != '\0'; p++) {
|
|
eepromWriteByte(addr, *p);
|
|
//_delay_ms(100);
|
|
addr++;
|
|
}
|
|
|
|
// TODO necessary?
|
|
_delay_ms(100);
|
|
|
|
uartPutLine("TESTWRITE success");
|
|
}
|