Author Archives: Allen Huffman

About Allen Huffman

Co-founder of Sub-Etha Software.

Kugoo G5 electric scooter problems.

Updates:

  • 2025-05-15 – The stem/post of my G5 broke. I no longer have a working G5, and have not been able to find any source for replacement parts. I now am trying a Segway Max G3 but the throttle control on it is awful.

I received a Kugoo G5 electric scooter to review. It seems to have died after a few minutes. And I can’t find any references to it anywhere on YouTube or the internet beyond a bunch of Kugoo websites, Alibaba and Amazon. This, this post.

When powering up, the display and lights come on for a second, there is a beep, then it shuts back off. The app can still connect via Bluetooth, but trying to power up via the app has the same result.

It’s weird not being able to find something on the internet.

I have been making a list of errors in the manual, as well, which I will provide back to Kugoo when the review is complete. Assuming their support responds and can get this review unit running for me.

Here is a Facebook group I created just for discussing this model. So far, no one has found it…

https://www.facebook.com/groups/1451645235237571/

Kugoo G5 electric scooter (non functional)

Tackling the Logiker Vintage Computing Christmas Challenge 2021 follow-up

Previously I discussed several approaches to printing out the Christmas tree pattern for this challenge.

The method that produced the smallest Color BASIC program looked like this:

0 FORC=1TO14:W=ASC(MID$("ACEGCGKOEKQWCC",C,1))-64:PRINTTAB(16-W/2)STRING$(W,42):NEXT

That uses 66 byte of BASIC program space (though will use more RAM for strings as it runs).

It appears there are still optimizations to make! In the comments. Stewart Orchard pointed out this one:

Not a big gain but two bytes can be saved by removing the third argument from MID$().

The two argument version of MID$() returns the remainder of the string starting from the specified position, and ASC() returns its result based on the first character of its argument.

– Stewart Orchard

In Color BASIC, MID$ can accept three parameters:

Color Computer 3 BASIC Quick Reference Guide, page 11

If you had as string of 10 characters, and wanted to print the third character, you could do it like this:

A$="ABCDEFGHIJ"
OK
PRINT MID$(A$,3,1)
C

Stewart pointed out that if you left off the final parameter, it returns the rest of the string:

A$="ABCDEFGHIJ"
OK
PRINT MID$(A$,3,1)
CDEFGHIJ

Now that I look at it, it appears MID$ with two parameters is sort of like an inverted RIGHT$. MID$ would give you all the characters starting at the one you specify, and RIGHT$ gives you the number of ending characters you specify.

PRINT MID$(A$,3)
CDEFGHIJ

PRINT RIGHT$(A$,3)
HIJ

I don’t recall using MID$ like this, but I have simulated the same behavior using RIGHT$ like:

PRINT RIGHT$(A$,LEN(A$)-3+1)
CDEFGHIJ

PRINT MID$(A$,3)
CDEFGHIJ

I am a bit embarrassed to admit I think I even did something like this:

PRINT MID$(A$,3,LEN(A$)-3)
CDEFGHIJ

…but let’s not speak of that.

And if MID$ can work like RIGHT$, it can also work like LEFT$:

PRINT LEFT$(A$,3)
ABC

PRINT MID$(A$,1,3)
ABC

But I digress…

If MID$(A$,3,1) gives you one character starting as location 3, and MID$(A$,3) gives you all the characters starting at position 3, how does that work? Stewart explained that ASC will still work if you pass it a string since it only works on the first character of the string. It is even documented that way:

Thus, ASC(“HELLO”) produces the same result as ASC(“H”) — the ASCII value of letter H.

With that in mind, we can remove “,1” from the program and reduce it by two bytes:

0 FORC=1TO14:W=ASC(MID$("ACEGCGKOEKQWCC",C))-64:PRINTTAB(16-W/2)STRING$(W,42):NEXT

64 bytes!

Thank you, Stewart, for leaving that comment.

Until next time…

Tackling the Logiker Vintage Computing Christmas Challenge 2021

Another programming challenge seems to be occupying folks this Christmas season:

