Author Archives: Allen Huffman

About Allen Huffman

Co-founder of Sub-Etha Software.

Stranger Things 2 and BASIC and Color BASIC

Updates:

  • 4/26/2022 – Added note about IF/ENDIF via comments. Added link to YouTube video of the segment.
  • 4/27/2022 – Updated screen shots with images taken from the YouTube video (linked in this posting).

With the season four of Stranger Things coming to Netflix soon, I have been re-watching the first three seasons.

Season one is set in 1983, and one of the characters (Joyce Byers, played by Winona Ryder) is shown working at a local general store. We see that there is a Radio Shack next door to it. We also see Radio Shack walkie talkies featured in the episodes.

In Season two we meet Joyce’s boyfriend, Bob Newby (played by Sean Astin). He works at that next-door Radio Shack. There is even one scene that shows him at work, though the environment is unlike any Radio Shack I ever saw.

In season two episode eight (“The Mind Flayer”), there is a need for them to restart a computer system. Radio Shack Bob says someone needs to know BASIC to do this. (Oh, really, writers?) This leads to a scene where Bob gets the system going by … typing in a BASIC program.

Here is the clip that someone posted to YouTube. (It starts around the 15:57 mark of the full episode.)

https://youtu.be/2bRAvxSSzEU

Here is a screen shot of the code:

Stranger Things S2E8 – Around 15:57 timecode.

It is some form of BASIC I am unfamiliar with. It allows defining variables as types (INTEGER in this case) and also appears to support functions with parameters similar to C. I am unsure if this is just Hollywood hookum or if there was actually a BASIC like this that existed in 1984 when Season 2 is set.

Here is a close-up of the code taken from the YouTube video (and apologies for the camera photo of a TV screen — Netflix blocks taking screen shots in their apps).

Stranger Things S2E8 – Around 15:57 timecode. (enhanced)

Update: Did you notice the end of line 70? You can see the lettering of the last word on TOP of the frame of the monitor. I never noticed that when watching it in full speed. The screen was probably added later as a special overlay effect and they didn’t take time to crop it in fully. But I digress…

Either the programmer used a bunch of memory typing in all the spaces to make it look nice, or this version of BASIC has pretty-output like Microware BASIC09 does.

I typed it in, trying to replicate the spacing…

10 DIM FourDigitPassword:INTEGER
20 FOR i = 0 TO 9
30     FOR j = 0 TO 9
40          FOR k = 0 to 9
50                FOR l = 0 TO 9
60                      FourDigitPassword = getFourDigits (i,j,k,l)
70                      IF checkPasswordMatch(FourDigitPassword) = TRUE THEN
80                              GOTO 140
90                      END
100                NEXT l
110          NEXT k
120     NEXT j
130 NEXT i
140 PRINT FourDigitPassword
150 END

Looking at this, I can now say it was a programmer adding the spaces. They do not follow a consistent tab value. Line 30-40 tabs in 5 spaces, then line 40-50 tabs in 6. My OCD is unhappy.

Line 10 creates a variable called FourDigitPassword. This tells us that this BASIC allows mixed case variable names. It also either support long variable names, or is like Microsoft Color BASIC where you can type them in, but the interpreter only honors the first two characters (or however many this version of BASIC supports).

This variable is declared as an INTEGER, whatever data type that is. Since an integer is a number, this four digit password must be like a PIN, consisting of numbers only. Since 0000 to 9999 is to big to fit in a byte (0-255), we’ll say INTEGER is a 16-bit value (0-65535).

Update: The Microsoft BASIC I am used to treat every numeric variable as a floating point value. I now recall that Commodore 64 had a way to declare a variable as an integer (non floating point). Perhaps that is what this is? (Though, they should have also declared I, J, K and L as INTEGERs too since none of this uses floating point values…)

Lines 30-50 are four FOR/NEXT loops using variables i, j, k and l. that cycle through 0-9 for each variable, representing each of the four digits of the password. Note that these variables are not declared in a DIM statement. Perhaps the default variable data type is a BYTE unless you otherwise specify?

In line 60, a function “getFourDigits” is called with each of the four variable values, returning something to variable “FourDigitPassword.” This looks like it would take four values like 1, 2, 3 and 4 and return them as an integer of 1234. So far, so good.

Line 70 is where things get strange. It calls a function “checkPasswordMatch” passing it this newly created integer value. If the function returns TRUE, it is intended to GOTO line 140 and print out the valid password, then end. However, since the GOTO is on a line starting with a new line number, I expect it would at the end of line 70 since nothing is after the THEN.

