diff --git a/arduino_programs/arduino_programmer/arduino_programmer.ino b/arduino_programs/arduino_programmer/arduino_programmer.ino index ae1674d..d6e5065 100644 --- a/arduino_programs/arduino_programmer/arduino_programmer.ino +++ b/arduino_programs/arduino_programmer/arduino_programmer.ino @@ -23,6 +23,60 @@ bool isFirstWrite = true; static char printBuff[128]; +void program(); +void dump(); + +void dumpFirts256Bytes() { + byte data; + Serial.println("Reading EEPROM"); + for (int addr = 0; addr < 256; addr += 16) { + sprintf(printBuff, "%04x:", addr); + Serial.print(printBuff); + for (int offset = 0; offset < 16; offset++) { + sprintf(printBuff, " %02x", readEEPROM(addr + offset)); + Serial.print(printBuff); + } + Serial.println(); + } +} + +void setup() { + // put your setup code here, to run once: + pinMode(SHIFT_DATA, OUTPUT); + pinMode(SHIFT_CLK, OUTPUT); + pinMode(SHIFT_LATCH, OUTPUT); + + digitalWrite(EEPROM_WE, HIGH); + pinMode(EEPROM_WE, OUTPUT); + + // Setting an invalid value. + lastOp = -1; + + Serial.begin(115200); +} + +void loop() { + static byte command; + // The loop function only process commands. + while (Serial.available() == 0); + + command = Serial.read(); + + switch(command) { + case 0x00: + // Program the eeprom. + program(); + break; + case 0x01: + // Dump the eeprom. + dump(); + break; + default: + // Ignore invalid commands. + break; + } +} + void latchOutput() { static byte latchMask = 0b00010000; @@ -119,12 +173,6 @@ byte readEEPROM(int address) { return readBus(address); } - -/** - * Writes a single byte of data to the specified address. - * If cooldown is true, the function adds a delay to avoid - * reading incorrect data after a write. - */ void writeEEPROM(int address, byte data, bool pollOnPageChange) { // Since we're performing page writes, we must poll the data when we change page. if ( @@ -176,47 +224,36 @@ void disableSoftwareProtection() { delay(10); } -void dumpFirts256Bytes() { - byte data; - Serial.println("Reading EEPROM"); - for (int addr = 0; addr < 256; addr += 16) { - sprintf(printBuff, "%04x:", addr); - Serial.print(printBuff); - for (int offset = 0; offset < 16; offset++) { - sprintf(printBuff, " %02x", readEEPROM(addr + offset)); - Serial.print(printBuff); - } - Serial.println(); +void program() { + // For now, the programmer will always write to the whole eeprom. + byte value; + // The program will write byte by byte. + for (long addr = 0; addr < 32768; addr++) { + // Wait for next value. + while(Serial.available() == 0); + value = Serial.read(); + writeEEPROM(addr, value, true); + // Send ack. + Serial.write(value); } } -void writeFirst256Bytes() { - Serial.println("Writing EEPROM"); - for (uint16_t addr = 0; addr < 256; addr++) { - writeEEPROM(addr, 255 - addr, true); +void dump() { + long startAddress = 0; + long byteCount = 0; + byte value; + // Wait and read the starting address to dump. + while (Serial.available() < 2); + startAddress |= Serial.read(); + startAddress |= Serial.read() << 8; + + // Wait and read the byte count. + while (Serial.available() < 2); + byteCount |= Serial.read(); + byteCount |= Serial.read() << 8; + + for (int address = startAddress; address < startAddress + byteCount; address++ ) { + value = readEEPROM(address); + Serial.write(value); } } - -void setup() { - // put your setup code here, to run once: - pinMode(SHIFT_DATA, OUTPUT); - pinMode(SHIFT_CLK, OUTPUT); - pinMode(SHIFT_LATCH, OUTPUT); - - digitalWrite(EEPROM_WE, HIGH); - pinMode(EEPROM_WE, OUTPUT); - - // Setting an invalid value. - lastOp = -1; - - Serial.begin(115200); - - writeFirst256Bytes(); - Serial.println("Done writiing."); - dumpFirts256Bytes(); -} - -void loop() { - // put your main code here, to run repeatedly: - -} diff --git a/cli/cli.py b/cli/cli.py index e69de29..312eac6 100644 --- a/cli/cli.py +++ b/cli/cli.py @@ -0,0 +1,130 @@ +import argparse +import time +import serial + + +def get_parsed_args(): + + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers(title="Operation to perform", dest="operation") + + program_parser = subparsers.add_parser("program") + dump_parser = subparsers.add_parser("dump") + + # Parser for the "program" subcommand. + program_parser.add_argument( + "-f", + "--file", + help="Binary file containing the program", + type=argparse.FileType("rb"), + required=True, + ) + + program_parser.add_argument( + "-p", "--port", help="Serial port where programmer is located", required=True + ) + + # Parser for the dump subcommand. + dump_parser.add_argument( + "-f", + "--file", + help="The file where the binary dump will be stored", + type=argparse.FileType("wb"), + required=True, + ) + + dump_parser.add_argument( + "-p", "--port", help="Serial port where programmer is located", required=True + ) + + dump_parser.add_argument( + "-s", + "--start", + help="The address where to start dumping", + type=int, + required=True, + ) + + dump_parser.add_argument( + "-c", + "--byte-count", + help="The amount of bytes to dump", + type=int, + required=True, + ) + + dump_parser.add_argument( + "--display", + help="Print the dump to the screen after storing it to the file", + action="store_true", + ) + return parser.parse_args() + + +def program(args): + print("Programming...") + with serial.Serial(args.port, 115200) as ser: + # Give a chance to the arduino to reset. + # TODO: Arduino resets by default when opening a serial + # connection, there's ways to avoid this. Investigate more. + time.sleep(2) + + # Sending command + ser.write((0).to_bytes(1, "big")) + + bytesToWrite = args.file.read() + # Forward the bytes from the selected file + for i in range(32 * 1024): + # Show progress. + if i % 1024 == 0: + print(".", end="") + value = (bytesToWrite[i]).to_bytes(1, "big") + ser.write(value) + if value != ser.read(): + # There was an error with the ack, finish early. + break + print("Done programming!") + + +def dump(args): + print("Dumping...") + with serial.Serial(args.port, 115200) as ser: + address = int(args.start) + byte_count = int(args.byte_count) + + # Give a chance to the arduino to reset. + # TODO: Arduino resets by default when opening a serial + # connection, there's ways to avoid this. Investigate more. + print("Waiting for the arduino to reset...") + time.sleep(2) + + # Sending command + ser.write((1).to_bytes(1, "big")) + + # Sending address, low byte first. + ser.write((address & 0xFF).to_bytes(1, "big")) + ser.write(((address & 0xFF00) >> 8).to_bytes(1, "big")) + # Sending byte count, low byte first. + ser.write((byte_count & 0xFF).to_bytes(1, "big")) + ser.write(((byte_count & 0xFF00) >> 8).to_bytes(1, "big")) + + # Read the stream coming from the Arduino and forward them + # to the user-selected dump file. + for _ in range(byte_count): + args.file.write(ser.read()) + print("Done dumping!") + + +def main(): + args = get_parsed_args() + + if args.operation == "program": + program(args) + elif args.operation == "dump": + dump(args) + else: + print("Unrecognized command, exiting now...") + + +if __name__ == "__main__": + main() diff --git a/cli/dump.bin b/cli/dump.bin new file mode 100644 index 0000000..fdd2a6b Binary files /dev/null and b/cli/dump.bin differ diff --git a/cli/program.bin b/cli/program.bin new file mode 100644 index 0000000..e05b194 Binary files /dev/null and b/cli/program.bin differ