Compare commits

..

No commits in common. "1f668b60327028263f460e7ba4011a448b27fc1b" and "9e0ffd394b5f1dd4009204092bc92f1eecdd6bd2" have entirely different histories.

10 changed files with 84 additions and 195 deletions

View File

@ -7,7 +7,7 @@ OBJCOPY = avr-objcopy
AVRDUDE ?= avrdude AVRDUDE ?= avrdude
# Compiler and linker flags # Compiler and linker flags
CFLAGS = -Wall -pedantic -std=c11 -Os CFLAGS = -Wall -std=c11 -Os
LDFLAGS = LDFLAGS =
# Target platform and programmer # Target platform and programmer

View File

@ -16,19 +16,19 @@
static inline void BIT_SET(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline)); static inline void BIT_SET(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline void BIT_SET(volatile uint8_t *target, uint8_t bit){ static inline void BIT_SET(volatile uint8_t *target, uint8_t bit){
*target |= (1<<bit); *target |= (1<<bit);
} };
// set clear // set clear
static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline)); static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit){ static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit){
*target &= ~(1<<bit); *target &= ~(1<<bit);
} };
// bit toogle // bit toogle
static inline void BIT_TOGGLE(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline)); static inline void BIT_TOGGLE(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline void BIT_TOGGLE(volatile uint8_t *target, uint8_t bit){ static inline void BIT_TOGGLE(volatile uint8_t *target, uint8_t bit){
*target ^= (1<<bit); *target ^= (1<<bit);
} };
// set bit by boolean // set bit by boolean
static inline void BIT_BOOL_SET(volatile uint8_t *target, uint8_t bit, bool enable) __attribute__((always_inline)); static inline void BIT_BOOL_SET(volatile uint8_t *target, uint8_t bit, bool enable) __attribute__((always_inline));
@ -38,6 +38,6 @@ static inline void BIT_BOOL_SET(volatile uint8_t *target, uint8_t bit, bool enab
}else{ }else{
BIT_CLEAR(target, bit); BIT_CLEAR(target, bit);
} }
} };
#endif /* BITIO_H_ */ #endif /* BITIO_H_ */

View File

