Refactor protocol/parsing code; implement address parsing
This commit is contained in:
parent
28be3c4e8b
commit
bc849d9662
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include "commands.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
#include "uart.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
// Execute a single parsed command
|
||||||
|
void executeCommand(CommandLine cmdLine) {
|
||||||
|
// Parse command
|
||||||
|
if (strcmp(cmdLine.command, "INIT") == 0) {
|
||||||
|
// INIT command: Initializes connection.
|
||||||
|
commandInit();
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
commandRead(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
|
||||||
|
uartPutString("ERR invalid command\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandInit() {
|
||||||
|
// TODO init... or something?
|
||||||
|
uartPutString("OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandRead(char* arg) {
|
||||||
|
if (arg == NULL) {
|
||||||
|
uartPutString("ERR READ needs an address or address range\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse address(es)
|
||||||
|
AddressRange range = parseAddressRange(arg);
|
||||||
|
if (!range.isValid) {
|
||||||
|
uartPutString("ERR invalid address format\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO read data and output it
|
||||||
|
uartPutString("ERR not implemented\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandWrite(char* arg) {
|
||||||
|
if (arg == NULL) {
|
||||||
|
uartPutString("ERR WRITE needs a start address\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse address
|
||||||
|
AddressRange range = parseSingleAddress(arg);
|
||||||
|
if (!range.isValid) {
|
||||||
|
uartPutString("ERR invalid address format\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO read data from input and write to EEPROM
|
||||||
|
uartPutString("ERR not implemented\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandErase() {
|
||||||
|
// TODO
|
||||||
|
uartPutString("ERR not implemented\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTREAD command: for testing purposes, reads a few bytes and returns them in a human readable format.
|
||||||
|
void commandTestRead() {
|
||||||
|
uint8_t byte;
|
||||||
|
char outBuffer[20];
|
||||||
|
|
||||||
|
eepromSetReadMode();
|
||||||
|
|
||||||
|
for (int i = 0x00; i < 0x20; i++) {
|
||||||
|
itoa(i, outBuffer, 16);
|
||||||
|
uartPutString("TESTREAD 0x");
|
||||||
|
uartPutString(outBuffer);
|
||||||
|
uartPutString(": ");
|
||||||
|
|
||||||
|
byte = eepromReadByte(i);
|
||||||
|
itoa(byte, outBuffer, 16);
|
||||||
|
|
||||||
|
uartPutChar(byte);
|
||||||
|
uartPutString(" (0x");
|
||||||
|
uartPutString(outBuffer);
|
||||||
|
uartPutString(")\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
uartPutString("TESTWRITE success\r\n");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef COMMANDS_H_
|
||||||
|
#define COMMANDS_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
|
||||||
|
void executeCommand(CommandLine cmdLine);
|
||||||
|
|
||||||
|
void commandInit();
|
||||||
|
void commandRead(char* arg);
|
||||||
|
void commandWrite(char* arg);
|
||||||
|
void commandErase();
|
||||||
|
|
||||||
|
// TODO commands only for testing
|
||||||
|
void commandTestRead();
|
||||||
|
void commandTestWrite(char* arg);
|
||||||
|
|
||||||
|
#endif /* COMMANDS_H_ */
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "eeprom.h"
|
#include "eeprom.h"
|
||||||
#include "protocol.h"
|
#include "parsing.h"
|
||||||
|
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
|
@ -18,6 +18,6 @@ int main(void) {
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
// Run main loop endlessly
|
// Run main loop endlessly
|
||||||
protocolMainLoop();
|
parseNextCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
#include "commands.h"
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
// Read and parse command line and dispatch command
|
||||||
|
void parseNextCommand() {
|
||||||
|
const int bufferLength = 80;
|
||||||
|
char buffer[bufferLength];
|
||||||
|
|
||||||
|
// Read next command
|
||||||
|
CommandLine cmdLine = readNextCommand(buffer, bufferLength);
|
||||||
|
|
||||||
|
// Execute command
|
||||||
|
executeCommand(cmdLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read next command line from UART
|
||||||
|
CommandLine readNextCommand(char* buffer, uint8_t bufferLength) {
|
||||||
|
while (1) {
|
||||||
|
// Read next command
|
||||||
|
int readChars = uartGetLine(buffer, bufferLength);
|
||||||
|
|
||||||
|
if (readChars >= bufferLength - 1) {
|
||||||
|
// Reading was aborted after bufferLength-1 characters to prevent buffer overflow.
|
||||||
|
uartPutString("ERR buffer overflow, discarding line\r\n");
|
||||||
|
|
||||||
|
// Discard everything until we read an actual end of line
|
||||||
|
for (unsigned char c = 0; c != '\n' && c != '\r'; c = uartGetChar());
|
||||||
|
readChars = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readChars != 0) {
|
||||||
|
return tokenizeCommand(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splits a command "CMD ARGS" to two strings "CMD" and "ARGS". Returns pointer
|
||||||
|
// to "ARGS" or NULL if no arguments were found. Changes the input string!
|
||||||
|
CommandLine tokenizeCommand(char* cmd) {
|
||||||
|
CommandLine cmdLine = {
|
||||||
|
cmd,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd == NULL) {
|
||||||
|
return cmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for a space character
|
||||||
|
for (char* p = cmd; *p != '\0'; p++) {
|
||||||
|
if (*p == ' ') {
|
||||||
|
// Split strings by replacing the space by \0, then set argument pointer.
|
||||||
|
*p++ = '\0';
|
||||||
|
cmdLine.arg = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address parsing
|
||||||
|
bool parseSingleAddressTo(char* addressStr, address_t* address) {
|
||||||
|
if (addressStr == NULL || strlen(addressStr) != 4 || address == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* p = addressStr; *p != '\0'; p++) {
|
||||||
|
if ((*p < '0' || *p > '9') && (*p < 'A' || *p > 'F')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*address = strtol(addressStr, NULL, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a single 2-byte hexadecimal address string "XXXX:YYYY" to an actual address.
|
||||||
|
AddressRange parseSingleAddress(char* addressStr) {
|
||||||
|
AddressRange range = {true, 0, 0};
|
||||||
|
if (!parseSingleAddressTo(addressStr, &range.from)) {
|
||||||
|
return (AddressRange) {false, 0, 0};
|
||||||
|
}
|
||||||
|
range.to = range.from;
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a hexadecimal address range string "XXXX:YYYY" to actual addresses.
|
||||||
|
// A single address "XXXX" is equivalent to "XXXX:XXXX", with from == to.
|
||||||
|
AddressRange parseAddressRange(char* addressStr) {
|
||||||
|
if (addressStr == NULL) {
|
||||||
|
return (AddressRange) {false, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = strlen(addressStr);
|
||||||
|
if (len != 4 && len != 9) {
|
||||||
|
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 + 4, &range.to)) {
|
||||||
|
return (AddressRange) {false, 0, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef PARSING_H_
|
||||||
|
#define PARSING_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Type definition for a command line with optional argument (actually just two pointers to strings)
|
||||||
|
typedef struct {
|
||||||
|
char* command;
|
||||||
|
char* arg;
|
||||||
|
} CommandLine;
|
||||||
|
|
||||||
|
// Type definition for address ranges (from-to)
|
||||||
|
typedef struct {
|
||||||
|
bool isValid;
|
||||||
|
address_t from;
|
||||||
|
address_t to;
|
||||||
|
} AddressRange;
|
||||||
|
|
||||||
|
void parseNextCommand();
|
||||||
|
CommandLine readNextCommand(char* buffer, uint8_t bufferLength);
|
||||||
|
CommandLine tokenizeCommand(char* cmd);
|
||||||
|
|
||||||
|
bool parseSingleAddressTo(char* addressStr, address_t* address);
|
||||||
|
AddressRange parseSingleAddress(char* addressStr);
|
||||||
|
AddressRange parseAddressRange(char* addressStr);
|
||||||
|
|
||||||
|
#endif /* PARSING_H_ */
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
#include "config.h"
|
|
||||||
#include "protocol.h"
|
|
||||||
|
|
||||||
#include "uart.h"
|
|
||||||
#include "eeprom.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
|
|
||||||
// Splits a command "CMD ARGS" to two strings "CMD" and "ARGS". Returns pointer
|
|
||||||
// to "ARGS" or NULL if no arguments were found. Changes the input string!
|
|
||||||
char* tokenizeCommand(char* cmd) {
|
|
||||||
if (cmd == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for a space character
|
|
||||||
for (char* p = cmd; *p != '\0'; p++) {
|
|
||||||
if (*p == ' ') {
|
|
||||||
// Split strings by replacing the space by \0, then return pointer
|
|
||||||
// to command arguments
|
|
||||||
*p++ = '\0';
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No space character found: command has no arguments, return NULL
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads, parses and executes next command
|
|
||||||
void parseNextCommand() {
|
|
||||||
const int bufferLength = 80;
|
|
||||||
char buffer[bufferLength];
|
|
||||||
|
|
||||||
// Read next command
|
|
||||||
int readChars = uartGetLine(buffer, bufferLength);
|
|
||||||
|
|
||||||
// Check if line is non-empty and has been read completely
|
|
||||||
if (readChars == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (readChars >= bufferLength-1) {
|
|
||||||
// Reading was aborted after bufferLength-1 characters to prevent
|
|
||||||
// buffer overflow.
|
|
||||||
// TODO Actually this isn't quite correct: if exactly bufferLen-1
|
|
||||||
// characters have been read including the \n, this could be
|
|
||||||
// true as well... test this?
|
|
||||||
uartPutString("ERROR buffer overflow while reading line\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tokenize command
|
|
||||||
char* cmd = buffer;
|
|
||||||
char* args = tokenizeCommand(cmd);
|
|
||||||
|
|
||||||
// Parse command
|
|
||||||
if (strcmp(cmd, "HELLO") == 0) {
|
|
||||||
// HELLO command: initializes connection
|
|
||||||
uartPutString("OHAI\r\n");
|
|
||||||
}
|
|
||||||
else if (strcmp(cmd, "READ") == 0) {
|
|
||||||
// READ command: takes a hex address or address range as argument,
|
|
||||||
// reads data and returns them in hexadecimal ASCII format.
|
|
||||||
|
|
||||||
// Check if arguments exist
|
|
||||||
if (args == NULL) {
|
|
||||||
uartPutString("ERROR READ needs an address\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse address(es)
|
|
||||||
// TODO
|
|
||||||
uartPutString(args);
|
|
||||||
|
|
||||||
// Read...
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
else if (strcmp(cmd, "TESTREAD") == 0) {
|
|
||||||
// TESTREAD command: for testing purposes, reads a few bytes and
|
|
||||||
// returns them in a human readable format.
|
|
||||||
|
|
||||||
uint8_t byte;
|
|
||||||
char outBuffer[20];
|
|
||||||
|
|
||||||
eepromSetReadMode();
|
|
||||||
|
|
||||||
for (int i = 0x00; i < 0x20; i++) {
|
|
||||||
itoa(i, outBuffer, 16);
|
|
||||||
uartPutString("TESTREAD 0x");
|
|
||||||
uartPutString(outBuffer);
|
|
||||||
uartPutString(": ");
|
|
||||||
|
|
||||||
byte = eepromReadByte(i);
|
|
||||||
itoa(byte, outBuffer, 16);
|
|
||||||
|
|
||||||
uartPutChar(byte);
|
|
||||||
uartPutString(" (0x");
|
|
||||||
uartPutString(outBuffer);
|
|
||||||
uartPutString(")\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(cmd, "TESTWRITE") == 0) {
|
|
||||||
// TESTWRITE command: for testing purposes, writes a few bytes
|
|
||||||
|
|
||||||
char str[] = "Ohai world";
|
|
||||||
address_t addr = 0x00;
|
|
||||||
|
|
||||||
char* writeStr = str;
|
|
||||||
if (args != NULL) {
|
|
||||||
writeStr = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
uartPutString("TESTWRITE success\r\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// unknown command: return error message
|
|
||||||
uartPutString("ERROR invalid command\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runs main loop to parse commands
|
|
||||||
void protocolMainLoop() {
|
|
||||||
while(1) {
|
|
||||||
// Parse next command
|
|
||||||
parseNextCommand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#ifndef PROTOCOL_H_
|
|
||||||
#define PROTOCOL_H_
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "protocol.h"
|
|
||||||
|
|
||||||
#include "uart.h"
|
|
||||||
#include "eeprom.h"
|
|
||||||
|
|
||||||
// Reads, parses and executes next command
|
|
||||||
void parseNextCommand();
|
|
||||||
|
|
||||||
// Runs main loop to parse commands
|
|
||||||
void protocolMainLoop();
|
|
||||||
|
|
||||||
#endif /* PROTOCOL_H_ */
|
|
||||||
Loading…
Reference in New Issue