http://logiker.com/Vintage-Computing-Christmas-Challenge-2021

The challenge is simple: Write a program that prints out a centered text Christmas tree using the same layout of their example program. I thought it would be fun to work through several methods to do this.

PRINT

We start with their simple example, which displays the centered tree using PRINT statements. Here is their example with spaces altered so it centers on the CoCo’s 32 column screen:

100 PRINT "               *
110 PRINT "              ***
120 PRINT "             *****
130 PRINT "            *******
140 PRINT "              ***
150 PRINT "            *******
160 PRINT "          ***********
170 PRINT "        ***************
180 PRINT "             *****
190 PRINT "          ***********
200 PRINT "       *****************
210 PRINT "    ***********************
220 PRINT "              ***
230 PRINT "              ***

386 bytes.

You will see one memory optimization they did was leaving off the ending quote. BASIC will stop parsing a quoted string if it reaches the end of a line, so the ending quote is only necessary if more statements follow the PRINT.

I do not know if the space between PRINT and the quote is required for the system they wrote this example, but on the CoCo we could remove it and save 23 bytes of program space right there.

Speaking of spaces, each space takes up a character. BASIC has a command that will jump forward a certain amount of spaces — TAB. It works like this:

PRINT TAB(5);"FIVE SPACES OVER"