@ -21,7 +21,7 @@ void executeCommand(CommandLine cmdLine) {
} }
else if (strcmp(cmdLine.command, "HELP") == 0) { else if (strcmp(cmdLine.command, "HELP") == 0) {
// HELP command: Print a list of supported commands. // HELP command: Print a list of supported commands.
commandHelp(); commandHelp(cmdLine.arg);
} }
else if (strcmp(cmdLine.command, "READ") == 0) { else if (strcmp(cmdLine.command, "READ") == 0) {
// READ command: Takes a hex address range (or single address) as argument, // READ command: Takes a hex address range (or single address) as argument,
@ -30,11 +30,11 @@ void executeCommand(CommandLine cmdLine) {
} }
else if (strcmp(cmdLine.command, "WRITE") == 0) { 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. // WRITE command: Takes a hex address as argument, reads data from UART and writes it to the EEPROM.
commandWrite(cmdLine.arg); commandRead(cmdLine.arg);
} }
else if (strcmp(cmdLine.command, "ERASE") == 0) { else if (strcmp(cmdLine.command, "ERASE") == 0) {
// ERASE command: Takes a hex address range as argument and writes 0x00 bytes to the specified range. // ERASE command: Takes a hex address range as argument and writes 0x00 bytes to the specified range.
commandErase(cmdLine.arg); commandRead(cmdLine.arg);
} }
else if (strcmp(cmdLine.command, "TESTREAD") == 0) { else if (strcmp(cmdLine.command, "TESTREAD") == 0) {
// TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format. // TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format.
@ -46,7 +46,7 @@ void executeCommand(CommandLine cmdLine) {
} }
else { else {
// unknown command: return error message // unknown command: return error message
uartPutLine("ERROR invalid command"); uartPutLine("ERR invalid command");
} }
} }
@ -89,14 +89,14 @@ void commandHelp() {
void commandRead(char* arg) { void commandRead(char* arg) {
if (arg == NULL) { if (arg == NULL) {
uartPutLine("ERROR READ needs an address or address range"); uartPutLine("ERR READ needs an address or address range");
return; return;
} }
// Parse address(es) // Parse address(es)
AddressRange range = parseAddressRange(arg); AddressRange range = parseAddressRange(arg);
if (!range.isValid) { if (!range.isValid) {
uartPutLine("ERROR invalid address format"); uartPutLine("ERR invalid address format");
return; return;
} }
@ -111,9 +111,7 @@ void commandRead(char* arg) {
do { do {
// Read a single block with up to DATA_BLOCK_SIZE bytes // Read a single block with up to DATA_BLOCK_SIZE bytes
Address nextAddress = eepromReadBlock(range, &buffer); range.from = eepromReadBlock(range, &buffer);
range.isValid = nextAddress.isValid;
range.from = nextAddress.value;
if (binary_mode) { if (binary_mode) {
// Send block as binary "package": // Send block as binary "package":
@ -125,13 +123,10 @@ void commandRead(char* arg) {
} }
} else { } else {
// Fancy ASCII output // Fancy ASCII output
uartPutChar('<'); uartPrintf("<%d>", buffer.bytes);
uartPutInteger(buffer.bytes);
uartPutChar('>');
for (int i = 0; i < buffer.bytes; i++) { for (int i = 0; i < buffer.bytes; i++) {
uartPutChar(' '); uartPrintf(" %02X", buffer.data[i]);
uartPutHexByte(buffer.data[i]);
} }
uartPutLine(NULL); uartPutLine(NULL);
} }
@ -141,96 +136,38 @@ void commandRead(char* arg) {
void commandWrite(char* arg) { void commandWrite(char* arg) {
if (arg == NULL) { if (arg == NULL) {
uartPutLine("ERROR WRITE needs a start address"); uartPutLine("ERR WRITE needs a start address");
return; return;
} }
// Parse address // Parse address
Address startAddress = parseSingleAddress(arg); AddressRange range = parseSingleAddress(arg);
if (!startAddress.isValid) { if (!range.isValid) {
uartPutLine("ERROR invalid address format"); uartPutLine("ERR invalid address format");
return; return;
} }
// Only binary mode // Only binary mode
if (!binary_mode) { if (!binary_mode) {
uartPutLine("ERROR WRITE in ASCII mode is not implemented"); uartPutLine("ERR WRITE in ASCII mode is not implemented");
return; return;
} }
// Create data buffer // TODO read data from input and write to EEPROM
uint8_t byteBuffer[DATA_BLOCK_SIZE]; uartPutLine("ERR not implemented");
DataBuffer buffer = {
.data = byteBuffer,
.maxSize = DATA_BLOCK_SIZE,
.bytes = 0
};
// "OK" indicates that data can be sent now.
uartPutLine("OK START");
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 > buffer.maxSize) {
uartPutString("ERROR maximal block size is: ");
uartPutInteger(buffer.maxSize);
uartPutLine(NULL);
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);
// TODO wait necessary?
//_delay_ms(100);
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() { void commandErase() {
uartPutLine("ERROR not implemented"); // TODO
uartPutLine("ERR not implemented");
} }
// TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format. // TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format.
void commandTestRead() { void commandTestRead() {
eepromSetReadMode(); eepromSetReadMode();
for (uint8_t i = 0x00; i < 0x20; i++) { for (int i = 0x00; i < 0x20; i++) {
uartPutString("TESTREAD 0x"); uartPrintf("TESTREAD 0x%02X: ", i);
uartPutHexByte(i);
uartPutString(": ");
uint8_t byte = eepromReadByte(i); uint8_t byte = eepromReadByte(i);
@ -240,9 +177,7 @@ void commandTestRead() {
uartPutChar('?'); uartPutChar('?');
} }
uartPutString(" (0x"); uartPrintf(" (0x%02X)\n");
uartPutHexByte(byte);
uartPutLine(")");
} }
} }

View File

@ -14,12 +14,6 @@ typedef uint16_t address_t;
// Define highest valid address for the EEPROM // Define highest valid address for the EEPROM
#define HIGHEST_VALID_ADDRESS 0x7fff #define HIGHEST_VALID_ADDRESS 0x7fff
// Type definition for a single address (nullable)
typedef struct {
bool isValid;
address_t value;
} Address;
// Type definition for address ranges (from-to) // Type definition for address ranges (from-to)
typedef struct { typedef struct {
bool isValid; bool isValid;

View File

@ -115,16 +115,12 @@ void eepromWriteByte(address_t address, uint8_t data) {
} }
// Read multiple bytes from EEPROM into a buffer // Read multiple bytes from EEPROM into a buffer
Address eepromReadBlock(AddressRange addressRange, DataBuffer* buffer) { address_t eepromReadBlock(AddressRange addressRange, DataBuffer* buffer) {
// Set read mode // Set read mode
eepromSetReadMode(); eepromSetReadMode();
buffer->bytes = 0; buffer->bytes = 0;
if (!addressRange.isValid) {
return (Address) {false, 0};
}
address_t currentAddress = addressRange.from; address_t currentAddress = addressRange.from;
address_t highestAddress = addressRange.to; address_t highestAddress = addressRange.to;
@ -134,41 +130,20 @@ Address eepromReadBlock(AddressRange addressRange, DataBuffer* buffer) {
while (currentAddress <= highestAddress && buffer->bytes < buffer->maxSize) { while (currentAddress <= highestAddress && buffer->bytes < buffer->maxSize) {
buffer->data[buffer->bytes++] = eepromReadByte(currentAddress++); buffer->data[buffer->bytes++] = eepromReadByte(currentAddress++);
// Handle integer overflow
if (currentAddress == 0) {
return (Address) {false, 0};
}
} }
return (Address) {true, currentAddress}; return currentAddress;
} }
// Write multiple bytes from a buffer to EEPROM // // Write multiple bytes from a buffer to EEPROM
Address eepromWriteBlock(Address startAddress, DataBuffer buffer) { // address_t eepromWriteBlock(address_t currentAddress, DataBuffer buffer) {
// Set write mode // // Set write mode
eepromSetWriteMode(); // eepromSetWriteMode();
if (!startAddress.isValid) { // for (uint8_t i = 0; currentAddress <= HIGHEST_VALID_ADDRESS && i < buffer.bytes; i++) {
return (Address) {false, 0}; // eepromWriteByte(currentAddress++, buffer.data[i]);
} // // TODO address overflow
// }
address_t currentAddress = startAddress.value; // return currentAddress;
uint8_t i; // }
for (i = 0; i < buffer.bytes && currentAddress <= HIGHEST_VALID_ADDRESS; i++) {
eepromWriteByte(currentAddress++, buffer.data[i]);
// Handle integer overflow
if (currentAddress == 0) {
break;
}
}
if (i < buffer.bytes) {
// There are unwritten bytes left -> must be an address overflow
return (Address) {false, 0};
}
return (Address) {true, currentAddress};
}

View File

@ -41,9 +41,9 @@ uint8_t eepromReadByte(address_t address);
void eepromWriteByte(address_t address, uint8_t data); void eepromWriteByte(address_t address, uint8_t data);
// Read multiple bytes from EEPROM into a buffer // Read multiple bytes from EEPROM into a buffer
Address eepromReadBlock(AddressRange addressRange, DataBuffer* buffer); address_t eepromReadBlock(AddressRange addressRange, DataBuffer* buffer);
// Write multiple bytes from a buffer to EEPROM // // Write multiple bytes from a buffer to EEPROM
Address eepromWriteBlock(Address startAddress, DataBuffer buffer); // address_t eepromWriteBlock(address_t addressRange, DataBuffer buffer);
#endif /* EEPROM_H_ */ #endif /* EEPROM_H_ */

View File

@ -8,9 +8,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <util/delay.h> #include <util/delay.h>
// Command parsing
// ---------------
// Read and parse command line and dispatch command // Read and parse command line and dispatch command
void parseNextCommand() { void parseNextCommand() {
const int bufferLength = 80; const int bufferLength = 80;
@ -31,7 +28,7 @@ CommandLine readNextCommand(char* buffer, uint8_t bufferLength) {
if (readChars >= bufferLength - 1) { if (readChars >= bufferLength - 1) {
// Reading was aborted after bufferLength-1 characters to prevent buffer overflow. // Reading was aborted after bufferLength-1 characters to prevent buffer overflow.
uartPutLine("ERROR buffer overflow, discarding line"); uartPutLine("ERR buffer overflow, discarding line");
// Discard everything until we read an actual end of line // Discard everything until we read an actual end of line
for (unsigned char c = 0; c != '\n' && c != '\r'; c = uartGetChar()); for (unsigned char c = 0; c != '\n' && c != '\r'; c = uartGetChar());
@ -69,11 +66,8 @@ CommandLine tokenizeCommand(char* cmd) {
} }
// Address parsing // Address parsing
// --------------- bool parseSingleAddressTo(char* addressStr, address_t* address) {
if (addressStr == NULL || strlen(addressStr) != 4 || address == NULL) {
// Validates a single 2-byte hexadecimal address string "XXXX".
bool validateAddressString(char* addressStr) {
if (addressStr == NULL || strlen(addressStr) != 4) {
return false; return false;
} }
@ -83,19 +77,18 @@ bool validateAddressString(char* addressStr) {
} }
} }
*address = strtol(addressStr, NULL, 16);
return true; return true;
} }
// Parses a single 2-byte hexadecimal address string "XXXX" to an actual address. // Parses a single 2-byte hexadecimal address string "XXXX:YYYY" to an actual address.
Address parseSingleAddress(char* addressStr) { AddressRange parseSingleAddress(char* addressStr) {
Address address = {false, 0}; AddressRange range = {true, 0, 0};
if (!parseSingleAddressTo(addressStr, &range.from)) {
if (validateAddressString(addressStr)) { return (AddressRange) {false, 0, 0};
address.isValid = true;
address.value = strtol(addressStr, NULL, 16);
} }
range.to = range.from;
return address; return range;
} }
// Parses a hexadecimal address range string "XXXX:YYYY" to actual addresses. // Parses a hexadecimal address range string "XXXX:YYYY" to actual addresses.
@ -105,29 +98,25 @@ AddressRange parseAddressRange(char* addressStr) {
return (AddressRange) {false, 0, 0}; return (AddressRange) {false, 0, 0};
} }
int length = strlen(addressStr); int len = strlen(addressStr);
if (len != 4 && len != 9) {
if (length == 4) {
Address address = parseSingleAddress(addressStr);
return (AddressRange) {
.isValid = address.isValid,
.from = address.value,
.to = address.value
};
}
else if (length == 9 && addressStr[4] == ':') {
addressStr[4] = '\0';
Address fromAddress = parseSingleAddress(addressStr);
Address toAddress = parseSingleAddress(addressStr + 5);
return (AddressRange) {
.isValid = fromAddress.isValid && toAddress.isValid,
.from = fromAddress.value,
.to = toAddress.value
};
}
else {
return (AddressRange) {false, 0, 0}; return (AddressRange) {false, 0, 0};
} }
if (len == 9) {
if (addressStr[4] != ':') {
return (AddressRange) {false, 0, 0};
}
addressStr[4] = '\0';
}
AddressRange range = parseSingleAddress(addressStr);
if (range.isValid && len == 9) {
if (!parseSingleAddressTo(addressStr + 5, &range.to)) {
return (AddressRange) {false, 0, 0};
}
}
return range;
} }

View File

@ -14,8 +14,8 @@ void parseNextCommand();
CommandLine readNextCommand(char* buffer, uint8_t bufferLength); CommandLine readNextCommand(char* buffer, uint8_t bufferLength);
CommandLine tokenizeCommand(char* cmd); CommandLine tokenizeCommand(char* cmd);
bool validateAddressString(char* addressStr); bool parseSingleAddressTo(char* addressStr, address_t* address);
Address parseSingleAddress(char* addressStr); AddressRange parseSingleAddress(char* addressStr);
AddressRange parseAddressRange(char* addressStr); AddressRange parseAddressRange(char* addressStr);
#endif /* PARSING_H_ */ #endif /* PARSING_H_ */

View File

@ -56,18 +56,17 @@ void uartPutLine(char* data) {
uartPutChar('\n'); uartPutChar('\n');
} }
// Convert an integer to decimal ASCII and transmit // Transmit a sprintf formatted string (maximum buffer: 256 bytes!)
void uartPutInteger(int value) { void uartPrintf(const char* format, ...) {
char outBuffer[32]; char outBuffer[256];
snprintf(outBuffer, 32, "%d", value);
uartPutString(outBuffer);
}
// Convert a byte to hexadecimal ASCII and transmit va_list args;
void uartPutHexByte(uint8_t byte) { va_start(args, format);
char outBuffer[8];
snprintf(outBuffer, 8, "%02hhX", byte); vsprintf(outBuffer, format, args);
uartPutString(outBuffer); uartPutString(outBuffer);
va_end(args);
} }
// Receive a single character (blocking) // Receive a single character (blocking)

View File

@ -16,11 +16,8 @@ void uartPutString(char* data);
// Transmit a string followed by a line break // Transmit a string followed by a line break
void uartPutLine(char* data); void uartPutLine(char* data);
// Convert an integer to decimal ASCII and transmit // Transmit a sprintf formatted string (maximum buffer: 256 bytes!)
void uartPutInteger(int value); void uartPrintf(const char* format, ...);
// Convert a byte to hexadecimal ASCII and transmit
void uartPutHexByte(uint8_t byte);
// Read a single character (blocking) // Read a single character (blocking)
unsigned char uartGetChar(); unsigned char uartGetChar();