Good points, Brian! I like the idea of using "!" so as to have fewer
special cases. I changed my co2do <https://github.com/hackerb9/co2do/>
script to match, kinda. I don’t quote spaces (32) or tab (9) which makes
the loader slightly smaller and that’s where the space matters.

One tricky thing is that Stephen started out the email thread by saying
±64, as you implemented, but then gave code showing ±128. I used the latter
approach because it tickles me that adding 128 and subtracting 128 are
actually equivalent — and the same as xor — modulo 256. It also suggests
that there could be an efficient 8085 implementation, which may be
necessary for me (see below).

Using ±128 meant the EOF signal, ‘!\xFF’, was needed to encode Delete
(127), which I’m actually fine with. If there’s going to be an EOF marker,
I think it should be truly invalid (POKEing a negative number would cause a ?FC
Error) instead of merely nonsensical. Like you, I doubted the need for an
EOF character, but left it in as I figured Stephen probably had more
experience than me on this.

By the way, I’m not sure if this will come back to bite me later, but I’m
also appending ^Z at the end of the .DO file, which makes it trivial to
send to the Model T without any transfer program.

RUN "COM:88N1"
cat FOO.DO >/dev/ttyUSB0

Even though the encoding is fairly efficient, it could be better. Very few
control characters actually need to be quoted over the serial line: they
actually get lost in tokenization. But the biggest issue is that the data
in the BASIC program takes up RAM, potentially making it impossible to
CLEAR enough space for the .CO. That means that many .CO files which could
run fine on an 8K machine, will fail to load. I wonder if there’s a way to
make a less RAM hungry loader which is as simple to use as the RUN/cat
example above.

For instance, instead of having a large BASIC program in memory with the
entire .CO file encoded in it, perhaps it could be two stages, with the
first being a minimal program that receives the .CO file over the serial
port and POKEs it directly into the correct location. Essentially, what I
want is for RUNM "COM:98N1" to actually work, with the one addition that it
would call CLEAR first based on the .CO header.

I don’t know how to do this yet or if it is even possible. Perhaps, if the
.DO file had an embedded ^Z so that the BASIC program could start executing
and reading the rest of the data…. I know, I know. It’d be too slow. Just
brainstorming. Maybe if I could pop into machine language quickly enough...
Hrm. I may have to give up on the idea of making it as convenient as
RUN/cat.

Any suggestions/solutions are welcome!

—b9

On Tue, Feb 24, 2026 at 2:59 PM Brian K. White <[email protected]> wrote:

> On 2/18/26 17:21, B 9 wrote:
> > Uses Stephen's encoding with some tweaks. (Main difference is that the
> > end of data flag is changed to be an invalid sequence, "//", so that DEL
> > can be encoded).
>
> I had the same initial thought about /255 as I was converting co2ba.sh
> to use Steve's method.
>
> "/ÿ"  (/255) does not mean that you can't have an actual 255 in the
> payload.
>
> First, a /255 in the encoded data doesn't conflict with anything in the
> payload because the payload only ever has /0+64 to /34+64 and /47+64 (/@
> to /b and /o).
>
> No other byte values will have a / in the first place.
>
> Also, the decoder always subtracts 64 from the value to undo the fact
> that the encoder added it to turn a control byte into a safe byte.
>
> So even if a /255 were meant to be an encoded byte of payload, /ÿ would
> decode to 255-64=191, but real 191 bytes are not encoded in the first
> place. Nor are real 255 bytes.
>
> So it's no risk or conflict to treat /255 (or /anything other than
> 0-31,34,47) for some other special purpose like end-of-data.
>
>
> In my case, I'm using ! (33) as the escape char instead of / (47), and
> just converting everything from 0-34 instead of adding a special cases
> for " and /.
>
> If I want the least encoder code, say for running on the 100 in the
> smallest possible routine, I can just encode everything from 0-34 and
> accept that 32's are encoded when they wouldn't need to be. Or if I want
> the smallest output I can add that one extra step in the encoder to
> exclude 32.
>
> It simplifies both the encoder and decoder slightly.
>
> Also in my case I'm dispensing with the /255 eof mechanism altogether
> because we always know the length and can just as easily write the
> length in the output as write an eof mark. Most of the time the data
> will be a CO file which needs the length info in it's header anyway, but
> even for arbitrary binary data without a CO header, it's still both a
> simpler and more robust loop to just count from start value to end value
> instead of count forever and perform a check on every byte along the way
> to see if we got an eof, (and hope we actually do always get one!).
>
> Similarly I also write a checksum along with the length.
>
> --
> bkw
>

Reply via email to