Adding Wi-Fi to the Macintosh Portable

Over the past year or so, I’ve been working with other
developers to add Wi-Fi functionality to their open-hardware SCSI device,
enabling Wi-Fi support for old Macs and other vintage computers going back some
36 years.

This is my Macintosh Portable M5126.
It’s very Macintosh and barely portable.
For some reason I’m using it on my lawn reading the
Wi-Fi Wikipedia article
over Wi-Fi through my
Wikipedia application
for System 6, with my Wi-Fi Desk Accessory showing it connected to my “!”
network with meager signal strength.

This article was originally supposed to be titled
Adding Wi-Fi to a
PowerBook 100

since that laptop is much more reasonable to lug around, but its logic board
died while working on this and I’m in the process of bringing it back to life.


For some background, there’s a handful of hardware devices that simulate SCSI
disks for vintage Macintosh, Amiga, and Sun computers (and
and can replace old, loud, power-hungry, unreliable,
spinning hard drives with solid-state SD card media similar to
CompactFlash IDE adapters
for old PCs.

There’s a bit of history surrounding these projects, but the first one created
in 2013,
is a commercial product coming in various form factors such as
external DB25.
SCSI2SD requires proprietary software to configure the disks it presents, and
then requires a low-level tool like dd to write a disk image at a particular
offset on the SD card.

In 2017, RaSCSI, since renamed to
did this with a
attached to a Raspberry Pi or
Pi Zero,
but it requires a full Linux OS to serve up everything which makes it kind of
overkill in my opinion, as it takes a while to boot all of that to serve a
computer that wants its hard drive available within a few seconds.

In 2018,
later forked to
did this using a
Blue Pill STM32
Arduino, and improved on SCSI2SD by using a regular FAT filesystem on its SD
card so disk images could be configured just by copying them to the card and
giving them particular filenames (much like the
did back in 2012) such as HD4-macplus.hda to present that file as a hard disk
on SCSI ID 4.

In response to the global chip shortage in 2022, the company that created
SCSI2SD created a new product called
which forked BlueSCSI’s firmware but was then entirely rewritten.
Then in 2023 in a round-about fashion, BlueSCSI forked the rewritten ZuluSCSI
firmware and created a new
BlueSCSI v2
board which uses the
$4 Raspberry Pi Pico
RP2040 microcontroller.

DaynaPORT Ethernet

In addition to SCSI hard disks and Zip drives, on my Macintosh Plus workstation
computers I use DaynaPORT SCSI/Link-3 SCSI ethernet devices which add 10baseT
networking over SCSI.
I also use a Dayna Pocket SCSI/Link for my PowerBook 100/180 which works the
same way and is powered through the ADB port.

TCP/IP applications on System 6 on the Mac are usually written to use the
MacTCP then talks to another driver for the particular network hardware to
actually exchange packets, such as
which talks to serial modems, or in this case, the
DaynaPORT SCSI driver.

Two DaynaPORT SCSI/Link-3 devices
DaynaPORT SCSI/Link Pocket

In 2021, the RaSCSI/PiSCSI project gained
of these Dayna ethernet devices which use a
SCSI command set for exchanging packets.
Since PiSCSI runs on a full Raspberry Pi, it’s easy to use its native ethernet
or Wi-Fi interface to deal with network traffic and then send it over SCSI
through the PiSCSI software (or at least as easy as anything is on Linux).

Last year I
similar emulation in the
PCE emulator.
I don’t usually use classic Mac OS in an emulator, but I found it useful to have
a System 6 environment on my laptop when I was away from my Mac Plus
workstation and wanted proper networking.


Around this time last year, I started talking to
Eric Helgeson
of the BlueSCSI project who was looking to make a
classic Mac app
that could transfer files from a classic Mac to the BlueSCSI itself which would
then transfer to the FAT filesystem on the SD card, rather than into the virtual
disk contained on the SD card.
This way a new hard disk or CD-ROM image could be uploaded from a Mac which
would then show up as a new drive to Mac OS without having to potentially
disassemble the computer the BlueSCSI is in to remove its SD card.

After helping Eric with some
classic Mac OS programming,
we met at the
Vintage Computer Festival Midwest
last September and I learned about BlueSCSI’s upcoming v2 design which was set
to use the Raspberry Pi Pico.
I told him that if it could use the newly released
I would be interested in writing the BlueSCSI firmware code to emulate a
DaynaPORT ethernet device via its Wi-Fi.

To be clear, this wouldn’t be like many
ESP8266 projects
that handle all of the TCP/IP and present some simplified interface to their
host computers, but would be more of a media converter just connecting to Wi-Fi
and presenting an ethernet interface to the host computer which would handle
TCP/IP itself.

Once the BlueSCSI v2 design was finalized, Eric and
sent me a prototype board and I got to work.


After fumbling around with the
environment in Visual Studio Code (two things new to me) needed for BlueSCSI, I
was able to build and test the firmware on my test device but was limited to
printf-style debugging.
I then learned about
which is special firmware running on another Pico that communicates with the
target Pico over its debug pins, which then allows stepping through code and
inspecting variables inside of the PlatformIO interface.
(I later learned there is a
Pico WH
model that breaks out these debug pins in a nicer way.)

picoprobe (left) connected to BlueSCSI

Pico PIO and SPI

To perform SDIO traffic as fast as possible, the BlueSCSI firmware offloads SPI
traffic to the RP2040’s
Programmable I/O (PIO).
Unfortunately the
Wi-Fi chip
of the Pico W also uses the same PIO instance so once Wi-Fi was activated, SDIO
Getting everything cooperating together required Androda to do some extensive
debugging and while waiting for that, I started on the SCSI code in the firmware
with the SD card support disabled so at least Wi-Fi and SCSI could work

Since I had already written
code in PCE
for the DaynaPORT, it was just a matter of adapting it to BlueSCSI’s code and
making it configurable like hard disks are by creating a file on the SD card
like NE3.txt to add a network interface on SCSI id 3.
By May of this year, I had a virtual device presenting to the Mac and recognized
by Danya’s System 6 driver and utilities:

DaynaPORT Diagnostics Utility showing a BlueSCSI

One of the commands that the Dayna driver sends to the DaynaPORT early on is to
ask what its MAC address is, and this has to have Dayna’s vendor prefix of
Since the Pico W would just be converting layer 2 traffic from Wi-Fi to SCSI,
this meant either changing the Pico’s MAC address to match the virtual Dayna
device, or rewrite every outbound Wi-Fi packet to have the Pico’s MAC and
rewrite inbound packets to replace it with the Dayna MAC.
Since I wasn’t sure where that Dayna MAC might show up inside of any packets, I
chose the former.
Unfortunately being able to change the Pico’s MAC address required recompiling
the upstream driver library, which meant BlueSCSI now has to maintain our own
Arduino-Pico and Pico-SDK trees with this pre-compiled library change.

SCSI Debugging

Once packets started flowing in from Wi-Fi and in from the Mac, I ran into an
issue where packets going out to the Mac through SCSI were getting dropped,
either by the DaynaPORT driver or MacTCP.
This took a while to track down because everything I was seeing was showing the
bytes being sent over SCSI were identical to what I received over the air, but
the Mac was just ignoring them.
I used PCE to show that the packets being sent to an emulated system was
identical as well, and it was being processed by the virtual Mac just fine.

I eventually purchased this old Ancot DSC-202F SCSI analyzer on eBay which has a
command-line interface over a serial port.

Ancot DSC-202F SCSI Analyzer hooked up to a BlueSCSI

The Ancot allowed me to watch the SCSI bus traffic and dump the commands and
data to verify that things were leaving the BlueSCSI properly.
I compared traffic from the BlueSCSI to what my real DaynaPORT device sent and
it looked identical, which was helpful but also frustrating.

00B47: Bus free
00B48:    Arbitration   /80 (7)
00B4B:    Select        /88 (3,7)
00B4F:       Command    /08 (Read/Receive)00 00 05 F4 C0
00B57:          Data-In /00 66 00 00 00 00 00 80 19 10 0B E9 00 E0 67 1F
00B67:                   CB 67 08 00 45 00 00 54 DF D9 00 00 FF 01 58 75
00B77:                   C0 A8 01 01 C0 A8 01 08 08 00 DC FD 80 46 00 01
00B87:                   A6 27 78 A7 EC 66 29 B3 39 EE 62 17 68 24 21 CC
00B97:                   0C 02 FD 06 E7 9B DC B3 18 19 1A 1B 1C 1D 1E 1F
00BA7:                   20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
00BB7:                   30 31 32 33 34 35 36 37 84 32 6C 6C
00BC4:       Status     /00 (Good)
00BC6:       Message-In /00 (Cmd Cmplt)
00BC8: Bus free

Eventually Androda figured out
what was required
to get the PIO for SCSI, SDIO, and Wi-Fi all working at the same time and just
when I was growing weary of debugging the SCSI issue, Eric pointed out that the
PiSCSI code had something my new BlueSCSI code didn’t:

[10:29] erichelgeson: i wonder if it’s sending the reponse too fast, piscsi has a send delay
[10:30] erichelgeson: […]/scsi_daynaport.cpp#L599
[10:30] Androda: Looks like that’s set to 2 + 4 (6)
[10:33] jcs: i’ll give it a shot
[10:41] jcs: dammit
[10:41] jcs: that was it

Apparently the BlueSCSI was sending traffic to the Mac too fast and the driver
needed time to process the incoming packet after receiving its size, but before
receiving the actual packet data.
My code for PCE didn’t have any delay and seemed to work fine, which was

With all of that in place, I was finally able to join my #cyberpals IRC
channel from my Macintosh Plus with its native TCP/IP stack, over Wi-Fi, through
IRC client.
Though of note, this was booted with its SCSI hard disk on a SCSI2SD, not (yet)
on the BlueSCSI which was providing Wi-Fi.

Wallops IRC client on a Macintosh Plus

Something I noticed while briefly testing it was that during large
downloads, it would pause once in a while but then catch up.
I didn’t give it much thought, but it ended up being another show-stopper.

Wi-Fi Debugging

By this point in June, I needed a break and the project got “paged out” of my
desk since I generally only have
for one big project at a time.
The other BlueSCSI developers were testing it on newer, faster Macs and seeing
the same pauses in traffic but it was much more frequent there.

In August, Eric wanted to release a beta BlueSCSI firmware with the new Wi-Fi
code, in hopes that someone could devote more time to finding the cause of the
traffic issues.
This was enough motivation for me to “page the project back in” and try to
figure out the cause.

[02:00] jcs: i spent some more time debugging the wifi situation and found something, are you still set on releasing it on friday @erichelgeson?
[08:00] erichelgeson: I can hold, what did you find?
[08:06] jcs: packets are dropping during wifi processing
[08:07] jcs: not the scsi injection
[08:53] Androda: Is it a raspberry pi framework issue?
[15:59] jcs: ugh, found it
[15:59] jcs: and now i get sustained 60kb/sec via fetch

While using the excellent
Hex Packet Decoder
on packets printed out from the BlueSCSI’s console, I noticed that packets were
coming in through Wi-Fi properly, getting added to the ring buffer, but then
getting corrupted before they were being sent out through SCSI.
This turned out to be a dumb mistake I made when cleaning up the code to use
#define constants which ended up reversing the dimensions of the ring buffer
so it became an array of packets[packet_size][queue_size] instead of

When storing packets, instead of properly writing to packet[1] which should
have been packet_size (1520) bytes offset from packet[0], it was writing at
offset queue_size (30), in the middle of packet[0].
This didn’t matter if packet[0] had already been transmitted to the Mac, but
on larger transfers where the queue has multiple incoming packets to transfer,
the current packet has the next packet written to the middle of it.
The delay and restart seen was the TCP stream not getting an expected packet
because it was corrupted, the sending side not getting an ACK for it, and then
having to timeout and re-transmitting it.

Mac Plus and Portable

Once transfers were working at proper speeds, Eric
a beta build of the BlueSCSI firmware and we got some initial feedback on it.
Notably it broke booting hard disks on the Macintosh Plus, which I hadn’t been
testing with because I was using mine for other things and testing meant
constant reboots.
The Macintosh Plus and Macintosh Portable have notoriously “special” SCSI
booting code in their ROM due to them being released before the SCSI spec was
formalized and the
SCSI2SD/ZuluSCSI/BlueSCSI already need
to handle booting on these machines.

Since I couldn’t leave my favorite classic Mac out in the cold, I dug into what
broke in the BlueSCSI code between the last release and adding my new Wi-Fi
While my firmware changes didn’t directly change any of the disk handling code,
it did bring in newer Arduino, Pico, and cyw43 driver code that could have
broken something.

After wading through a recursive maze of dozens of Git submodules and many hours
of trying to pick apart commits in each one, I finally figured out what broke
the Mac Plus.

[16:37] jcs: ok, the “PlatformIO Setup” commit builds and boots, which moved to a different raspberrypi tree
[16:38] jcs: hard to pick apart the pico-sdk and later changes
[21:17] jcs: i can compile and boot with “Missed a few steps”, “build: change board and core to upstream”, “don’t hard-code watchdog timer id”, “uart_init to 115200”
[21:19] jcs: this leaves out “Booting from SD, and comms with CYW43 working”
[22:06] jcs: getting there…
[22:39] jcs: my mac plus is booted with wifi
[22:40] erichelgeson: Wow! What was the culprit?
[22:43] jcs: this change broke it:

-#define LED_ON()     sio_hw->gpio_set = 1 << LED_PIN
-#define LED_OFF()    sio_hw->gpio_clr = 1 << LED_PIN
+#define LED_ON()     cyw43_gpio_set(&cyw43_state, 0, true)  //sio_hw->gpio_set = 1 << LED_PIN
+#define LED_OFF()    cyw43_gpio_set(&cyw43_state, 0, false)  //sio_hw->gpio_clr = 1 << LED_PIN

[22:45] erichelgeson: Led logic. The first place I’d look when debugging boot issues
[22:46] jcs: right?

Wi-Fi DA

With the Mac Plus now booting, I started writing a Wi-Fi
Desk Accessory
which lives in the Apple menu once installed.
Just like a modern computer with its own Wi-Fi card, I wanted to be able to scan
for networks, change to a different one, and see the current signal strength.

I created the Desk Accessory in
and when launched, it scans the SCSI bus to find the BlueSCSI, then gets the
current network information such as SSID and RSSI.
It then launches a background Wi-Fi AP scan and when the results are ready, it
populates a menu with the AP list.
When a different network is selected, it prompts for the password and then
issues a connection command to the BlueSCSI.

DA Menu
List of nearby networks
Prompting for a password


is the common protocol that Macs use for file and printer sharing.
I use it on my local network with
Netatalk 2.x
to host a file server on a Linux VM that my Mac Plus running System 6 can
access, while also supporting my M2 MacBook Air at the same time which makes it
very easy to shuffle files between the two.
I also use
over AppleTalk to be able to remotely control my
BBS Server Mac Plus
from my workstation Mac Plus, just like using VNC.

Historically AppleTalk ran over LocalTalk, which used cables daisy chained
between Macs and printers.
AppleTalk eventually gained the ability to send packets over Ethernet, which
There are also
that help bridge LocalTalk to EtherTalk.

I had tried getting EtherTalk working in PCE but was never able to receive
anything over my laptop’s Wi-Fi connection, so I just assumed it was not going
to work well over Wi-Fi for BlueSCSI.

I read about an informal
LocalTalk over UDP
specification and thought about possibly integrating it into the
BlueSCSI firmware where it could convert EtherTalk packets it receives from the
Mac into UDP packets, enabling EtherTalk over Wi-Fi.
After looking at the code of
multitalk, I realized that EtherTalk was
just multicast traffic and was likely being received over Wi-Fi just fine, but
that the CYW43439 Wi-Fi chip on the Pico W was filtering it out.

the cyw43 driver we are using to include newer multicast configuration
functionality, I was able to configure the Wi-Fi chip to allow the 08:00:07
prefix used by AppleTalk.
Once that filter was modified, I started to receive EtherTalk traffic over the
Wi-Fi interface and could connect to my Netatalk share.

File server appearing over EtherTalk over Wi-Fi
File server share


The Pico W is not a terribly fast device, but neither are the vintage computers
it’s talking to so it doesn’t really matter.
On a faster Mac, it can do a few hundred kilobits/second which is about on par
with the real DaynaPORT ethernet devices.
Since the packets are all going over SCSI, doing an upload or download of a file
that has to be read or written to the SCSI disk can put quite a bit of
contention on the SCSI bus.

The biggest issue with this project is probably the tiny integrated antenna on
the Pico W which limits Wi-Fi reception and throughput.
Especially once it’s been put into a laptop or other metal cage, its signal
strength can suffer quite a bit.
Unfortunately the Pico W has no provision for an external antenna and I’m not
sure how easy it is to hack one in, but this would certainly be helpful for
portable machines like the Macintosh Portable or 68k PowerBooks.


pull request
for the BlueSCSI firmware implementation is still pending as more people test
out the
beta firmware
and report bugs.
The next major firmware release will have full Wi-Fi support and
BlueSCSI distributors
are already shipping v2 units with Pico W boards as an option.

BlueSCSI v2 in a Macintosh Portable
BlueSCSI v2 in a PowerBook 180

The Wi-Fi Desk Accessory for System 6 and 7 will be released shortly as well
once I do a bit more testing.
Without it, Wi-Fi support still works with the SSID and password
in the bluescsi.ini file on the SD card.

By the way, I’ll have a table with some of this Macintosh stuff at the
Vintage Computer Festival Midwest
September 9th and 10th so if you see me there, say hello.

Source link