Astrolokeys and a Vortex Tab 90M

If you found this helpful and are planning on purchasing a Drop keycap set, please use my referral link and we’ll both get $10.

Astrolokeys with the Vortex Tab 90M base

I initially built a Drop CTRL keyboard combo with the Halo Clear switches and Astrolokeys Base set for the 15% discount, but after a while I felt myself missing my Cherry MX Silent Black switches and the full keyboard layout of the Vortex Tab 90M.

Transferring the Astrolokeys to Vortex Tab 90M

After transferring the keys, only the right [CTRL] [SHIFT] [ALT] and the [FN] [PN] and [CALC] keys were missing “in theme” keys. After spending a week with the old primary color key caps, I got the “Nonstandard Icon Mods” and the “Ortho Icons” from the Astolokeys page. Ultimately getting those sets plus the base kit instead of the Drop CTRL would have been $150 for the key caps only vs. $250 for the original keyboard base, switches, and base keycap set. But now someone else in the family has a very nice tactile keyboard with the old Tab 90M keycaps until they get their own custom keycaps someday.

Oh, and the Drop CTRL looks pretty cool with the Vortex Tab 90M keycaps, too…

Drop CTRL keyboard with Vortex Tab 90M keycaps

Microphone Crackle and Distortion on Windows 10 with New ASUS Motherboard

I’ve had to remedy microphone crackle and distortion twice on two different builds/rebuilds of Windows 10 PCs, and somehow forgot from the last time how to remedy.

In my case, the problem was the onboard sound for the ASUS Motherboard (ASUS ROG Strix B550-E and ASUS ROG Strix B550-A motherboards.) The solution is to get the audio drivers for the Realtek Audio that come on the board and install them (B550-A and B550-E downloads.)

Tandy/Radio Shack TRS-80 Model 16 Graphics

TRS-80 Model 16 Nostalgia

I grew up with a TRS-80 Model I with Level 2 Basic and a TRS-80 Model 16 with 128K of RAM that were our first computers in the house prior to me getting my first computer, a Commodore 128. There was a book about Level 2 Basic that came with the TRS-80 Model I that was (as far as I know) a giveaway, but I never saw the TRS-80 Model I running except when it was in my grandmother’s house in Old Louisville on the 3rd floor when my dad’s younger brothers were playing around with a simple number guessing game program.

One thing that intrigued me about the TRS-80 Model I was its very simple graphics commands, SET and RESET which operated on a 48×128 (row x column) graphics grid as well as PEEK and POKE commands which could address a 2×3 grid of those same graphics grid points, but on the 16×64 character grid.

BASICG? What is this

I played around with the Model 16 and its 8″ disks and BASIC in there, but it wasn’t until I stumbled on PDF documentation for the Tandy TRS-80 model II that I discovered that the business computers (Model-II / Model-12 / Model-16) actually supported graphics at all. Looking at the Model_2_Computer_Graphics_26-4104.pdf scanned reference, it turns out BASICG (must be all uppercase in TRS-DOS) is the way to load the BASIC graphics interpreter.

I’m not sure if the TRS-DOS disks that came with the Model 16 my dad had had this interpreter, but the trs80gp emulator includes BASICG on the default boot disk for Model 16 mode:

What’s this BASICG on the TRSDOS disk?

(It wasn’t until after the TRS-80 Model 16 was gone that I learned about the DIR command via using MS-DOS, but that would have been helpful for digging in more… Ironically, my Commodore 128 supported a DIRECTORY command, so … SO CLOSE BUT SO FAR)

The TRS-80 Model 16 screen is 640×240 (x,y) addressable monochrome pixels. Unlike the Model I with Level 2 BASIC, BASICG has some more advanced commands… LINE, CIRCLE, PAINT… also GET to read the contents of the screen and that can later be PUT.

Interestingly enough, although the CIRCLE documentation say that the third argument is “r”/radius

CIRCLE command documentation

actual usage in the emulator appears to behave like the argument is a diameter instead:

Circles drawn on text

I’m definitely looking for more resources on the Model 16, so if you have background, manuals, etc., email me at thomas at thisdomain.

Vortex Race 3 TKL LED Programming for Mac

I decided to switch to my Vortex Race 3 TKL for a more programming-centric job from the Vortex Tab 90M that felt a little better for email and spreadsheets. The Race 3 has Cherry MX Silent Reds vs. the Vortex Tab 90M’s Cherry MX Silent Blacks.

A couple of things that were a little bit difficult to follow were:

  1. How to set up the Race 3 for Mac (it had been used on a Windows PC most recently and never really used on a Mac). This Reddit thread gives some suggestions on how to optimize that.
  2. How to program the LEDs (for just basic effects):

The LED programming was fairly simple once I understood it (see here for a copy of the manual). The cool LED effects when you type are accessible by pressing the Pn key + one of the ‘1’ through ‘5’ keys. ‘4’ and ‘5’ have multiple effects:

Pn + ‘4’ cycles different “display single color LED mode”s which means that the interactive LED effects appear in context with your

  • [no effect?]
  • Interactive mode – keys light up as you type.
  • Flash vortex mode – keys pulse around the keyboard originating from your keystrokes
  • Aurora mode – keys pulse in color around the keyboard originating from your keystrokes

Pn + ‘5’ cycles different “Display full color LED mode”s which means “display on all the keys regardless of context”:

  • [no effect]
  • Full key light mode – just 100% on
  • Breath mode – keyboard pulses
  • Vortex mode – RGBs cycle in different phases with each other.
  • Rain drop mode – random drops of “color” appear on the keys

Pn + X – brightness down for the above effects

Pn + V – brightness up for the above effects

Pn + [< key] and Pn + [> key] are LED speed up and down.

Removing a Broken Headphone Plug from an iPhone

Broken Headphone Plug and iPhone. 😱

The headphone jack is a pretty key port for anyone not on an iPhone 7 or later, so a broken headphone plug shoved in the jack renders a phone pretty much useless. It’s also too small a space for needle nose pliers.

So what do you do if something breaks off in it? Well, searching around on iFixit lead me to the existence of a headphone plug extraction tool (for $50!!!) Unfortunately, my daughter actually uses her phone for school, so the wait (plus $50) was unacceptable if we could find another solution.

Other solutions?

  • Crazy glue the broken headphones to its counterpart (and risk sealing it up for good?!)
  • Small drill bit.
  • Bamboo toothpick.
  • Soda straw cut to squeeze around the broken plug.

Ok, the soda straw sounded reasonable and, if nothing else, low risk. So I tried with some IKEA straws and got close to extracting a piece out, but no further. The problem was that there was too much in the plug. (The headphone plug is concentric cylinders that had been shoved all the way in.)


So I kept reading… CUTICLE SCISSORS! My wife had a small pair that worked well to extract one of the pieces. Grab what you can with the scissors, push the straw around the remainder and tug to extract. The plug tip slid far enough out in this process to grab with my fingernails.

Below is the final carnage with extraction tools.

Cuticle scissors, straw, headphone plug pieces

Go Concurrency Benchmarking on a Raspberry Pi

In hindsight, no one claimed that a Raspberry Pi of any model was a powerhouse machine. However, I had thoughts about how to benchmark computing power after leaving Dreamhost and noticing that even tar and gzipping my WordPress installs performed like an ancient machine despite the processor statistics. That made me think about a raw benchmarking metric that could deployed anywhere. I was also learning Go and trying to understand Go concurrency. I ended up with a “concurrency” of 2 because the lower power systems didn’t get any more out of an additional goroutine.

