Browse Source

tools/upload.py: support files larger than 0xff bytes

pull/10/head
Virgil Dupras 5 years ago
parent
commit
df5549ae76
2 changed files with 58 additions and 36 deletions
  1. +12
    -9
      doc/load-run-code.md
  2. +46
    -27
      tools/upload.py

+ 12
- 9
doc/load-run-code.md View File

@@ -2,7 +2,7 @@

Collapse OS likely runs from ROM code. If you need to fiddle with your machine
more deeply, you will want to send arbitrary code to it and run it. You can do
so with the shell's `load` and `call` commands.
so with the shell's `poke` and `call` commands.

For example, let's say that you want to run this simple code that you have
sitting on your "modern" machine and want to execute on your running Collapse OS
@@ -22,7 +22,7 @@ Now, we'll send that code to address `0xa000`:

> mptr a000
A000
> load 8 (resulting binary is 8 bytes long)
> poke 8 (resulting binary is 8 bytes long)

Now, at this point, it's a bit delicate. To pipe your binary to your serial
connection, you have to close `screen` with CTRL+A then `:quit` to free your
@@ -31,7 +31,7 @@ tty device. Then, you can run:
cat tosend.bin > /dev/ttyUSB0 (or whatever is your device)

You can then re-open your connection with screen. You'll have a blank screen,
but if the number of characters sent corresponds to what you gave `load`, then
but if the number of characters sent corresponds to what you gave `poke`, then
Collapse OS will be waiting for a new command. Go ahead, verify that the
transfer was successful with:

@@ -62,16 +62,19 @@ Success!

The serial connection is not always 100% reliable and a bad byte can slip in
when you push your code and that's not fun when you try to debug your code (is
this bad behavior caused by my logic or by a bad serial upload?).
this bad behavior caused by my logic or by a bad serial upload?). Moreover,
sending contents bigger than `0xff` bytes can be a hassle.

To this end, there is a `upload.py` file in `tools/` that takes care of loading
the file and verify the contents. So, instead of doing `load 8` followed by
your `cat` above, you would have done:
the file and verify the contents. So, instead of doing `mptr a000` followed by
`poke 8` followed by your `cat` above, you would have done:

./upload.py /dev/ttyUSB0 tosend.bin
./upload.py /dev/ttyUSB0 a000 tosend.bin

This emits `load` and `peek` commands and fail appropriately if the `peek`
doesn't match sent contents. Very handy.
This emits `mptr`, `poke` and `peek` commands and fail appropriately if the
`peek` doesn't match sent contents. If the file is larger than `0xff` bytes,
repeat the process until the whole file was sent (file must fit in memory space
though, of course). Very handy.

## Labels in RAM code



+ 46
- 27
tools/upload.py View File

@@ -24,41 +24,60 @@ def sendcmd(fd, cmd):
def main():
parser = argparse.ArgumentParser()
parser.add_argument('device')
parser.add_argument('memptr')
parser.add_argument('filename')
args = parser.parse_args()

try:
memptr = int('0x' + args.memptr, 0)
except ValueError:
print("memptr are has to be hexadecimal without prefix.")
return 1
if memptr >= 0x10000:
print("memptr out of range.")
return 1
maxsize = 0x10000 - memptr
st = os.stat(args.filename)
if st.st_size > 0xff:
print("File too big. 0xff bytes max")
if st.st_size > maxsize:
print("File too big. 0x{:04x} bytes max".format(maxsize))
return 1
fd = os.open(args.device, os.O_RDWR)
sendcmd(fd, 'poke {:x}'.format(st.st_size).encode())
print("Poking...")
with open(args.filename, 'rb') as fp:
fcontents = fp.read()
for c in fcontents:
os.write(fd, bytes([c]))
# Let's give the machine a bit of time to breathe. We ain't in a
# hurry now, are we?
time.sleep(0.0001)
print("Poked")
os.read(fd, 5)
print("Peeking back...")
sendcmd(fd, 'peek {:x}'.format(st.st_size).encode())
peek = b''
while len(peek) < st.st_size * 2:
peek += os.read(fd, 1)
time.sleep(0.0001)
while True:
fcontents = fp.read(0xff)
if not fcontents:
break
print("Seeking...")
sendcmd(fd, 'mptr {:04x}'.format(memptr).encode())
os.read(fd, 9)
sendcmd(fd, 'poke {:x}'.format(len(fcontents)).encode())
print("Poking...")
for c in fcontents:
os.write(fd, bytes([c]))
# Let's give the machine a bit of time to breathe. We ain't in a
# hurry now, are we?
time.sleep(0.0001)
print("Poked")
os.read(fd, 5)
print("Peeking back...")
sendcmd(fd, 'peek {:x}'.format(len(fcontents)).encode())
peek = b''
while len(peek) < len(fcontents) * 2:
peek += os.read(fd, 1)
time.sleep(0.0001)
os.read(fd, 5)
print("Got {}".format(peek.decode()))
print("Comparing...")
for i, c in enumerate(fcontents):
hexfmt = '{:02X}'.format(c).encode()
if hexfmt != peek[:2]:
print("Mismatch at byte {}! {} != {}".format(i, peek[:2], hexfmt))
return 1
peek = peek[2:]
print("All good!")
memptr += len(fcontents)
print("Done!")
os.close(fd)
print("Got {}".format(peek.decode()))
print("Comparing...")
for i, c in enumerate(fcontents):
hexfmt = '{:02X}'.format(c).encode()
if hexfmt != peek[:2]:
print("Mismatch at byte {}! {} != {}".format(i, peek[:2], hexfmt))
return 1
peek = peek[2:]
print("All good!")
return 0

if __name__ == '__main__':


Loading…
Cancel
Save