diff --git a/firmware/src/commands.c b/firmware/src/commands.c index 5dcdc3c..ed8620a 100644 --- a/firmware/src/commands.c +++ b/firmware/src/commands.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -36,14 +37,6 @@ void executeCommand(CommandLine cmdLine) { // 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"); @@ -79,11 +72,6 @@ void commandHelp() { 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"); } @@ -102,14 +90,12 @@ void commandRead(char* arg) { uartPutLine("OK"); - uint8_t byteBuffer[DATA_BLOCK_SIZE]; - DataBuffer buffer = { - .data = byteBuffer, - .maxSize = DATA_BLOCK_SIZE, - .bytes = 0 - }; + // 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; @@ -120,16 +106,16 @@ void commandRead(char* arg) { // First the size of the package (1 byte) followed by the data bytes uartPutChar(buffer.bytes); - for (int i = 0; i < buffer.bytes; i++) { + for (uint8_t i = 0; i < buffer.bytes; i++) { uartPutChar(buffer.data[i]); } } else { // Fancy ASCII output - uartPutChar('<'); - uartPutInteger(buffer.bytes); + uartPutString("<0x"); + uartPutHexByte(buffer.bytes); uartPutChar('>'); - for (int i = 0; i < buffer.bytes; i++) { + for (uint8_t i = 0; i < buffer.bytes; i++) { uartPutChar(' '); uartPutHexByte(buffer.data[i]); } @@ -158,17 +144,12 @@ void commandWrite(char* arg) { return; } - // Create data buffer - uint8_t byteBuffer[DATA_BLOCK_SIZE]; - DataBuffer buffer = { - .data = byteBuffer, - .maxSize = DATA_BLOCK_SIZE, - .bytes = 0 - }; - // "OK" indicates that data can be sent now. uartPutLine("OK START"); + // Create data buffer + DataBuffer buffer; + Address currentAddress = startAddress; uint8_t block_length = 0; @@ -179,10 +160,8 @@ void commandWrite(char* arg) { // Read and check block length block_length = uartGetChar(); - if (block_length > buffer.maxSize) { - uartPutString("ERROR maximal block size is: "); - uartPutInteger(buffer.maxSize); - uartPutLine(NULL); + if (block_length > DATA_BLOCK_SIZE) { + uartPutLine("ERROR maximal block size is: " STR(DATA_BLOCK_SIZE)); return; } @@ -195,9 +174,6 @@ void commandWrite(char* arg) { if (buffer.bytes > 0) { currentAddress = eepromWriteBlock(currentAddress, buffer); - // TODO wait necessary? - //_delay_ms(100); - if (!currentAddress.isValid) { uartPutLine("ERROR reached end of EEPROM while writing block"); return; @@ -219,54 +195,28 @@ void commandWrite(char* arg) { uartPutLine("OK END"); } -void commandErase() { - uartPutLine("ERROR not implemented"); -} - -// 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; +void commandErase(char* arg) { + if (arg == NULL) { + uartPutLine("ERROR ERASE needs a start address"); + return; } - eepromSetWriteMode(); - - // write input line instead of static string - for (char* p = writeStr; *p != '\0'; p++) { - eepromWriteByte(addr, *p); - //_delay_ms(100); - addr++; + // Parse address(es) + AddressRange range = parseAddressRange(arg); + if (!range.isValid || range.to < range.from) { + uartPutLine("ERROR invalid address format"); + return; } - // TODO necessary? - _delay_ms(100); + uint32_t bytesErased = eepromEraseBlock(range); - uartPutLine("TESTWRITE success"); + if (bytesErased == 0) { + uartPutLine("ERROR 0 bytes erased"); + } else { + char outBuffer[16]; + snprintf(outBuffer, 16, "%lu", bytesErased); + uartPutString("OK erased "); + uartPutString(outBuffer); + uartPutLine(" bytes"); + } } diff --git a/firmware/src/commands.h b/firmware/src/commands.h index f31a471..1dd4ecf 100644 --- a/firmware/src/commands.h +++ b/firmware/src/commands.h @@ -12,8 +12,4 @@ void commandRead(char* arg); void commandWrite(char* arg); void commandErase(); -// TODO commands only for testing -void commandTestRead(); -void commandTestWrite(char* arg); - #endif /* COMMANDS_H_ */ diff --git a/firmware/src/common.h b/firmware/src/common.h index d6cb0e7..479a8af 100644 --- a/firmware/src/common.h +++ b/firmware/src/common.h @@ -8,6 +8,10 @@ // Define macro for NOP instruction #define _NOP() __asm__ __volatile__ ("nop"); +// Define macro to convert a preprocessor constant to a string literal +#define STR_(x) #x +#define STR(x) STR_(x) + // Define type for EEPROM addresses typedef uint16_t address_t; @@ -28,12 +32,11 @@ typedef struct { } AddressRange; // Define type for a block of data (bytes) +#define DATA_BLOCK_SIZE 64 + typedef struct { - uint8_t* data; - uint8_t maxSize; + uint8_t data[DATA_BLOCK_SIZE]; uint8_t bytes; } DataBuffer; -#define DATA_BLOCK_SIZE 64 - #endif /* COMMON_H_ */ diff --git a/firmware/src/eeprom.c b/firmware/src/eeprom.c index abe6e6b..9eb76ca 100644 --- a/firmware/src/eeprom.c +++ b/firmware/src/eeprom.c @@ -132,7 +132,7 @@ Address eepromReadBlock(AddressRange addressRange, DataBuffer* buffer) { highestAddress = HIGHEST_VALID_ADDRESS; } - while (currentAddress <= highestAddress && buffer->bytes < buffer->maxSize) { + while (currentAddress <= highestAddress && buffer->bytes < DATA_BLOCK_SIZE) { buffer->data[buffer->bytes++] = eepromReadByte(currentAddress++); // Handle integer overflow @@ -172,3 +172,34 @@ Address eepromWriteBlock(Address startAddress, DataBuffer buffer) { return (Address) {true, currentAddress}; } + +// Erase block of data on the EEPROM +uint32_t eepromEraseBlock(AddressRange addressRange) { + // Set write mode + eepromSetWriteMode(); + + if (!addressRange.isValid) { + return 0; + } + + address_t currentAddress = addressRange.from; + address_t highestAddress = addressRange.to; + + if (highestAddress > HIGHEST_VALID_ADDRESS) { + highestAddress = HIGHEST_VALID_ADDRESS; + } + + uint32_t bytesErased = 0; + + while (currentAddress <= highestAddress) { + eepromWriteByte(currentAddress++, 0x00); + bytesErased++; + + // Handle integer overflow + if (currentAddress == 0) { + break; + } + } + + return bytesErased; +} diff --git a/firmware/src/eeprom.h b/firmware/src/eeprom.h index 0dfdffd..84d9a42 100644 --- a/firmware/src/eeprom.h +++ b/firmware/src/eeprom.h @@ -5,10 +5,6 @@ #include "common.h" #include -// Define address length -// TODO 15 or 16? -#define ADDRESS_LENGTH 15 - // Macros for IO pins #define EEP_ADDR_LOW_PORT PORTC #define EEP_ADDR_LOW_DDR DDRC @@ -46,4 +42,7 @@ Address eepromReadBlock(AddressRange addressRange, DataBuffer* buffer); // Write multiple bytes from a buffer to EEPROM Address eepromWriteBlock(Address startAddress, DataBuffer buffer); +// Erase block of data on the EEPROM +uint32_t eepromEraseBlock(AddressRange addressRange); + #endif /* EEPROM_H_ */ diff --git a/firmware/src/parsing.c b/firmware/src/parsing.c index 8316251..c3b6f79 100644 --- a/firmware/src/parsing.c +++ b/firmware/src/parsing.c @@ -13,7 +13,7 @@ // Read and parse command line and dispatch command void parseNextCommand() { - const int bufferLength = 80; + const int bufferLength = 40; char buffer[bufferLength]; // Read next command diff --git a/firmware/src/uart.c b/firmware/src/uart.c index e2dc588..5e84c97 100644 --- a/firmware/src/uart.c +++ b/firmware/src/uart.c @@ -4,8 +4,15 @@ #include #include #include +#include +#include #include +// Hexadecimal digit lookup table +static const char hexDigitLookupTable[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + // Initialize UART void uartInit() { // Set Baud register @@ -56,18 +63,12 @@ void uartPutLine(char* data) { uartPutChar('\n'); } -// Convert an integer to decimal ASCII and transmit -void uartPutInteger(int value) { - char outBuffer[32]; - snprintf(outBuffer, 32, "%d", value); - uartPutString(outBuffer); -} - // Convert a byte to hexadecimal ASCII and transmit void uartPutHexByte(uint8_t byte) { - char outBuffer[8]; - snprintf(outBuffer, 8, "%02hhX", byte); - uartPutString(outBuffer); + // First hex digit: most significant 4 bits + uartPutChar(hexDigitLookupTable[(byte >> 4) & 0x0f]); + // Second hex digit: least significant 4 bits + uartPutChar(hexDigitLookupTable[byte & 0x0f]); } // Receive a single character (blocking) diff --git a/firmware/src/uart.h b/firmware/src/uart.h index 9065993..d5be266 100644 --- a/firmware/src/uart.h +++ b/firmware/src/uart.h @@ -16,9 +16,6 @@ void uartPutString(char* data); // Transmit a string followed by a line break void uartPutLine(char* data); -// Convert an integer to decimal ASCII and transmit -void uartPutInteger(int value); - // Convert a byte to hexadecimal ASCII and transmit void uartPutHexByte(uint8_t byte);