I know, this is silly, but I'm moving tools to something a bit closer to the system. I consider perl to be more system-like than python for a simple reason: perl is part of the OpenBSD base system and python is not. Also, I'm learning perl and using this as an opportunity.pull/85/head
@@ -0,0 +1,79 @@ | |||
#!/usr/bin/perl | |||
# Push specified file to specified device **running the BASIC shell** and verify | |||
# that the sent contents is correct. | |||
use strict; | |||
use Fcntl; | |||
if (@ARGV != 3) { | |||
print "Usage: ./uploadb.pl device memptr filename\n"; | |||
exit 1; | |||
} | |||
my ($device, $memptr, $fname) = @ARGV; | |||
if (hex($memptr) >= 0x10000) { die "memptr is out of range"; } | |||
if (! -e $fname) { die "${fname} does not exist"; } | |||
my $fsize = -s $fname; | |||
my $maxsize = 0x10000 - hex($memptr); | |||
if ($fsize > $maxsize) { die "File too big. ${maxsize} bytes max"; } | |||
my $fh; | |||
unless (open($fh, '<', $fname)) { die "Can't open $fname"; } | |||
my $devh; | |||
unless (sysopen($devh, $device, O_RDWR|O_NOCTTY)) { die "Can't open $device"; } | |||
sub sendcmd { | |||
# The serial link echoes back all typed characters and expects us to read | |||
# them. We have to send each char one at a time. | |||
my $junk; | |||
foreach my $char (split //, shift) { | |||
syswrite $devh, $char; | |||
sysread $devh, $junk, 1; | |||
} | |||
syswrite $devh, "\n"; | |||
sysread $devh, $junk, 2; # send back \r\n | |||
} | |||
sendcmd("m=0x${memptr}"); | |||
my $rd; | |||
sysread $devh, $rd, 2; # read prompt | |||
# disable buffering | |||
$| = 1; | |||
while (sysread $fh, my $char, 1) { | |||
print "."; | |||
for (my $i=0; $i<5; $i++) { # try 5 times | |||
sendcmd("getc"); | |||
syswrite $devh, $char; | |||
sysread $devh, $rd, 2; # read prompt | |||
sendcmd("print a"); | |||
my $s = ""; | |||
while (1) { | |||
sysread $devh, $rd, 1; | |||
if ($rd !~ /\d/) { last; } | |||
$s .= $rd; | |||
} | |||
sysread $devh, $rd, 3; # read prompt | |||
if ($s == ord($char)) { | |||
last; | |||
} else { | |||
if ($i < 4) { | |||
print "Mismatch at byte ${i}! ${s} != ${ord($char)}. Retrying.\n"; | |||
} else { | |||
die "Maximum retries reached, abort.\n"; | |||
} | |||
} | |||
} | |||
sendcmd("poke m a"); | |||
sysread $devh, $rd, 2; # read prompt | |||
sendcmd("m=m+1"); | |||
sysread $devh, $rd, 2; # read prompt | |||
} | |||
print "Done!\n"; | |||
close $fh; | |||
close $devh; |
@@ -1,79 +0,0 @@ | |||
#!/usr/bin/env python3 | |||
# Push specified file to specified device **running the BASIC shell** and verify | |||
# that the sent contents is correct. | |||
import argparse | |||
import os | |||
import sys | |||
def sendcmd(fd, cmd): | |||
# The serial link echoes back all typed characters and expects us to read | |||
# them. We have to send each char one at a time. | |||
if isinstance(cmd, str): | |||
cmd = cmd.encode() | |||
for c in cmd: | |||
os.write(fd, bytes([c])) | |||
os.read(fd, 1) | |||
os.write(fd, b'\n') | |||
os.read(fd, 2) # sends back \r\n | |||
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 > maxsize: | |||
print("File too big. 0x{:04x} bytes max".format(maxsize)) | |||
return 1 | |||
fd = os.open(args.device, os.O_RDWR) | |||
with open(args.filename, 'rb') as fp: | |||
fcontents = fp.read() | |||
sendcmd(fd, f'm=0x{memptr:04x}') | |||
os.read(fd, 2) # read prompt | |||
for i, c in enumerate(fcontents): | |||
c = bytes([c]) | |||
print('.', end='', flush=True) | |||
for _ in range(5): # try 5 times | |||
sendcmd(fd, 'getc') | |||
os.write(fd, c) | |||
os.read(fd, 2) # read prompt | |||
sendcmd(fd, 'print a') | |||
s = b'' | |||
while True: | |||
r = os.read(fd, 1) # putc result | |||
if not r.isdigit(): | |||
break | |||
s += r | |||
os.read(fd, 3) # read prompt | |||
if int(s) == c[0]: | |||
break | |||
else: | |||
print(f"Mismatch at byte {i}! {c} != {r}. Retrying") | |||
else: | |||
print("Maximum retries reached, abort") | |||
return 1 | |||
sendcmd(fd, 'poke m a') | |||
os.read(fd, 2) # read prompt | |||
sendcmd(fd, 'm=m+1') | |||
os.read(fd, 2) # read prompt | |||
print("Done!") | |||
os.close(fd) | |||
return 0 | |||
if __name__ == '__main__': | |||
sys.exit(main()) |