Let’s assume this weird BASIC will just continue parsing for more tokens on the next line, treating it as the “THEN” clause. If the compare was not valid, though, what would it do? Skip the next line? This is problematic.

Line 90 has an END, which would be problematic in BASIC. At this point, after the first unsuccessful check, this code would stop running.

Update: As noted in comments to this article by William A. and Lee, there were BASIC variants that used IF and ENDIF. If we treat that END to be intended as ENDIF, this code makes sense (but would still be a typo that would stop the code from running as presented

Conclusion: This program cannot work.

Line 100-130 are the NEXTs for the FOR loops.

Assuming functions work the way they appear and do what I assume they are meant to do, this appears to be a brute for password cracker, trying every combination of 0000 to 9999.

Make BASIC less strange…

Let’s make a real version! Here is my edit for Microsoft Color BASIC:

0 REM STRANGE.BAS
10 DIM PW
15 TP=1234
20 FOR I = 0 TO 9
30 FOR J = 0 TO 9
40 FOR K = 0 TO 9
50 FOR L = 0 TO 9
60 PW=I*1000+J*100+K*10+L
70 IF PW=TP THEN GOTO 140
100 NEXT L
110 NEXT K
120 NEXT J
130 NEXT I
140 PRINT PW
150 END

I had to change all the variables to UPPERCASE, and then shortened “FourDigitPassword” to just PW. I could have called it FOURDIGITPASSWORD since BASIC would still honor the first two letters (FO), but I find that a bad practice since it can lead to hard to track down errors latter (say, if you later used a variable called FOREVER or anything else that started with FO, thinking it was a unique variable while BASIC thought it was the same as FOURDIGITPASSWORD).

Since I do not have functions, I decided to just make a target password variable (TP) that will be the password to try to guess. I added this in LINE 15.

Line 20-50 are the same as the original program, just without the tabs (since my CoCo’s screen is only 32 characters wide and it would look messy).

In line 60, instead of calling a function that creates FourDigitPassword (PW) from four separate variables, I just build it myself. I multiply each digit out to turn 1,2,3,4 in to 1*1000 + 2*100 + 3*10 +4 (which is 1234).

Line 70 just compares the generated PW variable to the target TP variable. Again, no functions, so I just do it manually. I moved the “GOTO 140” to the end of that line (but it didn’t actually need the GOTO keyword after THEN).

I removed line 80 and 90 (since 80 is now at the end of 70).

Lines 100-150 are the same as the original program, except using uppercase and shorter variable names. Here is what it looks like, perfectly fitting a 32×16 CoCo screen. (I’ll even use the INVERSE VIDEO mode in tribute to Stranger Thing’s “upside down”):

Stranger Things Color BASIC

If I run this, it will grind away for quite some time before finally cracking the password and printing “1234”…

It would take far longer if the target password had been 9999, but hey, it works!

Make BASIC less slow…

There are some simple ways this could be sped up, such as combining lines, and removing the variables after each NEXT (so BASIC doesn’t have to look them up each time). And, the use of a variable for each of the four digits and creating an integer seems a bit pointless, since the function that checks for a match just does so with a single integer value. This whole thing could be turned in to…

0 REM STRANGE.BAS
10 DIM PW
15 TP=1234
20 FOR I = 0 TO 9999
70 IF PW=TP THEN GOTO 140
130 NEXT I
140 PRINT PW
150 END

Since I cannot resist a BASIC benchmark opportunity, I set the target password to 9999 and ran the first version. I cleared the timer (TIMER=0) at the start and printed it out just after it prints the result. The first version shows 12609.

Then I did the same with the second version, and it shows 277. (And that could be made a bit faster by removing spaces and combining lines — down to 263 in a quick test I did.

Poor Bob could have saved alot of time with that trick. It might have even saved his life ;-) (Do I need to give a spoiler warning for a show that aired in 2017? If so, spoiler warning!)

Until next time, stay strange!

BASIC and Google’s 25 horses interview question

When I loaded YouTube recently, one of the suggested videos was entitled “How To Solve Google’s 25-Horses Interview Question” by MindYourDecisions. The video cover image contained the text:

“What is the best way to find the 3 fastest horses? You can race 5 horses at a time, but you do not have a watch.”

– MindYourDecisions on YouTube

I did not watch the video since I thought this might be a fun exercise in BASIC. Instead, I fired up the excellent XRoar emulator and began writing a simple program that raced horses.

I started with an array big enough to hold the speed of 25 horses:

DIM H(24)

In Color BASIC, arrays are base-0, so that represents H(0) to H(24).

Next I initialized the array with a unique speed value by simply going through the loop and assigning each horse a speed of 0 to 24:

FOR I=0 TO 24:H(I)=I:NEXT

My next step was to randomize the entries, so I looked back on an earlier article I posted about Random BASIC shuffling. I implemented the suggested from James Jones to swap values in this array:

FOR I=0 TO 24
IF I/5=INT(I/5) THEN PRINT
J=I+INT(RND(25-I)-1)
T=H(I)
H(I)=H(J)
H(J)=T
PRINT H(I);
NEXT

Now I had an array of 25 horse speeds — H(0) to H(24) — that contains a random selection of values 0 (slowest) to 24 (fastest).

If you wanted to just find the fastest horse, you could simply scan the array and remember the fastest entry you found. At the end of the scan, you know the fastest horse. Something like this:

FH=-1:FS=-1
FOR I=0 TO 24
IF H(I)>FS THEN FH=I:FS=H(I)
NEXT
PRINT "FASTEST HORSE IS";FH

…but since this question requires racing no more than five horses at a time, I had to split that up in to code that would run five races of five horses, then a sixth race that raced the winners of each of the five races.

This is not the solution to the question, but it was a fun exercise. Here is the messy program I came up with. It will first print out the speeds of all 25 horses (five per line, matching how they will be raced) and then run the five races and final race of the winners:

0 ' HORSES1.BAS
1 '
2 ' 25 horses
3 ' Race up to 5 at a time
4 ' Find the fastest horse
5 '
10 ' H(x) - horse speed
15 DIM H(24)
20 '
21 ' Initialize each speed
22 '
25 FOR I=0 TO 24:H(I)=I:NEXT
30 '
31 ' Randomize
32 '
35 FOR I=0 TO 24
40 IF I/5=INT(I/5) THEN PRINT
45 J=I+INT(RND(25-I)-1)
50 T=H(I)
55 H(I)=H(J)
60 H(J)=T
65 PRINT H(I);
70 NEXT
75 PRINT:PRINT "RACE!"
100 '
101 ' Find fastest horse
102 '
105 DIM FH(4)
110 '
111 ' Race five sets of five
112 ' FH(x) - fastest horse
113 ' FS(x) - and its speed
114 '
115 FOR R=0 TO 4
120 FH(R)=-1:FS=-1
125 PRINT R;"-";
130 FOR I=R*5 TO R*5+4
135 PRINT I;
140 IF H(I)>FS THEN FH(R)=I:FS=H(I)
145 NEXT
150 PRINT "=";FH(R)
155 NEXT
160 '
161 ' Race the five winners
162 '
165 FH=-1:FS=-1
170 PRINT " F -";
175 FOR I=0 TO 4
180 PRINT FH(I);
185 IF H(FH(I))>FS THEN FH=FH(I):FS=H(FH)
190 NEXT
195 PRINT "=";FH
200 PRINT "WINNER IS HORSE";FH
500 END

And the result (also messy) looks like this:

Color BASIC program to find the fastest of 25 horses, when racing no more than five at a time.

But this isn’t the solution we are looking for.

The question was what is the fastest way to find the fastest three horses. I found the fastest by running six races. I expect the solution is simple, but I do not know it.

I thought I’d share this here and see if anyone else wants to work on it.

Any takers?

Video upscaling with Topaz Labs Video Enhance AI

I have Topaz Labs Video Enhance AI and have been converting hundreds of hours of my old Digital8/DV home videos. You can learn about this software here:

https://www.topazlabs.com/video-enhance-ai

If you can’t justify the cost of this software, I’d be glad to convert some videos for you. If the video is already high quality (like a 720p HD clip from a phone), converting it up to 1080p HD can look really good. If it’s older video (SD footage or old analog VHS stuff), it may not be quite as impressive, but still better than if you just scaled up the size in a video editor.

Drop me a note here, or you can check out samples at my Fiverr listing:

https://www.fiverr.com/allenhuffman/upscale-video-using-topaz-labs-video-enhance-ai

Insta360 ONE X2 photo and video modes and filenames

Updates:

  • 2022-04-06 – Initial work-in-progress document.
  • 2022-04-12 – Added preview photos of image examples.
  • 2022-04-14 – Updated TODO list.
  • 2022-04-22 – Here is a great page covering this: https://insta.pk360.de/#insta360_tech_fileTypes/
  • 2023-05-07 – I do plan to document the X3 files. They are slightly different, including a “.insp.gyro” file that I never saw on the X2. They also add an “.lrv” extension (so you have a file that starts with “LRV_” and ends in “.lrv”). If you have found any documentation on the changes, please let me know in the comments.

WORK-IN-PROGRESS

This is a work-in-progress document with much more to be added. There are probably mistakes in it, currently. Please comment with any corrections you may have.

TODO:

  • Table showing all the various photo and image combinations (HDR, fps settings, PRO/BASIC, etc.)
  • Example files to download.
  • Conversion tips for .insp to jpeg and PRO to video files.
  • .insprj project file info (from Insta360 Studio desktop app)
  • …and more…

The Insta360 ONE X2 camera can take photos and videos in a variety of formats:

X2 Photo Formats (Standard, HDR, Burst, Interval or Night Shot)

  • 360 (using both lenses)
  • Panorama (using one lens)
  • 150-degree (using one lens)
FormatModeResolution16:91:19:163:12:1
360Standardx
360HDRx
360Burstx
360Intervalx
360Night Shotx
PanoramaStandardx
PanoramaHDRx
150Standardxxx

Google Sheet: https://docs.google.com/spreadsheets/d/11FQjS861Hn8RZJ2KkpioXR5pWu5hoFivXcBVIdNekBU/edit?usp=sharing

X2 Video Formats (Standard, HDR, Timelapse, TimeShift and Bullet Time)

  • 360 (using both lenses) – 5.7K (30, 25 of 24 fps), 4K (30 or 50 fps), and 3K (100 fps)
  • 150-degree (using one lens) – Vertical (portrait) or Horizontal (landscape)
    • BASIC: 1440P (30 or 50 fps) and 1080P (30 or 50 fps)
    • PRO: 1440P (30 or 50 fps) and 1080P (30, 50 or 120 fps).
  • NOTE: Not all qualities/fps are available in all modes.

Files are saved as .mp4 video files (150-degree videos, BASIC mode), .insv files (PRO or 360 videos), and .insp (photos).

FormatModeResolution12010050302524
360Standard5.7Kxxx
360HDR5.7Kxx
360Timelapse5.7Kx
360TimeShift5.7Kxxx
360Bullet Time3Kx
360Standard4Kxx
360Standard3Kx
150 BASICStandard1440Pxx
150 BASICHDR1440Pxx
150 BASICTimelapse1440Px
150 BASICTimeShift1440Px
150 BASICStandard1080Pxx
150 BASICHDR1080Pxx
150 PROStandard1440Pxx
150 PROStandard1080Pxxx

Google Sheet: https://docs.google.com/spreadsheets/d/1TGSu1tFUbds-aMb3VNb86Rl29h0Rlqfi3TzXUzv9sWA/edit?usp=sharing

Filename Format:

  • PRE_yyyymmdd_hhmmss_xx_nnn.EXT
    • yyyy = four-digit year (2022)
    • mm = two-digit month (01-12)
    • dd = two-digit day (01-31)
    • hh = two-digit 24-hour (00-23)
    • mm = two-digit minute (00-59)
    • ss = two-digit second (00-59)
    • xx = camera
      • 00 – back camera (.dng, .insp, .insv, VID .mp4) or both cameras (.dng and .insp)
      • 01 – back camera (LRV .mp4)
      • 10 – front camera (.dng, .isnp, .insv, VID .mp4)
      • 11 – front camera (LRV .mp4)
    • nnn = sequence number (000-999)

Prefixes:

  • IMG_ – photo (ending in .dng or .insp)
  • LRV_ – low-resolution preview video (ending in .mp4 or .insv)
  • PRO_LRV_ – low-resolution preview video shot in PRO mode (ending in .mp4 or .insv).
  • PRO_VID_ – video show in PRO mode (ending in .mp4 or .insv) –
  • VID_ – video (ending in .mp4 or .insv)

Extensions:

  • .dng = RAW photo
    • xx of 00 (back) or 01 (front) – one circular image.
      • Examples:
        IMG_20220322_223414_00_211.dng (back camera)
        IMG_20220322_223405_10_210.dng (front camera)
    • Or, xx of 00 – two circular images (front and back cameras)
      • Example:
        IMG_20220322_223429_00_212.dng (both cameras)
  • .insp = 150-degree or 360-degree photo
    • xx of 00 (back) or 10 (front) – 150-degree image (single camera)
      • Example:
        IMG_20220322_223414_00_211.insp (back camera)
        IMG_20220322_223405_10_210.insp (front camera)
    • Or, xx of 00 – 360 image (both cameras)
      • Examples:
        IMG_20220322_223429_00_212.insp (front and back cameras)
    • HDR images will have three files with the same yyyymmdd_hhmmss name, xx of 00, and sequential sequence numbers.
      • Examples:
        IMG_20220211_094002_00_065.insp (back camera)
        IMG_20220211_094002_00_066.insp (back camera)
        IMG_20220211_094002_00_066.insp (back camera)
  • .insv = 360-degree video
    • LRV_ – 360 low res version of the video. xx will be 11:
      • Example:
        LRV_20220212_070353_11_003.insv (front and back cameras)
    • VID_ – 360-degree full size video. Two files with same yyyymmdd_hhmmss name and xx of 00 for back camera video and 10 for front camera video.
      • Examples:
        VID_20220212_070353_00_003.insv (back camera) VID_20220212_070353_10_003.insv (front camera)
  • .mp4 = 150-degree video
    • LRV_ – low res version of the video (vertical or horizontal orientation).
      • Example:
        LRV_20220212_112510_01_054.mp4 (back camera)
        LRV_20220211_153548_11_074.mp4 (front camera)
    • VID_ – full size video (vertical or horizontal orientation).
      • Example:
        VID_20220212_112510_00_054.mp4 (back camera)
        VID_20220211_153548_10_074.mp4 (front camera)

The filename and extension alone cannot be used to determine the type of file. Here is a table of the possible combinations:

Insta360 X2 Filenames

IMG_LRV_PRO_LRV_VID_PRO_VID_00011011
.dngxback / bothfront
.inspxback / bothfront
.insvxxbackfrontLRV both
.mp4xxxxbackbackfrontLRV front

Google Sheet: https://docs.google.com/spreadsheets/d/1Gn9V-no2CSrjV274G4RkZcRgDIFD41GCWQSvPhoFoEQ/edit?usp=sharing

You can see that .dng raw files and .insp image files use the same “00” code for single back lens images and 360 images that use both lenses. Insta360 has suggested using the file size to know if the image contains just one back lens image or both lens images.

360 Image File Examples (.insv)

NOTE: You can preview a .insv file by adding the extension “.mp4” to the end. In this example, I took all my .insv files and renamed them to “filename.insv.mp4” (so I could preserve the original extension in the filename). That allowed me to preview them in GraphicsConverter on the Mac.

You will see there should be an “LRV_yyyymmdd_hhmmss_xx_nnn.insv” file which is a low res preview movie containing both the front and back camera, then two “VID_” files with the same date/time and number, with one having 00 for the back camera and the other having 10 for the front camera:

Insat360 360-Degree .insv video (LRV low-res both cameras, VID back and front cameras).

The LRV_ files are only used by the Insta360 Studio program.

Timelapse 360 Example (.insv)

However, a time-lapse .insv recording will not have a LRV_ version. Here are two .insv time-lapse files for the same recording. 00 for the back camera, and 10 for the front camera:

Insta360 360-Degree .insv video (VID back and front camera).

150-degree Example (.mp4)

The camera will save two files: a low resolution LRV_ file with 01 if it used the back camera or 11 if it used the front, and a full size VID_ file with 00 for the back camera or 10 for the front:

Insta360 150-Degree .mp4 Timelapse video (LRV low-res, and VID full size).

360 Image Example (.insp)

The camera will record one .insp file which contains both the front and back camera images.

Insta360 360-Degree .insp photo.

150-Degree Image Example (.insp)

The camera will record one .insp file which contains either the front camera image (10) or back camera image (00):

Insta360 150-Degree .insp photo.

…More to come…

Upgrade from Windows 11 Home to Windows 11 Pro using an old Windows key

I have a Windows laptop that came with Windows 10 Home. Unfortunately, Home is missing two features I wanted to use — Remote Desktop (so I could connect to this machine from elsewhere) and Bitlocker (so I can encrypt the hard drive). Those features require upgrading to Windows 10 Pro.

I was able to do the free upgrade to Windows 11 Home, but upgrading to Windows 11 Pro was a $99 charge in the Microsoft Store. That’s quite a bit of money for two minor features I wanted to use.

Fortunately, over on the Sub-Etha Software Facebook page, Jason D. had a solution.

“If you have an old key for Win 7 Pro, it should work. Seeing as how the system has an OEM key on it now, though, who knows… You could always just bite the bullet and upgrade, I had to do that on my Surface.”

– Jason D.

I recalled I had Windows 7 Pro in the past, which I ran on my Mac under the Parallels PC emulator. I looked through my old registration files and found my activation key for Windows 7 Pro. Using it, I was able to upgrade my Windows 11 Home version to Windows 11 Pro.

Thank you, Jason, for the great idea! I’d never run that old Windows 7 install again, so this was a great way to re-use a license I already paid for. (I also have a Windows 10 Pro license, but I have to keep that one for running it on my emulator.)

Hopefully Jason’s suggestion also helps someone else…

Until next time…

while and if and braces … oh my.

Another day, another issue with a C compiler of questionable quality…

Consider this bit of C code, which lives in an infinite main loop and is designed to do something every now and then (based on the status of a variable being toggled by a timer interrupt):

while (timeToDoSomething == true)
{
    timeToDoSomething = false;

    // Do something.
}

The program in question was trying to Do Something every 25 ms. A timer interrupt was toggling a boolean to true. The main loop would check that flag and if it were true it would set it back to false then handle whatever it was it was supposed to handle.

While this would have worked with “while”, it would really be better as an “if” — especially if the code to handle whatever it was supposed to handle took longer than 25ms causing the loop to get stuck.

Thus, it was changed to an “if”, but a typo left the old while still in the code:

//
while (timeToDoSomething == true)
if (timeToDoSomething == true)
{
    timeToDoSomething = false;

    // Do something.
}

Since things were taking longer than 25ms, the new code was still getting stuck in that loop — and that’s when the while (which was supposed to be commented out) was noticed.

The while without braces or a semicolon after it generated no compiler warning. That seemed wrong, but even GCC with full error reporting won’t show a warning.

Because C is … C.

Curly braces! Foiled again.

In C, it is common to see code formatted using whitespace like this:

if (a == 1)
    printf("One!\n");

That is fine, since it is really just doing this:

if (a == 1) printf("One!\n");

…but is considered poor coding style these days because many programmers seem to be used to languages where indention actually means something — as opposed to C, where whitespace is whitespace. Thus, you frequently find bugs where someone has added more code like this:

if (a == 1)
    printf("One!\n");
    DoSomething ();
    printf("Done.\n");

Above, it feels like it should execute three things any time a is 1, but to C, it really looks like this:

if (a == 1) printf("One!\n");
DoSomething ();
printf("Done.\n");

Thus, modern coding standards often say to always use curly braces even if there is just one thing after the if:

if (a == 1)
{
    printf("One!\n");
}

With the braces in place, adding more statements within the braces would work as expected:

if (a == 1)
{
    printf("One!\n");
    doSomething ();
    printf("Done.\n");
}

This is something that was drilled in to my brain at a position I had many years ago, and it makes great sense. And, the same thing should be said about using while. But while has it’s own quirks. Consider these two examples:

// This way:
while (1);

// That way:
while (1)
{
}

They do the same thing. One uses a semicolon to mark the end of the stuff to do, and other uses curly braces around the stuff to do. That’s the key to the code at the start of this post:

while (timeToDoSomething == true)
if (timeToDoSomething == true)
{
    timeToDoSomething = false;

    // Do something.
}

Just like you could do…

while (timeToDoSomething == true) printf("I am doing something");

…you could also write it as…

while (timeToDoSomething == true)
{
    printf("I am doing something");
}

So when the “if” got added after the “while”, it was legit code, as if the user was trying to do this:

while (timeToDoSomething == true)
{
    if (timeToDoSomething == true)
    {
        timeToDoSomething = false;

        // Do something.
    }
}

Since while can be followed by braces or a statement, it can also be followed by a statement using just braces.

The compiler can’t easily warn about needing a brace, since it is not required to have braces. But if it braces were required, that would catch the issues mentioned here with if and while blocks.

Code that looks like it should at least generate a warning is completely valid and legal C code, and that same code can be formatted in a way that makes it clear(er):

while (timeToDoSomething == true)
    if (timeToDoSomething == true)
    {
        timeToDoSomething = false;

        // Do something.
    }

Whitespace makes things look pretty, but lack of it can also make things look wrong. Or correct when they aren’t.

I suppose the soapbox message of today is just to use braces. That wouldn’t have caught this particular typo (forgetting to comment something out), but its probably still good practice…

Until next time…

Web searching takes the fun out of History channel UFO shows.

I love a good conspiracy theory, but usually they fizzle out within a few minutes of web searching about them. Want to get the other side? Just search for whatever it is plus “debunk.”

The Secret of Skinwalker Ranch on History, for example, doesn’t hold up very well. In the season two finale, they fly a helicopter around to take sensor readings. The radar altimeter starts alerting them that the ground is less than 50 feet below, when they were 1500 or more above it.

The helicopter pilot was (pretending to be?) mystified. It was as if there was something just below the aircraft that no one could see.

A quick search reveals tons of documentation on things that mess up radar based altimeters and give them false low readings.

Pity.

I was really hoping for an invisible UFO flying around below them.

But, do your own research. Though, it may be a funner show if you don’t.

Short circuiting of C comparisons

In a language like C, you often have multiple ways to accomplish the same thing. In general, the method you use shouldn’t matter if the end result is the same.

For example:

// This way:

if (a == 1)
{
   function1();
}
else if (a == 2)
{
   function2();
}
else
{
   unknown();
}

// Versus that way:

switch (a)
{
   case 1:
      function1();
      break;

   case 2:
      function2();
      break;

   default:
      unknown();
      break;
}

Both of those do the same thing, though the code they generate to do the same thing may be different.

We might not care which one we use unless we are needing to optimize for code space, memory usage or execution speed.

Optimizing for these things can be done by trail-and-error testing, but there is no guarantee that the method that worked best on the Arduino 16-bit processor and GCC compiler will be the same for a 64-BIT ARM processor and CLANG compiler.

If you ever do make a choice like this, just be sure to leave a comment explaining why you did it in case your code ever gets ported to a different architecture or compiler.

Short circuiting

Many things in C are compiler-specific, and are not part of the C standard. Some compilers are very smart and do amazing optimizations, while others may be very dump and do everything very literally. Here is an example of something I encountered during my day job that may or may not help others.

I had code that was intended to adjust power levels, unless any of the four power generators hit a maximum level. It looked like this:

// Version 1: Do nothing if power limit exceeded.
if ((Power1 > Power1Max) ||
    (Power2 > Power2Max) ||
    (Power3 > Power3Max) ||
    (Power4 > Power4Max))
{
   // Max power hit. Do nothing.
}
else
{
   increasePower ();
}

Having conditionals lead to nothing seems odd. Wouldn’t it make more sense to check to see if we can do the thing we want to do?

// Version 2: Do something is power limit not exceeded.
if ((Power1 < Power1Max) &&
    (Power2 < Power2Max) &&
    (Power3 < Power3Max) &&
    (Power4 < Power4Max))
{
   increasePower ();
}

That looks much nicer. Are there any advantages to one versus the other?

For Version 1, the use of “OR” lets the compiler stop checking the moment any of those conditions is met. If Power1 is NOT above the limit, it then checks to see if Power2 is above the limit. If it is, we are done. We already know that one of these items is above, so no need to check the others. This works great for simple logic like this.

For Version 2, the use of “AND” requires all conditions to be met. If we check Power1 and it is below the limit, we then and check Power2. If that one is NOT below, we are done. We know there is no need to check any of the others.

Those sure look the same to me, and Version 2 seems easier to read.

The first example is basically saying “here is why we won’t do something” while the second example is “here is why we WILL do something.”

Does it matter?

To be continued…

JS Mocha CoCo emulator on iPad?

Online web emulators used to not work on tablets like the iPad due to how keyboard commands were handled. A few years ago I was working with an online emulator and the author confirmed it wasn’t possible due to the mobile browsers only sending keys, instead of “key X down, key X up” sequences (or something like that).

To my surprise, when I checked the JS Mocha CoCo emulator today, it worked on the iPad with a bluetooth keyboard! At some point, something changed and it is now possible to use an external keyboard on a tablet (at least an iPad) and use the emulators. I also spot checked the XRoar Online emulator and it works too, but since it does not currently support keyboard translation, you have to know where the CoCo keys are on a modern keyboard.

Check it out, and please let me know if this also works on android tablets.

My 1987 CoCo ASCII to Atari ATASCII converter

It seems like only yesterday that you had a dozens of choices in what computer you could buy. Most were not compatible with the others — and we liked it that way. Software companies, however, probably didn’t. To reach the largest market, they had to write their program multiple times for different systems. My Radio Shack Color Computer, sadly, did not get many of these official ports.

Side note: For a nice list of some of the official ports we actually did get, see this listing by Curtis Boyle.

Many things we take for granted today — such as sending text from one computer to another (via e-mail, text, etc.) — were not as simple back then. Not all systems used an industry standard character set, meaning the numeric code that represented a character on one system, might represent a different character on another.

The CoCo used ASCII – “American Standard Code for Information Interchange.” The defined numeric values represented the following characters in this clear and easy to understand chart:

ASCII table from https://en.wikipedia.org/wiki/ASCII

If that chart doesn’t help, you are not alone. Just know that characters 0 to 127 were all defined to represented a standard set of letters, numbers, punctuation, symbols and control codes (such as 8 being BACKSPACE, 13 being CARRIAGE RETURN, etc.).

System like the Atari 400/800 and Commodore PET/VIC-20/64/etc. included non-ASCII graphical symbols in their character set. Each of these systems came up with their own standard — PETSCII from Commodore (which originated on the Commodore PET in 1977), and ATASCII from Atari (which originated on the Atari 400/800 in 1979).

Before WWW there was BBS

One of the first things I ever did with a computer was use one with a modem to dial other computers over a land line telephone. (Kid’s, ask your parents…) Folks would run Bulletin Board System software that let others call their computer and post messages for other folks to read who called in later.

This presented a problem. If the character sets were different between computers, how could an ASCII CoCo user dial in to an Atari ATASCII system or a Commodore PETSCII system?

To solve this problem, some BBS programs on the non-ASCII computers would first ask you if you wanted ASCII or ATASCII (or PETSCII or whatever). For ASCII users, the BBS would then translate the character codes.

Not all systems did this, of course. There were plenty of Commodore-only and Atari-only systems that made use of the extended character set to draw fancy menus and screens that ASCII computers couldn’t view.

However, the modem “terminal programs” that non-ASCII systems ran usually had an ASCII translation mode built in. Thus, a Commodore or Atari user could call any ASCII BBS. While I am sure they existed, I never did see a terminal program for my ASCII CoCo that let it call an ATASCII or PETSCII-only system. (TwilightTerm by SockMaster is similar, allowing a CoCo 3 to view the IBM PC ANSI character set and colors.)

When I lived in Lufkin, Texas, one of the local BBSes was running on an Atari 800 (via BBS Express software) and allowed ASCII systems to call in. This was how I first learned about the differences in ATASCII versus ASCII.

Here is what ASCII characters 32-127 looked like on the CoCo 1 and 2 (characters 0-31 are control codes and such):

Radio Shack Color Computer 32-column text screen ASCII.

And here is the same set of characters on a CoCo 3 40-column screen with row and column numbers (since I had more screen room):

Tandy Color Computer 3 40-column text screen ASCII.

From wikipedia, here is what ATASCII looks like:

ATASCII from https://en.wikipedia.org/wiki/ATASCII

I think this table is much easier to read that the ASCII one, as long as you know hexadecimal.

Starting at character 32 (0x20) is a space, followed by special characters and the alphabet. Although there are some symbol differences (like the ^ on CoCo being a diamond on the Atari), the main letters, numbers and symbols are the same.

But, if I were to write up a text file and send it to the Atari BBS so they could post it, it would not work. ASCII uses 13 (CR, carriage return) as a line ending, but ATASCII uses 155 (ATASCII CR). If I translated line endings, and avoided using things like ^, brackets (or curly braces), etc., I could then have a text file the Atari BBS could use.

The amazing ASCII to ATASCII Convert program!

So I wrote a simple ASCII to ATASCII converter:

0 REM ASCII TO ATASCII CONVERT
1 REM BY ALLEN HUFFMAN
2 REM (09/02/87)
3 REM
5 CLEAR1000
10 CLS:PRINT@3,"ASCII TO ATASCII CONVERTER":PRINT@40,"BY ALLEN HUFFMAN":PRINTSTRING$(32,131)
15 PRINT@96,"ASCII FILE TO CONVERT:":LINEINPUT">";F1$:IFF1A$=""THEN15
20 PRINT@192,"NAME OF NEW FILE:":LINEINPUT">";F2$:IFF2$=""THEN15
25 PRINT@289,"CONVERTING ASCII TO ATASCII...":OPEN"I",#1,F1$:OPEN"O",#2,F2$
30 LINEINPUT#1,A$:PRINT@320,A$:PRINT#2,A$+CHR$(155);:IFEOF(1)=0THEN30
35 PRINT#2,CHR$(26);:UNLOAD
40 PRINT@422,"CONVERSION COMPLETE!":END

In line 15, it asks for an INPUT filename (F1$).

In line 20, it asks for an OUTPUT file name (F2$).

In line 25, it opens the first file as input (“I”) and the second file for output (“O”).

In line 30, it loops reading a raw line from the first file, displaying it on the screen (so the user can see what is going on), then writes the text out to the output file with a CHR$(155) at the end and NO ASCII carriage return (by using the semicolon). If end-of-file is not reached, it goes back to 30 to process the next line.

In line 35, it writes out a final CHR$(26) (control-Z) to the ATASCII output file — but I do not recall why. It then uses the UNLOAD command to close any open files.

I had to look up UNLOAD, as I had forgotten this existed. The description reads:

“Closes any open files on the disk in the drive you specify. If you do not specify a drive number, the com­puter uses Drive 0 (or the drive you specified in the DRIVE command).”

Disk Extended BASIC manual

Not much to it, but it worked and it let me write bulletins and such that I could upload to the Atari BBS.

I thought I would share this code in case any CoCo user out there needs to upload some text files to an Atari BBS.

Until next time…