Atari Controller Test Rig
Long-story-short, I've got a new night-job, bringing a large quantity of Atari-related paraphernalia back to life. I've done it before with the 2600 Jr, and I'm ready to do it again, and again, and again, with this batch.
First up is a box of gamepads and controllers. My initial plan was to get one of the Atari units in a known-state, and then test the controllers from there... but that could lead to issues if the console wasn't actually 100%. Instead, why not just rig up a DB-9 port to a simple 5v LED circuit to test each button?
Google will produce a crap-load of results for Atari Joystick Pinout, so find one of them and get started. I chose this one. It turns out the controllers are very straight forward... they just act as a conduit to ground. Pin 8 is the common ground wire and all buttons (directional-pad inclusive) just join their respective pin to this wire.
The above rig was therefore constructed. Voltage is supplied from my desktop power supply and a miriad of LEDs were selected from the junk box. A selection of 48ohm resistors tie them all to the 5v rail. Their anodes all go to a respective pin on the controller port... starting with Up, Down, Left, Right, A, B from the left-most green LED. Of course, A and B are contentious, as the 2600 only utilises one fire button. Even better, the DB-9 socket also supports trigger, so that's the clear LED placed awkwardly on the left-hand side.
First controller to be tested was an Atari gamepad and it instantly misbehaved. Upon opening it, I found that both A and B buttons were tied high with resistors.
A little googlin' declares that these gamepads are actually for the Atari 7800, which supported two buttons. They've nicely made them backwards compatible though, allowing either button to be the standard button for the Atari 2600 jr. Regardless, those pull-up resistors meant that my A and B button LEDs were always dimly-lit!
Upon pressing either button, their respective LED fully-lit, and so did the left-most trigger LED. This makes me think that trigger is the actual 'button' for the Atari 2600 Jr and A/B are for newer systems. Regardless, the unit still had an issue. For those keenly-observing the photos up until this point, you'll have guessed that the directional pad's right button was crapola. It worked sometimes... and then it worked all the time when you jiggled the cable at the entry-point to the controller. So, what to do? Truncate!
Take a good length off, away from the game pad. Cable fractures, when entering casing/housing, are a very standard thing. Usually, very much like this unit, there's 'protection' inside the casing where the cable is held in-place to prevent it from being wrenched out and putting pressure on internal components. This 'protection' in this case is a zig-zag of pins to hold the cable in place without putting serious pressure on it.
For this unit, this 'protection' has done its job and kept the internals safe, but the cable has instead formed an issue directly after it exits the controller case. Here, thanks to humans like me, waving the controller around (rather than pressing the correct buttons), causes undue stress internally and ruptures the wires. In this case, it actually severed the wire that conducts a directional-right press.
As above, strip the newly truncated cable and tin all ends. Once done, de-solder the original chunk of cable, re-soldering the newly cut ends in the same order. Make sure to keep the white bridging wire between both PCBs. Finally, run the cable through the zig-zag and hold it there for a bit to make sure it understands its new role. If you just place it and let go then the cable tends to want to return to it's standard straight-line form. It's actually tough for a thick cable to make those curves, but as mentioned above, it's for the sake of the guts of the contorller.
Finally, test, test, test and test again! Ah... that GREEN RIGHT LED is beautiful.
Atari 2600 Jr – Recapping + Controllers + Composite
Another one of these little units came across my workbench. This time it was a full set with two joysticks and a lot of games... including a boxed version of Frogger! I'd played with one of these before in my previous-previous apartment, so it must be nearly 4 years ago that I met my first Atari. This one wasn't as clean-and-tidy as the previous version, but it still worked nicely.
The first task was to upgrade the unit to composite output, so I jumped over to my previous post on the topic. I purchased all the components needed from Jaycar and, just before I was about to solder to the pins on the IC, realised that the actual mod instructions showed you where to solder. Not to the pins of the IC, but to the legs of the surrounding resistors.... the diagram is even colour-coded. I therefore also didn't have to scratch back a ground pad either!
In no time, the composite signal was being sent out and my TV Tuner card was picking it up nicely. Whilst I was performing the mod, I noticed that the surrounding electrolytic capacitors weren't looking the cleanest, so I replaced those too. After another trip to Jaycar, purchasing 4x 4.7uf and 1x 2200uf (unfortunately they didn't stock double-ended!) capacitors, I went about removing the old ones and soldering in the new ones. Solder wick really works well here to clean the holes in the PCB prior installing the new capacitors. The positive pins are also nicely marked on the PCB.
With everything replaced, there was no noticeable change in video quality or system stability, but neither were a problem to start with. This was more for longevity! I slapped in the multi-cart and tried Pitfall out. The Quickshot controller worked OK, but felt very sticky and the buttons weren't responding to each keypress... what to do? Pull it apart.
The board was not clean... so I grabbed some isopropyl wipes and gave it a good once-over. I also re-soldered the main A button wire as it had previously been compressed by the case and didn't look like it'd hold out much longer. With the unit back together, I could now jump on-command with the button on the base, but the trigger button up top wasn't overly responsive. The stick itself has three screws that hold it together, so I popped them out to have a look.
Turns out the top button had been mashed to within an inch of its life and the previous players had actually punched a hole in the PCB, removing the trace that the button was meant to make contact with.
A little bit of solder was added, which caused a height increase of the pad. I was slightly concerned that this would mean the button could mis-fire, but the spring prevented that from occurring... instead it just meant the button didn't have to travel as far to make contact. I could now jump through Pitfall reliably! Mario Bros was also now a lot more fun!
I suppose the final step now is to find a new ball for the top of this chewed-on stick!
Sega Mega Drive – Composite + Region-Free
On a total tagent from recent Amiga stuff, I found this in a box whilst I was moving house. I'd totally forgotten that I'd picked it up from a flea market prior to the Christmas Trip overseas.
I grew up a Nintendo-kiddie with Super Mario Bros and Duck Hunt, so the likes of California Games (oops, that's master-system-vintage) and Sonic were a weird adventure whenever I went to friend's houses. This unit arrived slightly scratched-up, but in perfect working condition. It came with a power pack and RF switch, but I wanted Composite output... so I started googlin' for hacks. Then I looked at the back of the machine and realised it had an 8-pin DIN for A/V output. A quick search found off-the-shelf cables, as I didn't have a properly degree'd DIN plug available that'd fit the socket. Your standard 8-pin DIN has the top two outer pins at a different degree and therefore wont fit.
Instead I had to make one from a 5-pin DIN as it turns out the pinout of the A/V Output port has all the pins I'll need at 3 o'clock, 6 o'clock and 9'oclock!
I purchased a 5-pin DIN port from Jaycar and hacked a standard stereo composite RCA video cable in half. From there, I joined ground together and soldered that to pin 3 on the 5-pin DIN. I then twisted L+R together, as this unit produced MONO sound and soldered that to the left-most pin, when looking at the back of the plug. Finally, the central wire from the yellow video plug was soldered to the right-most pin.
From here, the unit worked perfectly! Of course, to test I only had one game...
To make this fit, I had to actually gently file the cartridge slot.
Turns out the japanese-release games are square, whereas the Australian (and probably elsewhere) release carts have 2 rounded corners. After making it fit, the game just worked... although it might play slightly faster on a 60hz clock!
PCMCIA Cards on Desktop PCs
The PCMCIA (or PC Card) standard was built for portable machines which involve smaller form-factors than desktop PCs. Similar to ISA and PCI cards in desktop PCs, the cards offered expansion capabilities for portable machines including storage and communications. The most common cards are either ethernet, modem or wireless. Storage became an option with both flash memory cards, IDE interface cards and SCSI cards.
Desktop machines can be fitted out with PCMCIA card interfaces. Below I'll cover ISA to PCMCIA, PCI to PCMCIA and USB to PCMCIA, noting the limitations of each. I've had an IBM External CD-ROM 0991-011 in the collection for a while and I'd always wanted to check out its capabilities noting that it has a sound-card built-in!
The desktop machine that'll be running the tests is a PIII-500 with 512mb RAM. It's got enough storage internally to support multiple versions of Windows, so we can test compatibility across the board. I've actually taken out ethernet and sound cards, and disabled unnecessary onboard peripherals, to prevent hardware conflicts with any installed PCMCIA bridge.
PCMCIA Cards
I've tested the following PCMCIA Cards during this article. I wanted to make sure I had a card from each category, since I'd expected that certain adapters wouldn't handle all types of cards.
Device | Description | Driver |
---|---|---|
SanDisk 1.2gb Memory Card | Flash Storage | Uses the standard Mass Storage Driver |
Belkin 11g Wireless Card | Wireless Network | Download |
IBM External CD-ROM + Sound Card + Gameport | External IDE Interface + Extra | Download.EXE |
I'm pretty much in-love with the IBM External CD. It's got the beautiful 'Aptiva'-esque styling and a bloody sound-card built-in!
Yup, that's the amazing all-inclusive IBM External CD-ROM, but we'll discuss its capabilities at a later date. Following are the two boring (aka. just-work!) cards...
Super boring. They didn't even try to use a differing palette!
PCMCIA Interfaces
To slap a PCMCIA card into a desktop machine, you'll need some kind of adapter. The following are the units that have been tested throughout this article.
Device | Connection |
---|---|
IO-Data CardDock EX/DV | ISA |
Ricoh | PCI |
Ricoh | PCI |
Condor PCI Super Card | PCI |
AirFree | USB |
First up, here's the Condor PCI Super Card. It's huge and seems to have been custom built for a specific chassis? It might actually have been for a Kodak photo kiosk or somesuch where there are card slots on the front of the case. Based on it's length, I could see this card providing ports to the front.
Unfortunately, it wasn't detected by any part of the system!
The other Ricoh 485-based and 475II-based cards...
Hagiwara Sys-Com Airfree
And I-O DATA's CardDock2-EX/DV...
The results are as follows. The basic finding have been that the newer PCI/USB interfaces only support specific classes of PCMCIA devices. Those being Mass Storage and Network. As soon as you bring in a card that needs interrupts or other low I/O ranges then you're out of luck. On the flip-side, newer versions of windows don't support the older ISA hardware, meaning that the ISA PCMCIA bridge that I had just wont work on anything newer than Millenium.
Bridge | Device | Operating System | Result |
---|---|---|---|
IO-Data CardDock EX/DV | All | Windows 98 SE | Fully operational. |
IO-Data CardDock EX/DV | Any | Windows XP | Card cannot be installed. Drivers wont recognise hardware and Add/Remove Hardware doesn't auto-detect it. |
Ricoh 485/475II | Sandisk Flash Storage | Windows 98 SE | Works, but cannot be easily re-partitioned. Needed to use BOOTICE. (see information below) |
Ricoh 485/475II | Belkin 11g Wireless Card | Windows 98 SE | Worked perfectly. Used Odyssey Client 4.52 for WPA2 access. |
Ricoh 485/475II | IBM External CDROM | Any | Failed with resource issues. Hardware could not start. |
Condor Super PCI | Any | Any | Entire card couldn't be recognised. Even the BIOS didn't list it. Going in the bin... but it's so cool-looking! |
Hagiwara Sys-com Airfree | Flash Storage | Windows 98 SE | Works fine. A bit tricky to install on the US English version of Windows 98 SE as the installer just drops out. Works perfectly on Windows 98 SE JP. |
Hagiwara Sys-com Airfree | Belkin 11g Wireless | Windows XP | Works fine, as above with installation. |
Hagiwara Sys-com Airfree | IBM External CDROM | Any | As above with the PCI cards, it just doesn't work at all thanks to resource limitations. |
Partitioning Removable Media In Windows XP Or Lower
I'd somehow managed to trash the partition table on the SanDisk Flash Memory during the testing above. It hadn't caused the resource errors above (I went back and re-tested the scenarios after I'd realised the disk wasn't actually readable), but it had caused errors when trying to access the drive in My Computer... when it actually chose to show up. Both FDISK, DISKPART and Disk Management in all forms/versions/flavours of old-windows didn't want to touch the partition table. I also tried Partition Magic 7.0, but that didn't care either.
Actually, FDisk in Windows 98 SE JP managed to show the card, but then suggested that it was onlt 136mb in size? I actually tried to follow through with it and that's what probably really killed the partition table.
Thanks to this post at lancelhoff.com, I was directed to an older version of BOOTICE which disregards all forms of safety and allows you to totally wipe and re-partition removable media in older versions of Windows.
Choose the correct disk and click 'Parts Manage'. You'll be presented with the screen below...
I was expecting an option to set up the actual parition table, but nothing was presented. Instead you need to choose 'ReFormat USB Disk' and choose the top option.
WPA2 on Windows 98 SE
As mentioned above, you can install the Odyssey Client 4.52 on Windows 98 to enable connections to WPA2-encrypted wireless networks.
I expected that I'd have to build a guest network with WEP encryption, or worse - no encryption, to test the wireless PCMCIA cards... but I didn't! This software worked perfectly!
Conclusion
The IBM External CD-ROM is super-cool! The fact that it comes with a sound card inbuilt and a gameport/midiport is awesome. I suppose it's really suited to an older laptop that doesn't have a soundcard. I actually tried using the joystick port and it works fine, but don't expect all joysticks to work 100%. I'll post about that soon.
As for the PCMCIA to PCI or USB, you're mileage may vary. If you just want to use flash storage or ethernet cards, then go for it... but why not just get an ISA or PCI card? I remember back in the day I really wanted a PCMCIA to PCI adapter for a wireless card to join the Canberra Wireless network... as actual PCI wireless cards were still a pipe-dream. That never happened... and now I have a surplus of the technology and no real reason to need it. Actually... that's the point behind too many posts on this blog!
Restoring an Azure DB Bacpac into SQL Express
Every so-often, one receives a request out of the blue to revive things that one has totally forgotten about. In most cases, it's comments on pages on this hideous blog asking questions about things that I've gotten rid of, in one form or another, and can't answer! Fortuantely, this time I could: it was a request to revive a project which had been on ice for a long time, but had been well-backed-up... or so I thought.
Firstly, it took me two days to find the files... not cool. If you shut down a project, get EVERYTHING and put it in ONE LOCATION. The system comprised of a zip of the IIS inetpub folder, a zip of the data drive and finally, a database backup from the SQL-as-a-service database. This, thanks to Azure not providing direct access to the server, takes the form of a bacpac file.
Back in the day, when developing, the preprod server was located on a HP something-something with 44gb of RAM which hosted multiple VMs. It made a fantastic noise when it first booted, making sure the fans could hit the required RPMs, and so it was left on most of the time. It was quite the powerhouse and did everything we needed. To save cost, the preprod server only ran SQL Express, so whenever we needed to back-port the production database to diagnose and squash bugs, we needed to manipulate the backups to make them fit.
What do I mean by this? Well SQL Express (or, at least the old 2014 version running in the VM) isn't as capable as Azure DBs and therefore you needed modify the backups so that they wouldn't throw errors when they were being restored. Below is a perfect example (this happened tonight) of such errors...
All looking OK, taking large amounts of time, and then...
Bang! With is not a valid operator... what's it doing embedded in a SQL script? Let's find out! Did you know that a bacpac file is just a pkzip archive? Install 7-zip, right click on the bacpac file and choose Open Archive.
Nice, contents. You'll find the database tables stored as BCP files in the Data folder and actual entire structure and scripts in the model.xml file. If you have your favourite editor installed correctly, then you should just be able to double-click model.xml and edit the file inline.
We know that the error is about shared access keys, so I CTRL-F'd the relevant keyword and the result was at the very bottom of the file. It's trying to store the logging and auditing on Azure shared storage... which is obviously not a good idea if we're running a private server. It's also totally incompatible with SQL Express, so lets rip it out.
<DataSchemaModel> <Model> ... <Element Type="SqlDatabaseCredential" Name="[https://azure.net/sqldbauditlogs]"> <property Name="Identity" Value="SHARED ACCESS SIGNATURE"> </Element> <Element Type="SqlDatabaseCredential" Name="[https://azure.net/sqldbtdlogs]"> <Property Name="Identity" Value="SHARED ACCESS SIGNATURE" /> </Element> <Element Type="SqlFullTextCatalog" Name="[SnomedCatalog]"> <Property Name="IsAccentSensitive" Value="True" /> <Relationship Name="Authorizer"> <Entry> <References ExternalSource="BuiltIns" Name="[dbo]" /> </Entry> </Relationship> </Element> </Model> </DataSchemaModel>
I also ripped out the Full-Text Searching block above, as shown, and another block much further above that was also referencing this block. Once I'd made all the changes to the zip file, I closed my editor and went back to 7-zip.
Yes, 7-zip, I very muchly would love to commit the changes back into this 1gb archive, thank you. From here, I attempted to deploy the bacpac to the server...
Ok, right, by editing a file inside this archive, we've trashed the thumbprint. A checksum is a magical calculation of a chunk of binary data that, somehow, resolves it down to a unique number that indicates the bits. If a bit changes, the checksum number changes and this allows software to know if things have been tampered with. That's what has occurred here... we've actually tampered with it and it's changed the calculation.
The SQL Server has run a calculation on the file and the result has mismatched with something, but with what? Turns out that in the original.xml file is a checksum value! We need to change this value to the new checksum, but how do we calculate that? Don't even bother thinking, just copy the following script into a file called checksum.ps1 and store it in your home directory.
$modelXmlPath = Read-Host "model.xml file path" $hasher = [System.Security.Cryptography.HashAlgorithm]::Create("System.Security.Cryptography.SHA256CryptoServiceProvider") $fileStream = new-object System.IO.FileStream ` -ArgumentList @($modelXmlPath, [System.IO.FileMode]::Open) $hash = $hasher.ComputeHash($fileStream) $hashString = "" Foreach ($b in $hash) { $hashString += $b.ToString("X2") } $fileStream.Close() $hashString
If you've never run scripts in Powershell before, then you'll need to run the following command first if you get an error like 'checksum.ps1 cannot be loaded because running scripts is disabled on this system.'
set-executionpolicy remotesigned
Once sorted, run the following:
PS D:\> checksum.ps1 model.xml file path: d:\model.xml 898D9323A53F0C52B782867B9E8343D8371059A1192849F793CEA168FEAC7AA0
That final number needs to be pasted into original.xml in the archive. Save it back into the archive and deploy once more. Note that, before you try to deploy again, you'll need to detach the half-deployed database and delete the mdf/ldf files that were half-stored in the deployment folders that you set when you tried previously.
I then hit another error, a long way into deployment where the server said that AT was a shit command. Turns out one of my previous developers had tried to cast a datetime into a timezone using the query getdate() AT TIME ZONE 'UTC' AT TIME ZONE 'Aus Eastern Standard Time'. Neat! But SQL Express hates that... so... open the archive, edit model.xml, save it, copy it out of the archive, checksum it, edit original.xml and deploy again...
Fiinnnnaaalllyyyy....!!! IT'S ALIVE! ... Hah... it's not...
dbo.Sort Failed? What dat? Google! There's always someone else that has had your error before... tempdb full? Let's add a new 100gb disk and slap tempdb over there. You can do this by running the following in a new query editor against master...
USE master; GO ALTER DATABASE tempdb MODIFY FILE (NAME = tempdev, FILENAME = 'T:\MSSQL\DATA\tempdb.mdf'); GO ALTER DATABASE tempdb MODIFY FILE (NAME = templog, FILENAME = 'T:\MSSQL\DATA\templog.ldf'); GO
And you'll need to restart SQL before it applies...
The file "tempdev" has been modified in the system catalog. The new path will be used the next time the database is started. The file "templog" has been modified in the system catalog. The new path will be used the next time the database is started. Completion time: 2020-04-08T22:55:04.1929547+10:00
Of course, you'll need to change T drive to something else! Enjoy!... or not... what the hell is this error?
Right, memory? Is that physical memory? Swapfile memory? Or storage space? Fortunately, it's a VM, so lets increase every one of those. If you have the RAM, then that's easy... slide that slider to the right. Disk space is a little trickier. Open the main Virtual Box console and choose Virtual Media Manager from the File menu. From here, select your disks, slide the slider to the right and then hit apply. Note that this will only change the dimensions of the disk, it wont touch the partitions.
So, to extend the partitions, open Disk Management (right-click the start button) and then find the drive. Once located, right-click and choose Extend Volume. If the free space is directly after the drive, it'll already be selected and you can just hit nekk-nekk-finish. Enjoy!
Atari Mouse – Replacing Microswitches
I'd recently acquired an Atari 520STFM (more about that later) and the package came with two mice. One is actually optical and has a switch that allows it to also be used on an Amiga, but it really hated the kitchen bench. I do remember, back in the day, that first-generation optical mice couldn't deal with glossy single-coloured surfaces. The other mouse was the original Atari 2-Button Ball-Mouse. It tracked nicely, but the buttons were as soggy as a wet week?
Open 'Er Up
Very easy to do... two screws up the top-end where the cable enters. Lift at the front, up near the buttons and pull forward to clear the latch at the bottom end.
From here, the microswitches are your PCB-mounted standard, easily available from Jaycar. I toddled off and purchased some of the exact-same replacements, but also two slightly-taller switches. The latter had a much clickier click. The standard replacements were also clickier than the existing switches, but I wanted moar.
A quick look at the circuit board underneath saw that only one side of both microswitches was in use. You can see, per four-hole-mounting of each switch at the top left and top-right of the board, that only the bottom left and bottom right pins are used respectively. The top two are bridged, but the 4th pin on each goes nowhere.
Just because things change over the decades, I quickly checked that my microswitches contacted on the same dimension...
A simple de-soldering saw the old switches out. With the solder removed from the holes in the PCB, I could trial the clearance with the taller switches...
The case was easily re-assembled to test...
But, as you can see, the case wouldn't even close. Testing the buttons, with the case half-ajar, saw them super clicky... maybe toooo-clicky. So I switched in the new same-sized switches (SP0600 from Jaycar) and these were nice!
Although they're not that clicky when they're just in your fingertips in the shop, they're great once mounted in the mouse!
Testing...
All soldered up and plugged in, it was time to test it all out. Previously I had to mash the left-mouse-button a few times to get one click, so I was happy to see that a single click working perfectly!
And yeah, straight into Railroad Tycoon... damn that Grasshopper is a slow first train!
Unleashing An Old 8-bit ISA IO Card
This monster had been sitting in my box-o'-stuff for a while... actually, it seems next month is its three year anniversary in the box... jeesh. This was part of a dismantled 386 PC, used at the Siding Spring Observatory where I assume they needed a lot of IO to control telescopes? Anyway, I've been cleaning/clearing out a lot of junk lately and decided to finally check this thing out. As per that post above, I'd guessed it might be similar to the ACCESS - IOD-64, but I wasn't too sure.
As you can see it's a full length card with four 50-pin IDC headers along the top. There are very few markings on the card, making it near-impossible to work out who the manufacturer was. The bottom left tag area indicates D6004039 and the top-right IC has a serial number indicating 5215001. The card is 8-bit.
Base IO Header Status
Before getting started with anything like this, record everything you have in its initial state. Take photos of all the switches, all the jumpers, all the traces (handy to point fingers at who scratched what), all the pins, all the headers... one always ends up changing too-many-variables and needs a reference point to return to! Even if that point is incorrect (say 0x220 is a furphy?), it's a base to begin testing from again.
In this situation, I also wanted to know what the four ports were outputting, voltage-wise. Turns out the basic idea is as follows:
01 | 03 | 05 | 07 | 09 | 11 | 13 | 15 | 17 | 19 | 21 | 23 | 25 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v |
+12v | +12v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v |
02 | 04 | 06 | 08 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 |
27 | 29 | 31 | 33 | 35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 |
---|---|---|---|---|---|---|---|---|---|---|---|
~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | ~1.4v | +5v |
0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v | 0v |
28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 |
So, the two tables above should be butted together at the 20s... they're just too long to display in one hit. The table, as a whole, describes the first IO 50-pin IDC plug on the board. This is the one closest to the end plate. Note that the port is keyed, that a SCSI cable fits perfectly and that pin 1 lines up with the red wire.
From the image above, pin 1 is in the bottom-right and pin 50 top-left. We can determine that the even pins (top row) 6 to 50 are all ground/common since you can see them bridged via a horizontal trace. Pins 2 and 4 are providing 12v and pin 49 gives you 5v. I may have accidentally grounded all of these supply lines whilst initially testing, but it doesn't seem to have hurt the card! It did nearly melt my test wire though.
One quick thing we could determine here was the "V/G" jumper aligned with each header. My guess that it was either 'voltage' or 'ground' and would probably control the 'rail' of second pins from 6 to 48. A quick swap of the jumper on the first header proved that assumption totally wrong. Instead, when set to V, as they all were at the start, pins 2 and 4 were 12v. When on G, pins 2 and 4 then became GND, just like the entire rest of the row. This jumper does not affect the 5v on pin 49.
I never did work out what the EDP jumper setting did!
Programming Choices
I was going to install Visual Basic 6.0 (mount it with Daemon Tools) and build a pretty windows form, but I quickly realised that there's no direct hardware access to IO ports? I might dig into that again. Instead I downloaded QBasic 4.5 (it's also on the Win98 CD!) and slapped it in a folder on C:\. Note that if you want to play with QBasic on Windows 7++ then use dosbox.
QBasic supports the INP() Function which simply (and unrestricted-ly) reads a byte from an IO address. I had always thought this was only for serial/parallel ports, but it then occurred to me that any port in the system is really just a direct mapping (hopefully with some electrical isolation) of the data lines into the ISA bus. Therefore, if you give the IO address of anything else on the bus, you'll read data from those locations! Here's a list of standard ports for x86 which can, in this scenario, give you an idea of areas to avoid.
Hardware Configuration
Trying to work this out was a blast.... no, really... it took quite a lot of trial and error. If you look at the images above, you'll see the IO Address setting is set to 0-1-0-0-0-0-0-0, and if you look below, you'll even note a sharpie'd address written on the side of the first IDC port! 0x220 base IO address!
Crap, that'll conflict directly with any SoundBlaster... if that's what you happened to have installed. Using my new-found knowledge above, I wrote a really simple QBASIC script to get the data from a range of addresses near 0x220.
FOR PORT# = 220 TO 230 PRINT INP(PORT#) NEXT PORT#
The output was upsetting... just multiple outputs of the number 255. I wondered what the chances were that the dipswitches had been tampered with? Who knows if that inscription of 0x220 was, at all, correct? At the same time, if my pins were floating, then would the card report a 1 or a 0? Knowing where the supply voltage pins where, I danced around them and grounded a few of (what I expected were) the IO lines.
I still didn't get any results around 0x220, so I started searching... but, of course, where do I start searching? A DOS terminal screen gives me about 8 good rows of text space in text-mode, so I set a larger offset and started panning through the addresses. Using the IO Port Mapping for x86, I knew there were a few locations to skip and so I just kept digging.
This got pretty annoying after a while, so I went graphical... it really helped the next step!
DECLARE FUNCTION PortIsFree! (portNum#) DIM DATACACHE(0 TO &H900) AS INTEGER DIM OnOffPoints(0 TO 128) AS INTEGER DIM OnPoint AS INTEGER DIM OffPoint AS INTEGER DIM COLWIDTH AS INTEGER DIM ROWHEIGHT AS INTEGER DIM COLUMNS AS INTEGER DIM MAXADDRESSES AS INTEGER COLWIDTH = 8 ROWHEIGHT = 16 COLUMNS = 75 MAXADDRESSES = &H5A SCREEN 12 RESTORE OffPointData FOR PY = 0 TO 5 FOR PX = 0 TO 3 READ A PSET (PX, PY), A NEXT PX NEXT PY RESTORE OnPointData FOR PY = 0 TO 5 FOR PX = 4 TO 7 READ A PSET (PX, PY), A NEXT PX NEXT PY RESTORE OffCrapData FOR PY = 0 TO 5 FOR PX = 8 TO 11 READ A PSET (PX, PY), A NEXT PX NEXT PY RESTORE OnCrapData FOR PY = 0 TO 5 FOR PX = 12 TO 15 READ A PSET (PX, PY), A NEXT PX NEXT PY OnPoint = 0 OffPoint = 33 otherOnPOint = 64 OtherOffPoint = 80 GET (0, 0)-(3, 5), OnOffPoints(OnPoint) GET (4, 0)-(7, 5), OnOffPoints(OffPoint) GET (8, 0)-(11, 5), OnOffPoints(otherOnPOint) GET (12, 0)-(15, 5), OnOffPoints(OtherOffPoint) PORTSTART# = &H220 SELPORT# = &H220 PREVSELPORT# = &H220 FIRSTLOOP = 1 DATAOUT = 0 CLS DO DIM row AS INTEGER DIM col AS INTEGER col = 1 row = 1 FOR PORT# = PORTSTART# TO (PORTSTART# + MAXADDRESSES) IF (PORT# > 0) THEN IF (FIRSTLOOP = 1 OR SELPORT# <> PREVSELPORT#) THEN LOCATE row, col IF (SELPORT# = PORT#) THEN COLOR 12 ELSE COLOR 15 END IF PRINT HEX$(PORT#); END IF freeport = PortIsFree(PORT#) IF (freeport = 1 OR 1 = 1) THEN DATAIN# = INP(PORT#) CACHED = DATACACHE(PORT#) IF DATAIN# <> CACHED OR FIRSTLOOP = 1 THEN DATACACHE(PORT#) = DATAIN# dotrow = (row * ROWHEIGHT) offset = (col - 1) * COLWIDTH FOR bit = 8 TO 1 STEP -1 IF (DATAIN# AND (2 ^ (bit - 1))) THEN IF (freeport = 1) THEN PUT (offset, dotrow), OnOffPoints(OnPoint), PSET ELSE PUT (offset, dotrow), OnOffPoints(otherOnPOint), PSET END IF ELSE IF freeport = 1 THEN PUT (offset, dotrow), OnOffPoints(OffPoint), PSET ELSE PUT (offset, dotrow), OnOffPoints(OtherOffPoint), PSET END IF END IF offset = offset + 4 NEXT bit LOCATE row + 2, col PRINT " " COLOR 15 LOCATE row + 2, col PRINT DATAIN# END IF END IF END IF LOCATE 1, 1 col = col + 6 IF (col > COLUMNS) THEN col = 1 row = row + 4 END IF NEXT PORT# PREVSELPORT# = SELPORT# FIRSTLOOP = 0 LET K$ = INKEY$ LOCATE 29, 20 IF K$ = "q" OR K$ = "Q" THEN EXIT DO ELSEIF K$ = "/" THEN SELPORT# = SELPORT# + 20 ELSEIF K$ = CHR$(0) + CHR$(77) THEN SELPORT# = SELPORT# + 1 ELSEIF K$ = CHR$(0) + CHR$(75) THEN SELPORT# = SELPORT# - 1 ELSEIF K$ = CHR$(0) + CHR$(72) THEN CLS FIRSTLOOP = 1 PORTSTART# = PORTSTART# - MAXADDRESSES SELPORT# = PORTSTART# ELSEIF K$ = CHR$(0) + CHR$(80) THEN CLS FIRSTLOOP = 1 PORTSTART# = PORTSTART# + MAXADDRESSES SELPORT# = PORTSTART# ELSEIF K$ >= "0" AND K$ < = "9" THEN IF (DATASTEP = 0) THEN DATAOUT = VAL(K$) ELSE DATAOUT = VAL(K$) + (DATAOUT * 10) END IF DATASTEP = DATASTEP + 1 IF DATASTEP > 2 THEN DATASTEP = 0 END IF LOCATE 29, 1 PRINT " "; LOCATE 29, 1 PRINT DATAOUT; ELSEIF K$ = "s" THEN OUT SELPORT#, DATAOUT ELSEIF K$ <> "" THEN PRINT K$; END IF LOOP END OffPointData: DATA 00,10,10,00,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,00,10,10,00 OnPointData: DATA 00,12,12,00,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,00,12,12,00 OffCrapData: DATA 00,9,9,00,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,00,9,9,00 OnCrapData: DATA 00,1,1,00,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,00,1,1,00 FUNCTION PortIsFree (portNum#) IF (portNum# >= &H2F8 AND portNum# < = &H2FF) THEN PortIsFree = 0 ELSEIF (portNum# >= &H170 AND portNum# < = &H177) THEN PortIsFree = 0 ELSEIF (portNum# >= &H1F0 AND portNum# < = &H1F7) THEN PortIsFree = 0 ELSEIF (portNum# >= &H278 AND portNum# < = &H27A) THEN PortIsFree = 0 ELSEIF (portNum# >= &H3B0 AND portNum# < = &H3DF) THEN PortIsFree = 0 ELSEIF (portNum# >= &H3F0 AND portNum# < = &H3F7) THEN PortIsFree = 0 ELSEIF (portNum# >= &H3F8 AND portNum# < = &H3FF) THEN PortIsFree = 0 ELSE PortIsFree = 1 END IF END FUNCTION
Ahh... christmas... this now made it very easy for the next step... determination of the IO address switch. If you look at the photo of the monitor, you'll see from 680 that the first and last pins are grounded. This continues for 3 bytes, then skips a lot and continues again. That was the pattern I created on the cables to make it easier to find the card when I was adjusting the switches below.
Decoding the switch for IO address
Here comes the binary! I checked out the manual for that card I mentioned at the very start and it had a very convoluted way of adjusting the port offset. I chose to have more fun with the qbasic app above which simply displays the IO map of the system. Changing the cards' dipswitches whilst the machine was still on instantly affected the bytes displayed on-screen! The pattern of grounded wires, set on the first and last IO ports on the card, made it easy to distinguish... and, well, as dangerous as it sounds, it worked perfectly! The only slightly concerning thing was the address sharing... some of the areas had a duplicated area 0x400 bytes higher in the port table.
SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | SW7 | SW8 | Output |
---|---|---|---|---|---|---|---|---|
0x3F0,0x7F0 | ||||||||
X | 0x1F0 | |||||||
X | 0x2F0 | |||||||
X | X | 0x0F0 | ||||||
X | 0x370,0x770 | |||||||
X | X | 0x170 | ||||||
X | X | 0x270 | ||||||
X | X | X | 0x470 | |||||
X | 0x3B0,0x7B0 | |||||||
X | X | 0x5B0 | ||||||
X | X | 0x2B0 | ||||||
X | X | X | 0x4B0 | |||||
X | X | 0x330,0x730 | ||||||
X | X | X | 0x130 | |||||
X | X | X | 0x230 | |||||
X | X | X | X | 0x430 | ||||
X | 0x3D0,0x7D0 | |||||||
X | X | 0x1D0 | ||||||
X | X | 0x2D0,0x6D0 | ||||||
X | X | X | 0x4D0 | |||||
X | X | 0x350 | ||||||
X | X | X | 0x550 | |||||
X | X | X | 0x250,0x650 | |||||
X | X | X | X | 0x450 | ||||
X | X | 0x390 | ||||||
X | X | X | 0x190,0x590 | |||||
X | X | X | 0x290,0x690 | |||||
X | X | X | X | 0x490,0x890 | ||||
X | X | X | 0x310,0x710 | |||||
X | X | X | X | 0x110,0x510 | ||||
X | X | X | X | 0x210,0x610 | ||||
X | X | X | X | X | 0x410 | |||
X | 0x3E0 | |||||||
X | X | 0x5E0 | ||||||
X | X | 0x2E0,0x6E0 | ||||||
X | X | X | 0x4E0 | |||||
X | X | 0x760 | ||||||
X | X | X | 0x560 | |||||
X | X | X | 0x660 | |||||
X | X | X | X | 0x460 | ||||
X | X | 0x3A0 | ||||||
X | X | X | 0x5A0 | |||||
X | X | X | 0x2A0,0x6A0 | |||||
X | X | X | X | 0x4A0 | ||||
X | X | X | 0x720 | |||||
X | X | X | X | 0x520 | ||||
X | X | X | X | 0x620 | ||||
X | X | X | X | X | 0x420 | |||
X | X | 0x7C0 | ||||||
X | X | X | 0x1C0 | |||||
X | X | X | 0x6C0 | |||||
X | X | X | X | 0x4C0 | ||||
X | X | X | 0x740 | |||||
X | X | X | X | 0x540 | ||||
X | X | X | X | 0x640 | ||||
X | X | X | X | X | 0x440 | |||
X | X | X | 0x380 | |||||
X | X | X | X | 0x580 | ||||
X | X | X | X | 0x680 | ||||
X | X | X | X | X | 0x480 | |||
X | X | X | X | 0x300 | ||||
X | X | X | X | X | 0x500 | |||
X | X | X | X | X | 0x600 | |||
X | X | X | X | X | X | 0x400 | ||
X | 0x7F0 | |||||||
X | X | 0x5F0 | ||||||
X | X | 0x6F0 | ||||||
X | X | X | 0x4F0 | |||||
X | X | 0x770 | ||||||
X | X | X | 0x570 | |||||
X | X | X | 0x670 | |||||
X | X | X | X | 0x470 | ||||
X | X | 0x7B0 | ||||||
X | X | X | 0x5B0 | |||||
X | X | X | 0x6B0 | |||||
X | X | X | X | 0x4B0 | ||||
X | X | X | 0x730 | |||||
X | X | X | X | 0x530 | ||||
X | X | X | X | 0x630 | ||||
X | X | X | X | X | 0x430 | |||
X | X | 0x7D0 | ||||||
X | X | X | 0x5D0 | |||||
X | X | X | 0x6D0 | |||||
X | X | X | X | 0x4D0 | ||||
X | X | X | 0x750 | |||||
X | X | X | X | 0x550 | ||||
X | X | X | X | 0x650 | ||||
X | X | X | X | X | 0x450 | |||
X | X | X | 0x790 | |||||
X | X | X | X | 0x590 | ||||
X | X | X | X | 0x690 | ||||
X | X | X | X | X | 0x490 | |||
X | X | X | X | 0x710 | ||||
X | X | X | X | X | 0x510 | |||
X | X | X | X | X | 0x610 | |||
X | X | X | X | X | X | 0x410 | ||
X | X | 0x7E0 | ||||||
X | X | X | 0x5E0 | |||||
X | X | X | 0x6E0 | |||||
X | X | X | X | 0x4E0 | ||||
X | X | X | 0x760 | |||||
X | X | X | X | 0x560 | ||||
X | X | X | X | 0x660 | ||||
X | X | X | X | X | 0x460 | |||
X | X | X | 0x7A0 | |||||
X | X | X | X | 0x5A0 | ||||
X | X | X | X | 0x6A0 | ||||
X | X | X | X | X | 0x4A0 | |||
X | X | X | X | 0x720 | ||||
X | X | X | X | X | 0x520 | |||
X | X | X | X | X | 0x620 | |||
X | X | X | X | X | X | 0x420 | ||
X | X | X | 0x7C0 | |||||
X | X | X | X | 0x5C0 | ||||
X | X | X | X | 0x6C0 | ||||
X | X | X | X | X | 0x4C0 | |||
X | X | X | X | 0x740 | ||||
X | X | X | X | X | 0x540 | |||
X | X | X | X | X | 0x640 | |||
X | X | X | X | X | X | 0x440 | ||
X | X | X | X | 0x780 | ||||
X | X | X | X | X | 0x580 | |||
X | X | X | X | X | 0x680 | |||
X | X | X | X | X | X | 0x480 | ||
X | X | X | X | X | 0x700,0x300 | |||
X | X | X | X | X | X | 0x500 | ||
X | X | X | X | X | X | 0x600 | ||
X | X | X | X | X | X | X | 0x400 | |
X | 0x7F0,0x3F0 | |||||||
X | X | 0x5F0 | ||||||
X | X | 0x6F0 | ||||||
X | X | X | 0x4F0 | |||||
X | X | 0x770 | ||||||
X | X | X | 0x570 | |||||
X | X | X | 0x670 | |||||
X | X | X | X | 0x470 | ||||
X | X | 0x7B0 | ||||||
X | X | X | 0x5B0 | |||||
X | X | X | 0x6B0 | |||||
X | X | X | X | 0x4B0 | ||||
X | X | X | 0x730 | |||||
X | X | X | X | 0x530 | ||||
X | X | X | X | 0x630 | ||||
X | X | X | X | X | 0x430 | |||
X | X | 0x0x7D0,0x3D0 | ||||||
X | X | X | 0x5D0 | |||||
X | X | X | 0x6D0 | |||||
X | X | X | X | 0x4D0 | ||||
X | X | X | 0x350 | |||||
X | X | X | X | 0x550 | ||||
X | X | X | X | 0x650 | ||||
X | X | X | X | X | 0x450 | |||
X | X | X | 0x390 | |||||
X | X | X | X | 0x590 | ||||
X | X | X | X | 0x690 | ||||
X | X | X | X | X | 0x490 | |||
X | X | X | X | 0x310 | ||||
X | X | X | X | X | 0x510 | |||
X | X | X | X | X | 0x610 | |||
X | X | X | X | X | X | 0x410 | ||
X | X | 0x3E0 | ||||||
X | X | X | 0x5E0 | |||||
X | X | X | 0x6E0 | |||||
X | X | X | X | 0x4E0 | ||||
X | X | X | 0x360 | |||||
X | X | X | X | 0x560 | ||||
X | X | X | X | 0x660 | ||||
X | X | X | X | X | 0x460 | |||
X | X | X | 0x3A0 | |||||
X | X | X | X | 0x5A0 | ||||
X | X | X | X | 0x6A0 | ||||
X | X | X | X | X | 0x4A0 | |||
X | X | X | X | 0x320 | ||||
X | X | X | X | X | 0x520 | |||
X | X | X | X | X | 0x620 | |||
X | X | X | X | X | X | 0x420 | ||
X | X | X | 0x7C0 | |||||
X | X | X | X | 0x5C0 | ||||
X | X | X | X | 0x6C0 | ||||
X | X | X | X | X | 0x4C0 | |||
X | X | X | X | 0x740,0x340 | ||||
X | X | X | X | X | 0x540 | |||
X | X | X | X | X | 0x640 | |||
X | X | X | X | X | X | 0x440 | ||
X | X | X | X | 0x380,0x780 | ||||
X | X | X | X | X | 0x580 | |||
X | X | X | X | X | 0x680 | |||
X | X | X | X | X | X | 0x480 | ||
X | X | X | X | X | 0x300,0x700 | |||
X | X | X | X | X | X | 0x500 | ||
X | X | X | X | X | X | 0x600 | ||
X | X | X | X | X | X | X | 0x400 | |
X | X | 0x3F0,0x7F0 | ||||||
X | X | X | 0x5F0 | |||||
X | X | X | 0x6F0 | |||||
X | X | X | X | 0x4F0 | ||||
X | X | X | 0x770,0x370 | |||||
X | X | X | X | 0x570 | ||||
X | X | X | X | 0x670 | ||||
X | X | X | X | X | 0x470 | |||
X | X | X | 0x3B0,0x7B0 | |||||
X | X | X | X | 0x5B0 | ||||
X | X | X | X | 0x6B0 | ||||
X | X | X | X | X | 0x4B0 | |||
X | X | X | X | 0x330,0x730 | ||||
X | X | X | X | X | 0x530 | |||
X | X | X | X | X | 0x630 | |||
X | X | X | X | X | X | 0x430 | ||
X | X | X | 0x3D0,0x7D0 | |||||
X | X | X | X | 0x5D0 | ||||
X | X | X | X | 0x6D0 | ||||
X | X | X | X | X | 0x4D0 | |||
X | X | X | X | 0x350,0x750 | ||||
X | X | X | X | X | 0x550 | |||
X | X | X | X | X | 0x650 | |||
X | X | X | X | X | X | 0x450 | ||
X | X | X | X | 0x790,0x390 | ||||
X | X | X | X | X | 0x590 | |||
X | X | X | X | X | 0x690 | |||
X | X | X | X | X | X | 0x490 | ||
X | X | X | X | X | 0x710,0x310 | |||
X | X | X | X | X | X | 0x510 | ||
X | X | X | X | X | X | 0x610 | ||
X | X | X | X | X | X | X | 0x410 | |
X | X | X | 0x3E0,0x7E0 | |||||
X | X | X | X | 0x5E0 | ||||
X | X | X | X | 0x6E0 | ||||
X | X | X | X | X | 0x4E0 | |||
X | X | X | X | 0x760,0x360 | ||||
X | X | X | X | X | 0x560 | |||
X | X | X | X | X | 0x660 | |||
X | X | X | X | X | X | 0x460 | ||
X | X | X | X | 0x7A0,0x3A0 | ||||
X | X | X | X | X | 0x5A0 | |||
X | X | X | X | X | 0x6A0 | |||
X | X | X | X | X | X | 0x4A0 | ||
X | X | X | X | X | 0x720,0x320 | |||
X | X | X | X | X | X | 0x520 | ||
X | X | X | X | X | X | 0x620 | ||
X | X | X | X | X | X | X | 0x420 | |
X | X | X | X | 0x7C0,0x3C0 | ||||
X | X | X | X | X | 0x5C0 | |||
X | X | X | X | X | 0x6C0 | |||
X | X | X | X | X | X | 0x4C0 | ||
X | X | X | X | X | 0x740 | |||
X | X | X | X | X | X | 0x540 | ||
X | X | X | X | X | X | 0x640 | ||
X | X | X | X | X | X | X | 0x440 | |
X | X | X | X | X | 0x780 | |||
X | X | X | X | X | X | 0x580 | ||
X | X | X | X | X | X | 0x680 | ||
X | X | X | X | X | X | X | 0x480 | |
X | X | X | X | X | X | 0x700,0x300 | ||
X | X | X | X | X | X | X | 0x500 | |
X | X | X | X | X | X | X | 0x600 | |
X | X | X | X | X | X | X | X | 0x400,0x800 |
So from above... the magical calculation is... dunno... but the weird sharing of XXX with XXX+400h was confusing and slightly dangerous when both ranges could conflict with other hardware in the system!
Port Mapping
So now we know how to set the base address, how do we then actually work with the data? The card needs 16 consecutive IO Ports, so please make sure you find a space in the address table that has the capacity. You don't want it interfering with other hardware in your system. Actually, the code above gives you a really good idea as to what areas in use and which are free. Also make note of the 'ghosting' that seems to occur with the lower address ranges. The table below expects you've set the above address to 0x220, but this means the data will also be visible on 620! This could easily interfere with an AWE Soundcard.
Port | Usage |
---|---|
0x220 | CN1 pins 33,35,37,39,41,43,45,47 |
0x221 | CN1 pins 17,19,21,23,25,27,29,31 |
0x222 | CN1 pins 01,03,05,07,09,11,13,15 |
0x223 | Control Register for CN1 |
0x224 | CN2 pins 33,35,37,39,41,43,45,47 |
0x225 | CN2 pins 17,19,21,23,25,27,29,31 |
0x226 | CN2 pins 01,03,05,07,09,11,13,15 |
0x227 | Control Register for CN2 |
0x228 | CN3 pins 33,35,37,39,41,43,45,47 |
0x229 | CN3 pins 17,19,21,23,25,27,29,31 |
0x22A | CN3 pins 01,03,05,07,09,11,13,15 |
0x22B | Control Register for CN3 |
0x22C | CN4 pins 33,35,37,39,41,43,45,47 |
0x22D | CN4 pins 17,19,21,23,25,27,29,31 |
0x22E | CN4 pins 01,03,05,07,09,11,13,15 |
0x22F | Control Register for CN4 |
Writing to the ports
With the QBASIC code above, you can use the Up and Down arrows to paginate. You can then use the left and right to select a specific address. Use the forward-slash key to skip 10 addresses at a time. Once on an address, you can write a value to the selected port by typing that number in and pressing the letter S. From here I worked out the following:
- You can only write out values to the bytes if you send a value to the control register first.
- If you write a number to one of the three blocks of pins, then it'll set all associated bits HIGH.
- Sending a 0 therefore sets them all LOW, 255 will set them all HIGH.
- The final control register allows you to set all three bytes to 0 or 255 quickly. But I haven't totally decoded what the required values are.
I'm still trying to ascertain how it works. The EDP jumper seems to determine if one is allowed to send bytes to the ports, but I haven't correctly determined exactly how.
As is, the card could easily be used to control/read binary bits in its default setting.
Let's control a model railway!
This card would've been perfect when I was younger. I remember back at Lyneham Hockey Courts in Canberra, there was an engineer who'd built a smallish model railway at one of the conventions and it was totally computer controlled. There was this hulking XT/AT machine next to the layout with ribbon cables running everywhere. A card with this much IO would've been fantastic for sensors, point control and even throttles. I might do that now, just for fun, using some of the off-the-shelf Arduino modules in my box-o'-junk. Sure, it's cheating, but I'll still be using the full power of the card.
An L298 can provide the throttle, but it needs a variable resistance fed into this. We can use a Resistor Ladder to provide this, as we have so many pins available.
I might just put it back in its box for the next rainy day. If anyone has further documentation on this card, then please leave a comment!
VTech Socrates – Educational Video System
This poor unit was found in a box of random junk at the local tip shop. It's a VTech Socrates educational computer based of the Zilog Z80 chipset. It seems to have standard RF input/output, but someone has gone ahead and wired in their own antenna cable? The couldn't be bothered finding a screw-to-plug antenna adapter?
After working out how to tune an analog signal on my TV, I applied 12v... A very slow screen started to appear! Is that Johnny-5?
Giant Bomb's Review of the system doesn't give a favourable view. It seems that the unit had a 'very short life' due to slow graphics/animation and little software being available. It does mention the extra items, such as the mouse and touchpad... of which I've been unable to find physical examples of.
The expandability is obvious in the above photos.. you can see the Cartridge slot and Expansion slot on either side of the motherboard.
Composite Mod
Just like most items that come across my workbench, I don't believe there's any need to keep them as RF-output. RF modulators were a requirement back in the day as TVs only had RF-antenna input. RF was fine for terrestrial signals, where a cable would be slightly inconvenient! Not so when the unit producing the a/v output was located right next to the TV. Once composite signals started appearing on TVs, there was absolutely no need to convert to-and-from RF. Of course, it was already too late for devices that only had RF output.
The RF modulation circuits in these units usually consist of a silver modulator unit and the inputs to this are more-or-less the exact composite signal required. Removing (or bypassing) the modulator is an easy step and RCA sockets can usually be installed somewhere in such units. Here's how to do it on a Famicom.
Anyway, back to the Socrates. The original owner had already trashed the RF modulator, so I chose to remove it. The ribbon that runs to it is pretty hard to work with, but I spliced into it and ran the wires to RCA sockets instead. I provided both right and left audio plugs, but they're both wired to the same single mono audio output signal.
From there, the picture was clean and crisp. The sound too! Of course, it's always hard to take photos of CRTs.. I tested it on the BeoVision MX 7000.
And.. about that refresh rate... this was it trying to draw a spelling game over about 12 seconds...
I was presented with R A I O D as a scambled word challenge...
Nope.. it doesn't know what RAID-0 is.
Cartridges
A short time googling found me at Team Europe's blog post regarding the innards of a VTech Cartridge. How cute are they? Designed after a floppy drive, of which you jam in the side of the machine when it's turned off.
The insides look as simple as an EPROM on a board with a single capacitor? I was about to ask for the board pinout, as it seems there's one or two traces under the chip, but then I came across their post from this year regarding their multicart! Hah, it's exactly as expected... an EPROM on a very simple circuit board. They've used an EPROM that's 8x too large, to fit 8 images (all games ever produced) on the chip... you then select the start offset with the dipswitch.
I've sent out a message requesting one... let's hope they're still available!
Setting up a Palm OS/Sony Clie Development Environment
Why would I do this in 2019? Because fun! I found this unit in Malaysia and wanted to try and control my BeoVision MX 7000 with it. Turns out that none of the software I tried wanted to work! Actually, even at first, I had trouble trying to install the applications. Everything wanted HotSync? Muhahaha... I remember those old days! The I found this forum thread where everyone is just like "duh, copy the files to the LAUNCHER folder"... and so, I did.. and so, well, the apps worked... but that was about it.
Of course, before even getting the MS to read, I needed to find a reader that would support it. There seems to be (at least) three types of MemoryStick and this thing uses the very first version. I tried my standard card-reader that I use constantly for my camera's SDHC card, but this wouldn't read the MS at all. Fortunately, there was an older reader (with CF slot!) in my box-o-junk that happily read the MS. Of course, it then didn't read the SDHC, so there was a lot of juggling to get data transfered.
So, the apps.. OmniRemote Pro was the closest to work. It supported learning and even supposedly 'recognised' my fake BeoVision remote. But no attempt to send the signal back to the TV worked.
At least I now knew how to run external programs... let's write one!?
Cygwin + PRC-Tools
GCC for Palm OS (or PRC Tools) is a self-contained compiler that sits on top of Cygwin. It even comes with source code examples. I've recorded the steps below to set up a functional development environment... the code even worked on the Sony!
Firstly, download Cygwin 32-bit Setup from here. 64-bit won't work! Once downloaded, run setup-x86.exe -X from the command line to allow unsigned packages. Choose a local mirror and then add http://prc-tools.sourceforge.net/install in the User area below. After adding, both mirrors will be selected... hit next. Search for prc and check the selections...
Make sure you then also choose to install make and pilrc. Hit next and let it all install. Whilst that's happening, go and download the Palm OS SDKs from here. Yes, you'll need to download the whole lot (Download as Zip from the root github folder), but it's not that big. Once downloaded, extract the contents to a new directory called c:\Cygwin\PalmDev.
If everything has been done correctly, then open the Cygwin Terminal and run palmdev-prep.exe.
$ palmdev-prep.exe Checking SDKs in /PalmDev sdk-1 headers in 'include', no libraries sdk-2 headers in 'include', no libraries sdk-3.1 headers in 'include', no libraries sdk-3.5 headers in 'include', libraries in 'lib' sdk-4 headers in 'include', libraries in 'lib' sdk-5r3 headers in 'include', libraries in 'lib' sdk-5r4 headers in 'include', libraries in 'lib' When GCC is given no -palmos options, SDK '5r4' will be used by default Writing SDK details to configuration files... ...done
Yes, we got it installed!... Now grab the code from this link and try and compile it...
$ make m68k-palmos-gcc -O2 -Wall -g -c -o helloworld.o helloworld.c 3 [main] m68k-palmos-gcc (11268) C:\cygwin\bin\m68k-palmos-gcc.exe: *** fatal error in forked process - couldn't allocate heap, Win32 error 487, base 0xEF0000, top 0xF50000, reserve_size 389120, allocsize 393216, page_const 4096 915 [main] m68k-palmos-gcc (11268) cygwin_exception::open_stackdumpfile: Dumping stack trace to m68k-palmos-gcc.exe.stackdump 1 [main] m68k-palmos-gcc 1983 dofork: child -1 - forked process 11268 died unexpectedly, retry 0, exit code 0xC0000142, errno 11 m68k-palmos-gcc -O2 -Wall -g -o helloworld helloworld.o pilrc -q -ro -o helloworld.ro helloworld.rcp build-prc -n helloworld -c helo helloworld helloworld.ro
That error looks a little scary... but whatever... let's see what happens?! Noooo waaaaay....
We got an icon! Does it work?
Look at that glorious string of redundant text! Next I'll come back and write actual source to talk via IRDA. Maybe even to my Matsucom On Hand PC?
Sony Clie PEG-SJ30 (N50)
I picked up this Sony Clie at the Chinatown fleamarkets in Kuala Lumpur during the last trip and have finally gotten around to testing it. As expected, the battery was dead-flat, so I didn't have much hope. Also, no cables or other accessories... so how to bring it back to life?
I found a standard rechargeable 3.7v battery after unscrewing the back panel. I say 'standard', as this voltage seems very popular for small rechargeable devices! I don't have any rechargeable batteries on hand... but then remembered something else I'd picked up in Malaysia!
The current battery was dead, so I snipped the connector and wired it into the drone battery...
Niiiiice! It works! But this isn't a good answer... the battery is too big for the unit. Off to Jaycar I went to pick up a GT4195 battery. This one happens to be the correct voltage and fits perfectly!
Off the shelf, the battery came with zero charge! That's pretty unusual actually... I don't think I've ever bought a rechargeable battery from anywhere and have it have absolutely no juice. This straight-away presented a problem... I have no charger for this PDA, meaning that I can't seal the battery in and charge externally. So, I had to wire in another plug to use the drone charger to keep this thing going. Not 100% awesome, but it's a workable solution.
After a full charge, or so the usb-charger reckoned with its red light off, I gave it a quick test. All worked perfectly with this smaller battery!
I'm also surprised it accepted the year 2019!
Before I knew it... we were at the home screen.
Meanwhile, it has a Memory Stick in the slot... a quick check found the following...
Joy! Time to format that and get some IRDA software to try and control the BeoVision MX 7000.