From my test, it appears TAB takes up one byte(for the “TAB(” portion, then a byte for each digit, then a byte for the closing parenthesis. If tabbing a single digit of spaces, it takes three bytes of program space. Thus, any time we are spacing over more than 3 spaces, it would save memory to use TAB. Also, the semicolon between TAB and the item being printed is optional, so we can leave that out as well.

For the tree example centered on a 32 column screen, every line starts with at least 4 spaces, so using TAB should save memory. Let’s try this:

100 PRINT TAB(15)"*
110 PRINT TAB(14)"***
120 PRINT TAB(13)"*****
130 PRINT TAB(12)"*******
140 PRINT TAB(14)"***
150 PRINT TAB(12)"*******
160 PRINT TAB(10)"***********
170 PRINT TAB(8)"***************
180 PRINT TAB(13)"*****
190 PRINT TAB(10)"***********
200 PRINT TAB(7)"*****************
210 PRINT TAB(4)"***********************
220 PRINT TAB(14)"***
230 PRINT TAB(14)"***

279 bytes.

That looks icky, but produces the same result with less code space.

Pattern Matching

If we take a look at the tree design, we see it has a pattern to how each of the three seconds is printed:

           *            1
          ***           3
         *****          5
        *******         7
          ***           3
        *******         7
      ***********       11
    ***************     15
         *****          5
      ***********       11
   *****************    17
*********************** 23
          ***           3
          ***           3

It is drawing three sections, with the first expanding on each side by 1 (adding two asterisks to each row), then the next section expanded each side by 2 (adding four asterisks to each row), then the final section expands each side by 3 (adding six asterisks to each row).

There is probably a simple way to math it. But first…

Centering

Since one of the requirements is centering the tree on the screen, let’s look at how we center a string. To do this, we simply subtract the length of the string we want to center from the width of the string then divide the result by two:

A$="CENTER THIS"
PRINT TAB((32-LEN(A$))/2);A$

Or, to eliminate some parenthesis, we can start with half the width of the screen (the center of the screen) and subtract half the length of the string:

A$="CENTER THIS"
PRINT TAB(16-LEN(A$)/2);A$

With that out of the way, now we need to figure out how to draw the three triangle shapes of the tree, each time getting wider.

Numbers and patterns.

I decided to lookat the number sequences of each line length for each section of the tree (skipping the trunk lines).

Section 1: 1  3  5  7
Section 2: 3  7 11 15
Section 3: 5 11 17 23

I could easily create the first pattern by doing a FOR/NEXT loop with a step of 2:

FOR I=1 TO 7 STEP 2:PRINT I:NEXT

And then I could do 3 to 15 with a STEP 4, and 5 to 23 with a STEP 6.

FOR I=1 TO 7 STEP 2:PRINT I:NEXT
FOR I=3 TO 15 STEP 4:PRINT I:NEXT
FOR I=5 TO 23 STEP 6:PRINT I:NEXT

This would generate the number sequence I need, and then I could simply print a centered string of that many asterisks, and manually print the tree trunk at the end.

10 FOR I=1 TO 7 STEP 2:GOSUB 50:NEXT
20 FOR I=3 TO 15 STEP 4:GOSUB 50:NEXT
30 FOR I=5 TO 23 STEP 6:GOSUB 50:NEXT
40 I=3:GOSUB 50:GOSUB 50:END
50 PRINT TAB(16-I/2)STRING$(I,42):RETURN

127 bytes.

That’s much better! Though, I saved a bit more by combining lines, and I could save even more by removing spaces and combining lines further:

10 FORI=1TO7STEP2:GOSUB50:NEXT:FORI=3TO15STEP4:GOSUB50:NEXT:FORI=5TO23STEP6:GOSUB50:NEXT:I=3:GOSUB50:GOSUB50:END
50 PRINTTAB(16-I/2)STRING$(I,42):RETURN

(Compressed down to 94 bytes.)

Now we’re getting somewhere! But ignoring the compressing, can we do better than 127 using better math?

Math. Why did there have to be math?

I am slow and bad at math, but I am convinced there is a math solution to this, as well.

Let’s look at how the numbers for START value and STEP value work. I know there are going to be three sections of the tree, so it seems logical I’d start with something like this:

10 FOR I=1 TO 3
20 PRINT I*2-1
30 NEXT

That would print out 1, 3 and 5, which is the start width of each section of the tree. I could have also done the FOR loop using 0 to 2 and added 1 to get the same result:

10 FOR I=0 TO 2
20 PRINT I*2+1
30 NEXT

Maybe one will be more useful than the other depending on what comes next…

Once we know how wide a section starts, we need to know how much the length increases for each line.

Section 1 increases by 2 each row, section 2 increases by 4 each row, and section 3 increases by 6 each row. That is a pattern of 2, 4, 6. It looks like I could get those values by taking the section (1 to 3) and multiplying it by 2. This will print 2, 4, 6:

10 FOR J=1 TO 3
20 PRINT J*2
30 NEXT

I am bad with math, as I mentioned, but I was able to work out that taking a value of 1 to 4 (for each layer of a section) and multiply that by the section (1 to 3), and subtracting one, I could get this:

10 FOR I=1 TO 3
20 FOR J=1 TO 4
30 PRINT J*I*2-1
60 NEXT
70 NEXT

The math looks like this:

 J * I       * 2       - 1
-------   -------   -------
(1 * 1) = (1 * 2) = (2 - 1) = 1
(2 * 1) = (2 * 2) = (4 - 1) = 3
(3 * 1) = (3 * 2) = (6 - 1) = 5
(4 * 1) = (4 * 2) = (8 - 1) = 7

(1 * 2) = (2 * 2) = (4 - 1) = 3
(2 * 2) = (4 * 2) = (8 - 1) = 7
(3 * 2) = (6 * 2) = (12 - 1) = 11
(4 * 2) = (8 * 2) = (16 - 1) = 15

(1 * 3) = (3 * 2) = (6 - 1) = 5
(2 * 3) = (6 * 2) = (12 - 1) = 11
(3 * 3) = (9 * 2) = (18 - 1) = 17
(4 * 3) = (12 * 2) = (24 - 1) = 23

…and that gets our number sequence we want:

Section 1: 1  3  5  7
Section 2: 3  7 11 15
Section 3: 5 11 17 23

To print the row of asterisks, I use the STRING$ function. It takes the number of characters to print, then the ASCII value of the character. The asterisk is ASCII character 42 so it I wanted to print ten of them I would do:

PRINT STRING$(10,42)

I can now print the layers of the tree like this:

10 FOR I=1 TO 3
20 FOR J=1 TO 4
30 W=J*I*2-1
50 PRINT TAB(16-W/2);STRING$(W,42)
60 NEXT
70 NEXT

But that still doesn’t handle the “trunk” at the bottom of the tree.

Since the trunk does not follow any pattern, I will simply treat it like an extra section, and increase the section loop (FOR I) by one, and add an IF that says if we are on that layer, the width will be 3. Then, since I don’t want this section to be four layers thick, I can use a second IF after the one that checks for the fourth section to know when to exit (checking for J to be larger than 2):

10 FOR I=1 TO 4
20 FOR J=1 TO 4
30 W=J*I*2-1
40 IF I>3 THEN W=3:IF J>2 THEN END
50 PRINT TAB(16-W/2);STRING$(W,42)
60 NEXT
70 NEXT

162 bytes.

Ah, well, being clever seems to have increase beyond the 127 bytes of just using three FOR/NEXT loops. I suspect it’s the overhead of the way I am trying to print the trunk section. Indeed, without it (like 40, above, and adjusting the I loop to 3) makes it 125.

Sometimes being clever doesn’t help. Even without trying to be clever about the trunk section, the “W=J*I*2-1” stuff takes up as much space as just doing another FOR/NEXT and a GOSUB to print the line.

DATA

We could just have a table to line lengths, and do it like this:

10 READ W
20 IF W=0 THEN END
30 PRINT TAB(16-W/2);STRING$(W,42):GOTO 10
40 DATA 1,3,5,7,3,7,11,16,5,9,13,17,3,3,

98 bytes.

Not bad at all! And that is before compressing it to fewer lines. Here’s a 79 byte attempt, removing spaces, removing the semicolon, altering the logic just a bit to be on LINE 0 (so you can just say GOTO) and changing the IF so there is no END token:

0 READW:IFW>0THENPRINTTAB(16-W/2)STRING$(W,42):GOTO:DATA1,3,5,7,3,7,11,16,5,9,13,17,3,3,

Another “DATA” technique which I have seen Jim Gerrie use is to simply encode the line lengths as characters in a string, and use that as data. For example, ASCII “A” (character 65) will represent 1, “B” will represent 2, and so on. Make a string of the appropriate characters and retrieve them using MID$() and get the ASCII value using ASC() then subtract 64 from that value and you have something like this.

10 FOR C=1 TO 14
20 W=ASC(MID$("ACEGCGKOEKQWCC",C,1))-64
30 PRINT TAB(16-W/2);STRING$(W,42)
40 NEXT

97 bytes.

If we compress the lines together, we can shrink it even further:

10 FORC=1TO14:W=ASC(MID$("ACEGCGKOEKQWCC",C,1))-64:PRINTTAB(16-W/2)STRING$(W,42):NEXT

66 bytes!

Is this as small as it gets? (Technically, this uses more memory, since string space has to be used to create temporary strings for MID$(), but we are only looking at program size and not memory usage.)

What else can we try? Leave a comment.

Until next time…

The mind blowingness of Spatial Audio

Although I had heard of this new-fangled “spatial audio” now supported by Apple, my devices are all so old they are limited to good old-fashioned stereo.

And I like it that way.

I mean, just because you give “surround sound” a new name doesn’t mean I’m gonna fall for it.

And “surround sound” doesn’t work in headphones, in spite of all the demos trying to convince you that this ultra-separated stereo recording can make you think a sound is coming from in front of, behind, or above you.

I was wrong.

While I still don’t think headphone based “surround sound” is anything more than two-speaker stereo with fancy mixing, spatial audio turns out to be something quite different. And I discovered it by accident.

A few months ago, I picked up some Apple AirPods to use as noise cancelling headphones while spending many weeks working in a noisy warehouse. Being able to turn noise cancelling on and off was, on its own, a slight form of magic. At least, that’s how I felt when I first got to demo the BOSE noise cancelling headphones in the Denver airport two decades ago. Today, however, noise cancelling is built in to even cheap headphones.

I read that these AirPods supported spatial audio, but when I tried to listen to the demos it just sounded like stereo to me.

New name, same scam. Or so I thought.

Later I read that spatial audio was only supported on newer devices that the ancient ones I had. This intrigued me. Why would the device’s horsepower matter?

I learned why, quite by accident.

I swear I heard something…

I got to use a new-model iPad and was watching HULU using my AirPods. I thought nothing of it, until I turned my head to look at something. I heard the sound in my right ear.

Oops. Had I actually not turned these headphones on, and was blaring HULU through the speakers? How embarrassing.

I checked and my speakers were silent. What just happened?

I resumed playing the video, this time paying attention to the sound to see if, somehow, the iPad speakers were turning on. As I turned my head to test again, the sound was heard to shift to the closer ear.

I felt a tad bit of magic, as I realized turning my head was shifting how the audio was playing, simulating listening to a TV at a fixed point in space. I had never heard anything like this before in headphones. After all, headphone sound doesn’t move.

And now I know what makes spatial audio more than just surround sound. Sensors in the headphones, combined with processing in the playback device, are able to create custom mixes of the audio as your head moves. It’s difficult to describe, beyond just saying “it’s as if the sound was real and you weren’t wearing headphones.”

If your iDevice supports it, there is even a test built in to the Bluetooth connection settings for the AirPods:

When I first tried this demo, I switched from Stereo Audio to Spatial Audio and it just sounded like a better stereo mix. But when I tried again, now aware of what spatial audio was, I found I could turn my head away from the screen and the audio mix sounded like it was coming from the screen to the left or right of me, depending on where I turned.

Magic.

Very cool magic.

While I was a two-speaker surround-sound denier (I still am), I am definitely a believer of spatial audio.

Not all apps support it, but the ones that do provide a very new experience when using headphones to listen to audio.

Until next time…

CoCo 3 and 256 colors

Apparently, if you use a composite monitor or TV set on a CoCo 3, you can just put bytes on the 640x192x4 color video mode and they create artifact color. You can get over 200 artifact colors that way with no special tricks other than a palette translation to know what byte value is what color.

Commodore VIC-20 PETSCII on the CoCo

In case you ever wondered what the VIC-20 character set would like like on a CoCo 1…

VIC-20 PETSCII (Uppercase 0-511) on a CoCo
VIC-20 PETSCII (Lowercase 0-511) on a CoCo

It would look like that.

And if you wanted to know what the VIC-20’s 22×23 screen would look like on a CoCo…

VIC-20 20×32 screen displaying PETSCII on a CoCo

That. It would look like that.

When I moved from the VIC-20 to the CoCo, I lost colors and sound, but gained a “huge” screen that was 32 columns wide instead of 22. But I lost horizontal lines (23 down to 16). It felt more usable (wider screen) but smaller.

It wasn’t until I started revisiting the VIC-20 this past year that I realized since each screen block was eight bytes tall, the VIC’s native “resolution” for that 22×23 screen would be 176×184 (22*8 by 23*8). The CoCo’s 256×192 was larger and could fit the VIC-20 screen with room to space (but without the colors).

When I tried to do a quick port of my VIC Sky-Ape-Er game, the different text resolution (22×23 versus 32×16) made all my levels need to be redesigned. It would not be the same game — but the same game engine with different sized levels that resembled the original.

It might be fun to come up with an assembly routine to handle VIC-20 custom characters on a 256×192 graphics screen. It would likely be slower (blitting out 8 bytes instead of printing one byte) than text mode, but I could then port my games over (minus color and sound) much more accurately.

Maybe some day…

There is no substitute for real hardware.

I make use of emulation regularly. While I do still have my original Radio Shack Color Computers from the 1980s, it is usually more convenient to just load up an emulator. For short experiments in BASIC, or casual game playing, this works just fine. However, emulation is not perfect and sometimes you run in to something that stands out.

Consider this…

…and this…

These purple colors were generated on the XRoar 1.0 emulator when emulating a later-model Color Computer 2 with an updated T1 version of the 6874 VGD video chip.

I had never seen such colors, but since I had never had a T1 CoCo I assumed it was just another odd secret that chip held I was just unfamiliar with.

The first sign that this might be an emulation issue was that the purple only showed up when the emulator was using simulated RF output. In that mode, it tries to replicate the fuzzy appearance of TV output. turn that simulation off and the screen changed to expected orangish reddish alternate color.

While I do not know the details on what caused this, XRoar has been updated to no longer produce these purple colors in this mode.

You can pick up the latest XRoar emulator (that adds support for the Color Computer 3 and MC-10) here:

http://www.6809.org.uk/xroar/

String space required. No exceptions.

Revisiting my Color BASIC String Theory series… Here is one to ponder…

CLEAR 0 can be used to reserve 0 bytes for string storage. With no string space, we obviously expect something like this to NOT work:

A$="THIS WON'T WORK WITH CLEAR 0"

Indeed, that would give us “?OS ERROR” — Out of string space.

The exception to this rule are “constant strings” that are embedded inside the BASIC program itself. In a YouTube video I recently posted, I demonstrated how constant strings in a program do not use string space:

You can see twenty nine other short Color BASIC videos I posted to YouTube during the month of #SepTandy 2021.

But I digress…

Here are some other things that won’t work without string space, even if, at first glance, it seems like they would:

It seems you can’t SAVE, LOAD or even PRINT a “constant” string if there is no string space.

But why?

Consider this… The same thing happens with string functions such as LEFT$, RIGHT$, MID$ and even INSTR:

Looking at those, and recalling my String Theory article, we know LEFT$, RIGHT$ and MID$ are trying to create a new string. With no string space, there is no way to create it. That must be why they fail. This makes sense.

But INSTR does not create any strings. It merely returns the position where one string appears inside of another, or 0 if the string is not found. (Or 1 if you give it an empty string, which truly does seem like a bug but other flavors Microsoft BASIC behave the same way with their implementations of INSTR. But I digress…)

And SAVE, LOAD and PRINT are similar. They just print something, not create a string.

That does not make sense.

Let’s speculate a bit.

What’s all this, then?

Without consulting the Color BASIC Unravelled disassembly, my guess is that the ROM code for SAVE, LOAD, PRINT, etc. probably expects some register to be pointing to where the string exists in memory (a location pointer in the variable data). This might be code space, in the case of a constant string embedded in a BASIC line, or string space, in the case of a dynamic string.

But when you are entering a command directly in to BASIC, there is no program memory for that command (even though it seems like it could just point to the keyboard input buffer and then make the ROM call). BASIC needs to put that constant string data somewhere before jumping to the ROM call.

That’s weird, and quite possibly unnecessary, but would, at least, make sense.

I am going to add this to my “look this up in the disassembly to see what’s going on” list for future investigation.

In the meantime … I wonder what else won’t work without string space?

Until next time…

The undocumented syntax of Extended Color BASIC



The other night I was experimenting with Extended Color BASIC and the “GET” and “PUT” commands. I knew that the documentation was incorrect about them, and was trying to figure out how they worked. I also wanted to do this without cheating (i.e., doing a quick web search and finding the results of someone who already did this).

I will share the results of this experimentation later, but I wanted to pass along something I was unaware of until last night. I ended up looking at the Extended Color BASIC disassembly to try to find clarification on why something I was seeing was happening. Reading through it revealed a syntax I was unaware of for the following commands:

  • CIRCLE
  • GET
  • LINE
  • PAINT
  • PUT

Much like the CoCo BASIC “PRINT@” command, the ‘@’ sign is allowed on these commands as well. It does nothing, and is merely skipped:

Extended Color BASIC’s unused @ syntax.

A note in the Unraveled book says:

It is interesting to note that the “@” symbol does not do anything! It is there to make the command syntax consistent with the “PRINT @” concept and to make it compatible with other versions of Microsoft BASIC.

– Extended Color BASIC Unraveled II

Since this was not documented in the manual (as far as I know), I was not aware of this syntax.

Did you know about this?

There are certainly many undocumented secrets in the Color BASIC ROMs, from the unimplemented Easter egg to things like how the PLAY command plays nonexistent notes. Certainly the author of the Unraveled series discovered these items, and anyone who read those books would have known about it, but I wonder how widespread these oddities were back in the 1980s.

Until next time…