package main
import (
func main() {
var before string
var after [64]byte
var base64Encoding string
var result chan string = make(chan string)
var resultString string
var addOnStart int64
start := time.Now()
addOn := 0
concurrency := 2
sem := make(chan bool, concurrency)
for {
before = fmt.Sprintf("Message%d", addOn)
after = sha3.Sum512([]byte(before))
base64Encoding = base64.StdEncoding.EncodeToString(after[:])
if strings.HasPrefix(base64Encoding, "TEST") {
fmt.Printf("%d seconds\n", int64(time.Since(start)/time.Second))
fmt.Printf("%d: %s\n", addOn, base64Encoding)
addOnStart = 0
start = time.Now()
for {
sem <- true
go scan1000000(addOnStart, result, sem)
select {
case resultString, _ = <-result:
fmt.Printf("%d seconds\n", int64(time.Since(start)/time.Second))
func scan1000000(addOnStart int64, result chan string, sem chan bool) {
var before string
var after [64]byte
var base64Encoding string
defer func() { <-sem }()
for i := addOnStart * 1000000; i < (addOnStart+1)*1000000; i++ {
before = fmt.Sprintf("Message%d", i)
after = sha3.Sum512([]byte(before))
base64Encoding = base64.StdEncoding.EncodeToString(after[:])
if strings.HasPrefix(base64Encoding, "TEST") {
result <- fmt.Sprintf("%d: %s\n", i, base64Encoding)

view raw


hosted with ❤ by GitHub

The program requires 13,135,013 sha3 hashes and conversions to base 64 to come up with a string that starts with “TEST”.

My work workstation’s output:

[Specs: Late 2013 Retina MacBook Pro 15″, 2.3 GHz Core i7 – (I7-4850HQ)]

  • Single thread: 16 seconds
  • Concurrency of two: 10 seconds
  • Compared with PassMark:
    • 9066
    • Single thread 1964

A Late 2011 MacBook Pro 13″, 2.4 GHz Core i5 (I5-2435M):

  • Single thread: 34 seconds
  • Concurrency of two: 19 seconds
  • Compared with PassMark:
    • 3269
    • Single Thread 1347

A Core i3-5010U 2.10 GHz NUC (Windows 10 Pro)

  • Single thread: 27 seconds
  • Concurrency of two: 17 seconds
  • Compared with PassMark:
    • 3060
    • Single Thread 1171

A Mid 2009 MacBook Pro 13″, 2.26 GHz Core 2 Duo (P7550)

  • Single thread: 57 seconds (Originally was 83 on go1.3.3, but better results with 1.8.3)
  • Concurrency of two: 32 seconds (Originally was 80 on go1.3.3)
  • Compared with PassMark:
    • 1521
    • Single Thread 892

A ThinkPad 11e with A4-6210 APU (1.8 GHz – Windows 10 Home)

  • Single thread: 135 seconds
  • Concurrency of two: 65 seconds
  • Compared with PassMark:
    • 2143
    • Single Thread 697

Raspberry Pi 3B

  • Single thread: 1265 seconds
  • Concurrency of two: heat warnings!

For the purposes of this “performance” benchmark, there is definitely a non-linear relationship between a canned benchmark score and the score in a brute force operation that has a heavy calculation component. I’m also isolating only one aspect of system performance. There is a SATA SSD on the newest machine, a SATA HDD on the 2011 and 2009 machines, and an SD card on the Raspberry Pi. The RAM is different in every machine as well. Still, it was a fun experiment that motivated me to spend a little extra time in Go and learning Go Concurrency.

Using an Arduino to keep a Seiki 4K Display On

I love my Seiki 4k Display for writing code on my Mac. The one downside is that it times out and goes to sleep after 2 or 4 hours of inactivity (from the remote, not the screen). I decided to fix this problem in a somewhat complicated way: With an Arduino Uno that I already had, and an IR control kit.

I used the IR receiver to find the Seiki “Volume Up” and “Volume Down” codes, which appear to be structured like NEC codes. Those are hardcoded because I haven’t really bothered to refine the setup or code any more. The IRBlaster library uses digital out 3 for the IR sends, and I used digital 8, 9, and 10 for red, yellow, and green indicators to give some indication of where in the refresh cycle things are. The code as-is sends the volume up and volume down signals every hour or so, and the indicators start with a slow blink on red, a slightly faster blink on yellow, and a fast blink before remote send on green.

IR Blaster set up (with IR receiver partially wired in still)
IR Blaster set up (with IR receiver partially wired in still)


IRsend irsend;
int led = 13;
int red = 8;
int yellow = 9;
int green = 10;

void setup()
  pinMode(led, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(yellow, OUTPUT);

  pinMode(green, OUTPUT);

int choice(int i) {
  if(i > 1300) {
    return red;
  } else if (i > 900) {
    return yellow;
  return green;

void ledOn(int i) {
  digitalWrite(choice(i), HIGH);
void ledOff(int i) {
  digitalWrite(choice(i), LOW);

void loop() {
  while(true) {
    irsend.sendNEC(1086232679, 32); // seiki volume up
    irsend.sendNEC(1086206159, 32); // seiki volume down
    for(int i=1800; i >=0; i--) {

What should I do with this existing desktop?

I have a mostly custom built desktop, and want to replace it with adequately current hardware, but no real plans for gaming.

  • The IDE Hard Drives are going out.
  • On the existing desktop:
    • Windows 2000 is installed, but I rarely boot to it.
    • Ubuntu 9.04 is installed.
  • I have a SATA 250 GB drive that works perfectly fine, but which I have from another system which I upgraded to 2 x 500 GB.
  • The Antec case is a fairly nice, but dated, mid-tower ATX case.
  • I think the power supply handles SATA power.
  • The existing motherboard only supports IDE, up to a 3.06 Northwood core processor.
  • I currently do not have *any* Windows 7 installs.

I also have a Dell Desktop which is our main desktop in the home:

  • Windows XP
  • 3 GB of RAM
  • 2 x 500 GB SATA hard drives
  • 2.16 GHz [E6400?] Core 2 Duo processor
  • iTunes, media, and photos are on this box.

Some interests:

  • Windows 7 64-bit would be nice to play around with.
  • Would still like to end up with a Ubuntu install somewhere.

Some options that I’ve thought of:

  1. Upgrade the custom build (that’s a mobo/processor and ram minimally, even if integrated video)
  2. Get a recent refurb desktop, replace the Dell with it, and replace the custom build with a Dell
  3. Buy a Mac desktop, move the Dell downstairs.

More issues with my Lenovo T61

Here’s a nice shot of the nVidia driver context menu wackiness in windows XP. The longer a window is open, the more of these that appear. (Considering the window in question is Safari, that time span is probably 2-3 hours.)

Meanwhile, I spent 10-15 minutes trying to get the laptop to recognize that my external monitor was plugged in, and then trying to close windows for a graceful shutdown.