Subscribe via RSS
19Nov/240

Toshiba T3200 + Fairy YL-23 IC Tester

This beast happened to be in a store-room at work and was about to go into the e-waste bin... rest assured I prevented that from occurring! Thanks to my eagerness, I was then tasked with taking a backup of the HDD. Would it even boot?

Sorry, yes, it was already in pieces on the workbench... I should care more about blog photography, I suppose.

Don't apply power, check the caps first!

I didn't want to send unwieldly voltages into the motherboard, so I pulled the unit apart. The unit was caked in factory 'dust', so this also gave me a good chance to clean it. Thankfully there were actually no problems detected internally.

I had planned to extract the data by extracting the IDE HDD, but it turns out this unit is MFM! I'm going to have to do something trickier.

First boot in 25 years

Although this unit seems to have had a hard life, I was quite sure it hadn't been turned on in ~25 years. Knowing that the capacitors in the power supply were stable, I plugged in the 240v cable and sent it. The fans, display and HDD all came to life!

Look at that glorious screen! I've seen numerous posts where these screens have expired, so I was very happy to see this come to life.

Floppy woes

The floppy disk would seek to track zero and nothing else. As I've done on the PC-98s before, the first bet is to clean the heads with isopropyl. That didn't work, so I then extracted the drive and checked out the drive-speed sensor circuit.

Oh sure, that cap is crap... I touched it with tweezers and it took the pads with it! Fortunately the traces could be beeped out and a ceramic cap was installed instead. With my bodge in place, a DOS 5.0 boot disk loaded!

Backing up the HDD

The HDD was loading fine, so I had to find a way to get the data off the system. Via floppy would be a last-resort as it'd take a few of them. As nostalgic as spanned-volume pkzip'ing is, I'd rather not. Instead, I grabbed my trusty XT-IDE and found a 48mb CF card. I used the default configuration on the card, only setting the CF to 'slave' via the dip-switch.

Sure enough, with the CF as master, the card booted into it's copy of DOS 5.0 and XCOPY was used to transfer the entire HDD contents (all 19.4mb!) onto the CF card. Success!

Games!

The CF was also used to bring games to the system. Police Quest, Space Quest, Kings Quest, Alleycat and... A-Train? Railroad Tycoon?

Everything of the correct vintage worked fine!

Fairy YL-23 EPROM Programmer And Chip Tester

I'd purchased this ages ago via FB Marketplace and hadn't found a need for it yet. Also, being ISA, I'd have to keep my P2 in an accessible location to be making use of this device. What better host than a chunky 286 laptop? Yes, this laptop has ISA slots!

With the card in the slot, I realised I had no idea how to orient the cable! I extracted it again and checked for grounding. Here's a clear example for anyone else:

Back in, with the laptop powered on, no life was shown in the unit. The software was downloaded (two exe files, only YL.EXE is really needed!) and copied over via CF card.

Cool! The menu was easy enough to navigate. I chose to test some 74LS00 chips first:

Running the IC Tester (option 1) made the software try and guess the model of IC:

You could also force a test of a specific chip:

I then grabbed some SRAM and tested that:

Very nice. It all just worked!

Filed under: Retro No Comments
10Sep/243

PC-98 – 110-Pin Cables And External I/O

This was something I had always wanted to try: I had my trusty PC-9801N NS/A and the 110-pin port worked, as I'd tested it with both an Ethernet Adapter and SCSI Adapter.

What else can you do with this port? Well, it turns out that it's a full interface to the PC-98's C-BUS. I mean, that's why the Ethernet and SCSI adapters work so easily... they're actually mini C-BUS cards built to fit the portable asthetic of the 98-Note and its 110-pin connector.

It turns out that NEC released an entire external chassis, known as the PC-9801N-08 External I/O Unit, to hold three C-BUS cards. This connects to any 98-Note with a 110-pin port (later 98-Notes have a much larger port!) via a chunky cable, of which I've never seen one in the flesh. What I have seen are 110-pin to Floppy Drive cables, but these have a centronics 50-pin plug at the far end, instead of the required 110-pin at both ends.

The moons aligned: The right items appeared on Buyee at the right time for the right place... so I collected them.

Can I make a cable?

I set off to find the appropriate 110-pin connectors, but the best I could gather were 'external floppy cables' for the 98-NOTE. Fortunately, these have the correct connector on one end!

Look at that tiny-centronics goodness! Before-long, I had the casing off and the plugs dismantled with minimal damage.

The plastic casing can be prised off...

As expected, the floppy interface didn't need to use all pins, so only a small amount of wiring existed. The plugs are actually crimp-style, so further dismantling occurred to get them apart.

Ok, we're torn-down with minimal damage... a few broken clips, but nothing structural! I grabbed the nearest 50-pin IDC SCSI ribbon and tried to make it fit...

And it was never going to work as the cable was too thick. I couldn't think of viable alternatives... so I went down the solder route. DON'T DO THIS!

I ended up wrecking that plug, so jumped back on the auction site and shelled out too much for yet another 110-pin to floppy cable... it's in the mail.

The proper way to re-wire!

I ended up murdering a few data cables, that had been happily chilling in my box'o'junk, whilst looking for appropriately-girthed wires of a proper length. First up was a 50-pin Centronics SCSI cable... how could that not be tiny-strand?

Crap photo... but that far-left light-blue is the SCSI wire and you can see it's double the thickness. What else? Apple Serial cables were also too thick...

And then I hit the gold mine! DVI cables! Who doesn't have 6 million of the ugly things sitting in a box? And so I got started...

Some of the internal wiring of the DVI cable was twisted pair, probably for the colour video signals. These could still be used, you just needed to strip back more shielding...

The wires locked in to the rail nicely and even happily bent 90-deg, as required for the plug.

And look at that! It happened. I then realised I hadn't recorded the colouring, or even started on the other end... so I had to BEEP OUT the entire thing to wire it up. I mean, this was also a good quality verification process!

Meanwhile, as that I'd murdered the plug for the other side with solder, I couldn't even finish it. 75% done though!

Why was it never going to work?

Whilst waiting for the next cable to arrive, I decided I should investigate the I/O Unit end. Whilst beeping out the pins on the 110-pin connector, I realised that both extremeties of both rows of pins were ALL grounded. ALL GROUNDED. Looking at the pinout of the 110-pin port, these should all be +5v or other signals.... there's no way that these should be grounded on the I/O end?

A quick further googl' pointed out the obvious. In this Japanese forum post, one user asks if they can connect the unit straight through and is quickly told (via googl's bad translator):

However, looking at itp's post, it seems that there are cables (2 pieces) and an interface adapter for the expansion box. Without this, it is practically impossible (to connect a laptop directly). If you look closely at the connector on the back of the I/O Unit, it is not 110 pins. The manual says "100-pin connector".

It's what?

Haha... that's one of my 110-pin Ethernet modules lined up against the 100-pin (Yes, NOT 110-PIN!) connector on the I/O side. All that hard work above was NEVER going to work. Then again, maybe I'll finish the cable as it could still function as one-of-two of the cables needed if I ever manage to find/build the interface box! But then I'll still need a 100-pin amphenol plug!?

We'll chalk this one down as a huge (mildly-expensive) time-sinking failure!

Filed under: Retro 3 Comments
31Aug/240

Apache Spark 2.4 EOL

EOL = End of Life. It's dead, Jim. No longer supported. If you get this error in Azure Synapse, then your Apache Spark Pool worker is trying to load v2.4 (INSERT_VERSON_HERE, really... as I'm sure this'll happen in the future as the window rolls) which has been deleted.

RUNTIME_CONFIGURATION_ERROR_VHDOVERRIDENOTFOUND: Livy session has failed. Session state: Error. Error code: RUNTIME_CONFIGURATION_ERROR_VHDOVERRIDENOTFOUND. Cannot find vhd based on override: Message=The system did not find a VHD copy in the system for creating the ClusterName=12341223-5555-4444-3333-63c446fe4d8b, Workspace=synws-d-e-v-d-e-v-01, Subscription=, Location=australiaeast, isVhdOverride=True Source: Dependency.

I'm putting this on the web so others can googl' for it. I had no results and it burnt 1/4 of my weekend. Re-deploy your pools with:

Update-AzSynapseSparkPool -WorkspaceName ws_name -Name pool_name -SparkVersion 3.4

And... cross your fingers. Of course, if you've tried to delete a pool with notebooks attached, then you'll have ERROR, POOL IN DELETED_FAILED STATE and you'll need to create a new temp pool, associate ALL notebooks, delete the old and then rename the new... or create another with the old name and then switch them all back and delete the new... or something. It's a monday problem.

28Aug/240

3Com EtherLink II 3C503 – Boot ROMs

The XT-IDE Universal BIOS is a very cool project, enabling older hardware to support much newer storage devices. The safest way to use it is with a dedicted 8-bit ISA controller card, but there are other ways to get started. If you have an Ethernet card with a spare ROM slot on it, you can program an EPROM with their BIOS and boot from there! Or so I thought... enter the 3Com 3C503.

Willem EPROM Burning: 101

I've discussed using the Willem Programmer before and, since working out the caveats, it's relatively straight-forward. Firstly, make sure you have a known-working version of the burning software installed on a known-working machine with a known-working parallel port. Next, check that you have the EPROM-specific dip switches correct, the power at a suitably-high (with enough current!) level and TOTALLY erased EPROMS. I usually leave my EPROMs to cook for around 20 minutes in my super-dodgy Ultra-Viole(n)t eraser.

Another good note is to make sure that you write them more-than-once when programming. Press the program button on the programming software again and again... so that the EPROM is written and verified multiple times. The software will write a byte and check it, and I've had it where the second programming run will fail. The usual reason is that the EPROM wasn't erased well enough, and that the initial write tinkered with residual data/current in the chip's cells, which then settled. The second write will write/read/check and fail as that cell has changed to another value. Erasing and programming again might work, else that chip needs to go in the bin.

Preparing an XT-IDE Boot EPROM

The default ROM can be downloaded from here. Choose the folder whose name begins with an 'r' and has the highest number. This'll be the most-recent release of the software and should be bug-free on all supported hardware. There's a miriad of flavours of the software, so you'll need to choose the one that's right for your hardware.

Burn it to an EPROM. I chose a 27C256 as I had a spare truckload.

Testing it in known hardware

This is paramount. Don't just slap this in marginal hardware and expect things to work. I found a boring Realtek PCI 8139 NIC and slapped the freshly-minted EPROM in.

It was installed in my PIII-500 workhorse and worked first time!

Just for fun, I inspected the area of system memory where it mentioned the ROM was hosted:

Microsoft(R) Windows 98
   (C)Copyright Microsoft Corp 1981-1999.

C:\WIN98JP\DESKTOP>debug
-d d000:0000
D000:0000  55 AA 10 E9 B5 03 58 55-42 32 31 30 2D 3D 58 54   U.....XUB210-=XT
D000:0010  49 44 45 20 55 6E 69 76-65 72 73 61 6C 20 42 49   IDE Universal BI
D000:0020  4F 53 20 28 41 54 29 3D-2D 00 00 00 72 36 32 39   OS (AT)=-...r629
D000:0030  20 0A 28 32 30 32 34 2D-30 37 2D 32 30 29 00 00    .(2024-07-20)..
D000:0040  61 FC 00 00 04 00 00 00-02 80 00 01 00 00 F0 01   a...............
D000:0050  F0 03 00 0E 1D 00 00 00-00 00 1D 00 00 00 00 00   ................
D000:0060  70 01 70 03 00 0F 1D 00-00 00 00 00 1D 00 00 00   p.p.............
D000:0070  00 00 E8 01 E8 03 00 00-1D 00 00 00 00 00 1D 00   ................
-d d197:0000
D197:0000  89 55 12 89 5D 14 31 C9-89 4D 16 C7 45 18 00 02   .U..].1..M..E...
D197:0010  2D 01 40 81 DA EC 00 19-CB 73 04 80 4D 02 02 26   -.@......s..M..&
D197:0020  8A 54 0A 30 F6 89 55 08-89 4D 0A 26 8A 54 0B 89   .T.0..U..M.&.T..
D197:0030  55 0C 89 4D 0E 26 8B 54-0C 89 55 04 89 4D 06 91   U..M.&.T..U..M..
D197:0040  E9 4F FB 81 7E 18 AA 55-75 14 C6 46 1F 21 F7 56   .O..~..Uu..F.!.V
D197:0050  18 E8 0D 00 89 4E 1C 80-66 24 FE E9 3A FB E9 CD   .....N..f$..:...
D197:0060  FA B9 01 00 80 7D 14 04-73 03 80 C9 04 C3 FF FF   .....}..s.......
D197:0070  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF   ................

Nice, there it is. I dumped it (great tutorial on dumping over here at MESS) for safe-keeping, so I could use it for any comparison in the future:

-n pci-d000.bin
-r bx
BX 0000
:0000
-r cx
CX 0000
:2000
-m d000:0 2000 0100
-w 0100
02000 BYTES WRITTEN
-q

Note that you need to hit enter at the end of any line starting with "-". 0x2000 is 8kb (aka 8192) in HEX. Debug also only cares for 8.3 filenames, so don't give it anything longer.

3Com EtherLink II 3C503

The actual card to test was this 'trusty' 100yen purchase from a Hard Off in Japan. The 3Com 3C503 was detected and installed under Win98 and worked fine. I then put in the EPROM and nothing happened during a restart!

This card has one thing going for it: configurable jumpers. The ROM location can be easily specified and I'd put it at 0xCC00.

I have no idea if this was a good location, but I went for it. A reboot saw absolutely nothing get executed! To test if it had actually been loaded into memory, I used debug once more:

Microsoft(R) Windows 98
   (C)Copyright Microsoft Corp 1981-1999.

C:\WIN98JP\DESKTOP>debug
-d cc00:0000
CC00:0000  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF   ................
CC00:0010  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF   ................
CC00:0020  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF   ................
CC00:0030  FF FF FF FF FF 00 00 00-00 00 00 00 00 00 00 00   ................
CC00:0040  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
CC00:0050  BF 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
CC00:0060  08 00 45 00 CA 00 8F 02-60 E8 12 01 00 00 32 FF   ..E.....`.....2.
CC00:0070  8A DA 66 D1 E3 66 50 66-BA D4 03 66 B8 1F 57 66   ..f..fPf...f..Wf
-q

Ah yeah, that's not it. I tried a few other locations, landing on D800, but it seems that Windows 98 was stealing the memory back after DOS had loaded. I ended up having to F8 to DOS when booting and debug from there:

That's still not it! But at least it's blank. What am I doing wrong? Turns out this card only supports 27C64 EPROMs and I've shoved a 27C256 in it! Ok, lift the address pin that could be conflicting:

And what do we see?

We're literally a half-step closer! I spent a lot of time googlin' what the @#$ was going on, but then I looked at the card again:

DATA MODE has an option between 16 and 8. I had thought this was Twisted Pair or BNC... but I was wrong. Setting it to 8 (finally) revealed:

Ok, the 'top end' looks good... what about the rear end? The ROM is 8kb, but there's a bit of filler at the end. The ROM data is around 1D7 bytes:

Ok good, but what about the very end? The ROM is 8k, and that's 0x2000 in hex. It's based at 0xD800, so we also need to check up to 0xD9FF:

What... what is that 0x04 0x04? I only had to ask the internet, because... as I keep saying, nothing is new on the internet. Someone has almost always had an issue in the same vein as anything and everything I've ever encountered. The strange thing with this forum thread is that they say that the 3C503 returns 0x80 0x80 as the last two bytes. Above, as you can see, we're getting 0x04 0x04. How broken are we? I dumped the ROM and compared everything with HxD and we're not bad! It really just is the last two bytes.

Ok, so there are the two bad values right at the end. The card is always reporting them and we need to find a work around.

BIOS Option ROM Checksums

We know the EPROM data is being loaded into memory, but we don't know why the system BIOS isn't executing it. I had to dig a bit to find a thread on Option ROM checksums which lead me to a great howto on Etherboot ROM booting. This latter document contained a great list of dot-points that need to be met for an Option ROM to be seen and booted:

How does the main BIOS know that the code in the ROM is to be executed and why does it not execute some random code by accident? The ROM code has several conditions placed on it:

  1. The ROM must start on a 2kB boundary in the memory space, between 0xC8000 and 0xEE000, although some main BIOSes scan outside these limits.
  2. The first two bytes of the ROM must be 55 AA hex.
  3. The third byte of the ROM should contain the number of bytes in the ROM code divided by 512. So if the ROM code is 16kB long, then this byte would hold 20 hex (32 decimal).
  4. All the bytes in the ROM (specified by the length byte just mentioned) must checksum to 8 bits of binary zero. The sum is formed by 8 bit addition of all the bytes, throwing away the carry. Note that there is not a particular location designated as the "checksum byte". Normally the ROM building process alters an unused byte somewhere to fulfil the checksum condition.

From the dump above, we can confirm that we tick the first and second point. For the third point, our third byte is 0x10, meaning that we're 8192 bytes long. This means that if we add together every byte in our 2k ROM, we need to sum to a total of 0. Fortunately, we don't have to do this manually! If we use the checksum calculator over here, it'll run throught the ROM and adjust the last byte to fulfil the checksum zero-sum requirement.

I fed it the ROM dumped from memory, as loaded by the 3C503. Why bother using the correct binary on disk if that's not the way it'll show in RAM?

C:\Users\steve\Downloads>romcksum32.exe \\yadayada\....\3comd800.bin

ROM Checksum Calculator  VER: 0.2 REV: D
Copyright (C) 1998-2021 Microprogramming TECHNIQUES
Programming/PC Code: Alexandru Groza
All rights reserved.

ROM file     : 3comd800.bin
Disk size    : 8192 (8 KiB)
ROM usage    : 100.00% (8192/8192)
ROM checksum : 0x4h (8-bit)

ROM file checksum updated.

So, what's it done?

It replaced the final 0x04 with an 0x49? So it decided that, once summed, we were missing 0x45 to sum back around to zero... sure... but our card is going to whack that final 0x49 back to 0x04. We'll need to 'spread' this checksum'd difference around spare bytes, but they're all 0xFF, so let's change the third-last byte to 0x00 and use it to store the remainder. Running the checksum again after making this change saw:

So, with an 0x00 instead of 0xFF, we now have a final byte value of 0x48. So the FF was worth 0x01? Regardless, if we know the last 0x48 will become 0x04 in the physical machine, we can store the 0x44 difference in the third-last byte:

And you know what? I wrote this version of the binary to an EPROM, inserted it into the 3C503 and IT BOOTED! Of course, this was a stock-standard XT-IDE BIOS ROM. What you ACTUALLY need to do is to run the XTIDECFG.COM file from a floppy with a machine-relevant BIOS loaded and then customise it to the configuration on your machine. This default BIOS tries to load a second ATA controller and causes no end of lock-ups as the hardware isn't actually attached!

I can't believe it worked.

Filed under: Retro No Comments
27Aug/240

Apricot Xi PC

This Apricot Xi (further info) (Service Manual) appeared on eBay and the seller was willing to ship it! He descibed it as the following:

It was tested to power up only. The hard drive spins up and a red light is visible inside through the floppy drive slot. It did not appear to boot. A minute or so after first powering up some caps blew in the power supply, likely filter capacitors. It did not stop and later could be powered up again to the same state.

That latter concept of why not try turn it on again after it exploded left me a little bemused... but what could I lose by trying to get it going?

The tear-down was nice and simple. A few screws here and there and things just nicely came apart.

The power supply was out first and the damage was blindingly obvious.

Those two nuts on the wall were not fun to remove, but with them out the base board came out cleanly.

With the new capacitors back in, the unit was re-assembled.

Of note, in the middle shot above, make sure to line up the carry-handle with the slot it fits through. In the last shot, make sure to re-connect the speaker cable to the motherboard before screwing down the drive-bay plate.

With it all together, voltages were checked and the 12v rail was quite high! With no load, this was mildly expected. I slapped in a sacraficial HDD and hit the power... it spun up and the motherboard speaker even beeped! I was good to continue the testing.

Video Out

Long-story-short... it's a 71.9hz vertical sync signal at 15.978khz horizontal. This doesn't match MDA, CGA or EGA... let alone anything higher.

The video port is a 9-pin male DB-9 with both syncs, video and a dangerous -12v pin. Don't just hook this up to anything non-Apricot!

I attempted with some logic to invert the vertical sync as it was mentioned somewhere that it might be negative and needs to be positive, but that didn't work.

The GBS-8200 didn't work either! So, what to do? Let's test something that's been on the shelf for a while...

I hadn't tested out the oscilliscope before and I still don't know how to use it. I was happy to see it seeing signals... but I couldn't work out if the frequencies were at the numbers I needed. I then realised my retro-corner LCD supports 15khz and threw together a test-wire straight through to VGA plug:

Hello there! It's totally failing to work out the vertical refresh rate... but that's fine... this thing is running a VGA vertical refresh with an EGA horizontal... it was never expected to 100% work without some kind of conversion. Just for fun, here's the specifications:

----CRT DATA DISPLAY SPECIFICATIONS---
PHYSICAL CHARACTERISTICS
Dimension 174mm max.
Height 241 ±1.5 mm
Width 226±5.0 mm
Depth 6.2 Ibs (2.8 kg)
Weight 240AMB39 polish
Picture Tube Visual 9" 90° def. 20 mm dia.
Tilt 10° ± 1°
ELECTRICAL CHARACTERISTICS OF CRT DISPLAY MONITOR
Power Requirements DC 11.8V 1.0A
Video Input Signal Requirements Black level = 0 + 0.4 -O.OV
White level = 4 ± 1.5V
Input Impedance 300 ohms min 40pF max.
VERTICAL INPUT SYNC SIGNAL REQUIREMENTS
Active Polarity Positive
Pulse Rate 71.9 Hz
Pulse Width 158us
Amplitude Low = 0 + 0.4 -O.OV
High = 4 ± 1.5V
Input Impedance 1 Kohm min. 40pF max.
HORIZONTAL INPUT SYNC SIGNAL REQUIREMENTS
Active Polarity Positive
Pulse Rate 15.79 kHz
Pulse Width 8.0us
Amplitude Low = 0 + 0.4 -O.OV
High = 4 ± 1.5V
Input Impedance 2 Kohms min. 40pF max.
Video Amplifier Band Width 25 MHz typ
Resolution >= 800 TV Lines at center
>= 650 TV Lines at corner
Vertical Character Area 120 ±5mm
Horizontal Character Area 150 ±5mm
* According to the attached timing chart
* +B = 11.8 ± 0.05V
BLANKING TIME REQUIREMENTS
Vertical 1200us min.
Horizontal lOus min.
Vertical Deflection Linearity 10%
Horizontal Deflection Linearity 10% ((max - min)/(max + min) x 100)

So, what next? Find someone else that's built a 15khz VGA adapter. Writing this now, after building the MCEBlaster, I can't help but wonder if I should not have gone the simpler route and built the qiqitori analog-RGB to VGA adapter?

The MCEBlaster is multi-purpose for MDA/CGA/EGA, but none of those suit this display output! MDA is close, but it's still a reach from the resolution this unit is outputting. Using qiqitori's adapter, I could've just customised the code directly for this machine.

REGARDLESS, I didn't have this hindsight and built the MCEBlaster. In fact, I built it to the the schematic... expecting my video pin display data to be fed into all three coloured RGB TTL lines at once...

This was wrong, and with code changes forcing the EGA lines to 72hz vertical (which the code was picking up as the input signal, correctly), I got the following:

With a silly amount of tinkering (as this was never going to work as EGA is too limited to display the full EGA picture), I eventually got quite a bit of the picture to display!:

As mentioned, trying to fit 800x400 in 320x240 was never going to work. We're an MDA-esque signal and the board had full provision for such. I should have, from the start, fed the image into the input as if it was an MDA plug. This meant we needed to input video data on pin 7 and intensity on pin 6.

Unfortunately, the Apricot doesn't output an intensity pin, so pin 6 can be grounded. My wiring between the 74LVC245 and Pico could stay, as per the schematic, as the Pico knew to look on pins 26 and 27 if the vertical frequency was correct. I adjusted the MDA modeline config to look for 72hz (rounded-up) sync and we started getting somewhere...

I already had that encroaching feeling of Why am I doing this? If/when it works, what will I do with it?... so this was a good enough video output to test the rest of the peripherals. The error shown above is Error 31 and it means that Keyboard diagnostics failed.

Keyboard Input

As always, someone has already done this before. I built the circuit and plugged everything together expecting things to just-work, but I still got Error 31!

With the arduino connected, there was no data showing as coming from the Apricot? I checked the MAME source code for the Apricot keyboard and you could see that the keyboard was meant to receive a reset command from the computer and respond with an ACK:

		case CMD_KEYBOARD_RESET:
			logerror("System requests keyboard reset\n");
			transmit_byte(ACK_DIAGNOSTICS);
			break;

The computer stayed silent towards everything I threw at it. No amount of forced-sending of control codes from the keyboard to the computer worked, so I hooked up the oscilloscope to the data pin 2 of the keyboard port and yeah, the transmit signal from the computer to the keyboard was held high and had a not of noise. Interestingly though, pressing CTRL+ALT+DEL on the keyboard actually did reset the Apricot? The apricot-kbd arduino code has a special block where sees a reset request and holds the transmission line to ground for 100ms. Is this the required signal? I checked the schematics again and noticed that there was a special path for a system reset request.

Above, you can see the keyboard connector in the green box on the left. The two standard paths are orange and blue and they travel through respective MC1489/MC1488 paths to the Z80 SIO/0. I'm getting nothing from, and seemingly sending nothing to, this chip... so the only reason reset would work is via the purple path down the bottom.

Just for fun, I dismembered the trace between the SIO and the MC1488 on the outbound TX line to see if the MC1488 was the issue. Doing so still saw a high and messy voltage on the Z80A SIO/0 side, meaning something was wrong it, or with a chip further towards the CPU. Whilst doing all this, I happened to press my finger down on the SIO and found that it was hot enough to fry an egg! No wonder it's lid is so smooth and shiny.

It was a very quick removal. A socket was installed and... I found a pair of ICs (supposedly new-old-stock) on eBay. The machine was put back in the corner of the room... unscrewed, but neatly stacked. The ICs came in due course and one was installed.

And...?

PS2 to Xi
Value FA - Status Bits 0  Code 0xFA [�]   --  .
Value AA - Status Bits 0  Code 0xAA [�]   --  5F
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
----------From Apricot:
0 [] 
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
Value 2B - Status Bits 0  Code 0x2B [+]   --  60
Value 802B - Status Bits 80  Code 0x2B [+]   --  FFFFFFE0
Value 11E - Status Bits 1  Code 0x1E []   --  40
Value 811E - Status Bits 81  Code 0x1E []   --  FFFFFFC0
----------From Apricot:
E8 [�] 
----------From Apricot:
E8 [�] 
----------From Apricot:
E2 [�] 
----------From Apricot:
D0 [�] D4 [�] AA [�] E3 [�] 0 [] E2 [�] 81 [�] 52 [R] 41 [A] 4D [M] 20 [ ] 35 [5] 31 [1] 32 [2] 4B [K] 
Value 11E - Status Bits 1  Code 0x1E []   --  40
Value 811E - Status Bits 81  Code 0x1E []   --  FFFFFFC0

Wowzers... it's reporting 512K RAM to the non-existent Keyboard LCD! The paired values are from the PS/2 Keyboard keypresses and the data from the Apricot is self-explanatory once you've read the opcodes over here.

  if (Serial1.available()) {
    Serial.println("----------From Apricot:");
    while (Serial1.available())
    {
      uint16_t b = Serial1.read();
      Serial.print(b, HEX);
      Serial.print(" [");
      Serial.print((char)(b & 0xff));
      Serial.print("] ");

      switch (b)
      {
        //keyboard reset. just ACK
        case 0xe8: Serial1.write(0xfb); break;

      }
    }
    Serial.println("");
  }
}

Above is the only bit I changed when compared to the git repo.

Floppy Disk

This thing is a monstrosity, and didn't work at the start. It wasn't until I replaced the ZIO above that the floppy started seeking on boot and showing other signs of life. I haven't got a floppy disk formatted for this unit yet, but it really does seem that a catastrophic event occurred to wreck a whole bunch of chips in this machine. With one fixed, the data bus may well have been free'd up to communicate. It does still seem that once the machine has warmed up, that more faults start occurring. I'm guessing RAM? Either way, here's the beast of a drive:

If I can get it working more-consistently then I'll use apridisk to write disk images and have fun... but that's for another post. This one has gone on long enough!

Heat-Activated Gremlins

It seems that there are still issues with this machine. With the keyboard responding with an ACK, the system is finally reporting System OK on a cold boot, but starts to lose it once it's warmed up. After hitting enter at the prompt, the following message was displayed:

You can tell it's coded into the autoexec.bat file. Whilst trying to search for files on the Winchester Disk that others may have left behind, I initially received proper disk directory listings... until I didn't.

Letting the machine cool down again saw those same error'd directories list fine... so it's not the HDD itself... it's heat. I left the machine on for 20 minutes and touched all the chips... only the main CPU and its friend were (burningly) hot.

Could I be bothered replacing it? Should I heatsink the crap out of it to test further? Why am I even doing all of this? No idea.

Filed under: Retro No Comments
5Aug/240

How To Miss Doctor Yellow

So, you've all heard the news: Doctor Yellow is being retired in 2027. Thankfully that's 2 years away, so I still have time to see the consist in action. During my recent trip to Japan I travelled all the way to coastal Kanagawa to photograph Shinkansen and freight in the country-side, but gave up due to the weather and ... a general feeling of old-age?

The Original Plan

Take enough trains to Hayakawa Station and walk an extended path to Nebukawa Station. The embedded map below doesn't show the actual path, opting for the most direct. If one follows some of the mountain contours, many tunnel portals can be observed from amazing angles!

It was probably overly-adventurous in the middle of a humid summer. The forecast was actually for rain, but by 9am it was already nearly 30 degrees celsius.

What Actually Happened

I arrived at Hayakawa Station bright and early on Thursday the 6th of June, 2024. There's a pedestrian bridge just east of the station (and a Lawson), so I went to get some line-side shots (and breakfast).

The elevation of the pedestrian bridge really is nice! For some reason I decided that the main goal was to get up to the first Shinkansen tunnel portal.

I got half-way up a hill to a beautiful vantage point for Shinkansen. As I was making my way up there two freighters passed on the zai-rai-sen, one being a Kangaroo-Liner!

Finally, the s-bend of the road provided an awesome vantage point.

I was appeased by the Shinkansen action:

After watching quite a few Shinkansen pass, I somehow let the ambient temperature, humidity and mosquitos get to me. It was a mild climb to this point and I knew this was one of the smaller inclines over the entire path. Due to all of this, I chose to not continue on the original path and, instead, to head back into Tokyo and check out anything with air-conditioning. I'm still regretting this!

Anyway, I spent 5 seconds admiring the people who obviously didn't choose for the Shinkansen to be built next to their bedroom...

...and then I left back to Hayakawa, took the locals to Fujiawa, Enoden to Enoshima, the monorail to Ofuna and then trains to Akiba.

What Did I Miss Out On?

For those playing at home, there's a Japanese-only website known as Kamotsu (Freight) Channel for tracking the locomotives on japanese train services. Users also have the opportunity to upload other sightings... including Doctor Yellow! So, a week after returning from Japan, I was still in the sliding-window of sightings and happened to check when Doctor Yellow been operational whilst I was in Japan.

(You'll just have to pretend that the screenshot above was for the correct dates)

Would you believe it was the exact day I'd chosen to be line-side in Kanagawa? If I'd stayed 30 more minutes I would've snapped the ultra-rare sighting of Doctor Yellow on the Tokaido Shinkansen? The thought still haunts me... but I will seek revenge! I'll also go back to Nou in Itoigawa and also find those bloody onion trains.

Filed under: JPN No Comments
31Jul/240

Remote Garage Door Sensor/Opener

So, I live on the top floor of a three-storey building. My garage has an electric door and is vertically below my aparment on the 'basement' level. The following post details my efforts to be able to know if the door is open, and to possibly control it remotely. In the past, I've accidently left the door open and I want to be able to prevent this! I also want to be able to access the garage when the keys aren't nearby.

I've already tried a crappy 433mhz universal remote from eBay, which did train to the garage remote. I then went to test it and 1-in-50 key-presses worked. The purchase ended up being a quick and cheap way to work out that the Vicway V-380G has rolling codes!

Fortunately, this model garage-door-opener also has terminal blocks with a screw-terminal named DOOR. I asked the manufacturer if I could just short that terminal with the one next to it named GND and they confirmed that doing so will operate the door! What should I use to do this? Arduino? Raspi? Any of the above? Sure... but how do I communicate with any of them from three concrete storeys above?

  • WIRELESS: Does not work... the signal doesn't reach. My mobile phone gets no wifi signal when in the garage. It does work out in the carpark though.
  • ETHERNET: Ok sure... run a cable down the side of the building? Is there an inner cable cavity between solid concrete floors? No, but, ethernet-over-power does work! Do I want my LAN exposed to the entire building's power grid? I dunno.
  • LORA: Will this be able to communicate through three layers of solid concrete? Wifi couldn't. I'm still going to give it a bash. Will the signal be encrypted? Can any hacker just muck around with my garage door if they wanted to?

POC #1: Ethernet

I have two pairs of ethernet-over-power devices, and I tested a Netcomm set first. Plugging it in saw the home link light mainly solid, but it was probably blinking more than it usually should. I assume the connection through the building's power grid is noisy-AF and, well, I didn't really think I expected anything less. Regardless... I wasn't here to stream 4K60, I just wanted a crappy website hosted on the Arduino with a button and a bit of status information.

An Arduino Ethernet Shield was purchased from Jaycar, along with a tiny relay board. I have a few boards with 4 or 8 relays... but I didn't want to waste them. The example webserver sketch was uploaded to a UNO with the Ethernet shield attached and the unit was moved to the garage with the ethernet-over-power in place.

And ... nothing. Link, but no data. I don't know what I was expecting... ethernet-over-power was not going to work.

POC #2: LoRa with MQTT

There are a lot of great blogs on the internet... and whenever I think of a cool idea for a project... I know someone has already done it... somewhere... somehow. What I wasn't expecting was to find someone in NZ that was considering the exact same setup of components from jaycar. Jon, thank you for the work you put in to documenting the caveats of these older-style components. I went ahead and purchased both the LoRa Sheild (I already had enough spare Arduinos at home) and LoRa Gateway.

The LoRa Gateway is an all-in-one LoRa radio + Arduino + Linux SOC. The SOC talks to the Arduino via SPI and uses Yun's Bridge Protocols. If you search for any of this, then you'll quickly find that all of this tech is OLD. LoRaWAN is the new standard and this is all LoRa-only.

I had plans to host a webpage on the gateway and send data directly to the LoRa node, but I quickly realised that extending the gateway to do my bidding was going to be difficult. It uses flash disk with most files read-only and the website is hosted from ROM! Instead, I'd have to have the gateway actually be a gateway and transmit data to some other server on my LAN.

The setup would therefore be configured as follows...

Garage Gateway NAS
Arduino (Read Sensors) –> LORA Gateway (Arduino) –> LORA Gateway (Linux SOC) –> MQTT Broker <-> Website
Arduino (Operate Relay) <– LORA Gateway (Arduino) <– LORA Gateway (Linux SOC) <– –> SQL Database

I chose a local MQTT Broker, as I didn't really want to sign up to another external webservice (they seem to use Thingspeak), to only then have to bring the data back down to the local network once again. The local broker wouldn't persist data, so I would also have to work out a mechanism to store in a DB somewhere. Fortunately (hah, or so I thought) I already has MS SQL running in docker on the NAS.

Setting up the Arduino IDE

Following the actual Dragino documentation with a newer version of Arduino will end in misery. I installed the latest 2.3+ version and got no end of errors of missing libraries. So, what to do? Spin up Win7 on my NAS and set up Arduino 1.8.6.

Once installed, add the following url to the Additional Boards Manager URLs: http://www.dragino.com/downloads/downloads/YunShield/package_dragino_yun_test_index.json

Now go to Board Manager and install the Dragino Yun set of boards:

Next, download the RadioHead Library and extract it into Documents\Arduino\libraries.

Finally, select the board, the port and load up the LoRa_Simple_Server_Yun sketch from the Dragino examples.

If it compiles... try an upload! You'll need to enter your LG01's password...

... and then ...

Seamless! Amazing actually. The code has passed through a Linux SOC and then been transmitted over SPI into the Atmel co-CPU? If this didn't work, then write a comment below and tell me what happened. Next up, set up your first node. I used a spare Leonardo with a LoRa Shield.

Download this sketch (or Jon's version), modify the node_id from 12345 to something relevant (leaving the less-than and greater-than symbols in-place) and check the serial monitor on both sides...

It... works! RSSI of -21 is very good... since the nodes are on the workbench, right next to eachother. Let's see what happens when I shift the node to the garage.

Integrate the Garage

The garage door motor has a terminal block wth DOOR and GND. These need to be bridged to activate (open or close) the door... so I bought a relay module and wired it across. Next up, I wanted to know if the door was open or closed, so I bought two magnetic reed switches and installed them at either end of the door chain traversal. I also threw on a temperature and humidity sensor.

With this all wired up, the Arduino was ready to transmit statistics and react to commands.

Provide basic feedback from the Gateway

I was initially going to use an Arduino Buzzer from Jaycar and the Buzzer Library (who doesn't want bits of the Super Mario tune playing!?), so I could get audio feedback to know what the garage door is doing. Unfortunately, including and operating the buzzer interfered with the Yun Bridge Library communication when writing/reading files from the Linux SOC.

It seems that Timer or PWM operation trashes the Process call and no amount of asynchronous or shell-command tinkering worked. Even the FileSystem write command spewed out empty files. I didn't even bother begging for help on the forums as the library is already deprecated. One note though... The official dragino repo has Arduino 1.6.9 for download and I wonder if this is the final 'supported' version with this gateway. Using 1.8.6 might cause these bugs?

Instead, I purchased a self-contained piezo buzzer and wired it up via my transistor power method. I wasn't sure if the digital pins could deal with the current and therefore used the transistor as a switch. I also grabbed a large flashing LED for consistent 'door is open' statii notification.

Attaching all this to the Gateway was easy enough as they provide a really nice screw-terminal block. The pinout is as follows:

1 2 3 4 5 6 7
+ - + - + - + - + - + - a b
+5v GND A0 A1 GND A3 A4 A5 A6 A7 N/A GND D3 D4

I chose to integrate with the Digital pins 3 and 4 for my buzzer and LED respectively.

MQTT Broker Installation

This MQTT Server and Node Tutorial helped a lot, but I still didn't want to use Thingspeak. Instead, I overloaded my NAS further with the Eclipse Mosquitto Docker Image.

I created a base folder on the NAS for the home of Mosquitto. In here, I downloaded the default configuration file and created a data and log directory. The default configuration only allows local connections, so we'll need to edit it to allow external nodes to report to it. There's a great guide here, but the basic idea is to add the following line to the configuration file:

# listener port-number [ip address/host name/unix socket path]
listener 1883 0.0.0.0
listener 9001 0.0.0.0
protocol websockets

Search for #listener and replace that chunk with the bit above. Now we need to create the server so that we can shell in and create a password file. Port 9001 will be used for WebSocket connections and port 1883 will be for standard TCP connections. I've called it mosqii here, but you can call it whatever you like. Just remember to use the new name in each subsequent command.

#docker create --name mosqii -it -p 1883:1883 -p 9001:9001 -v /volume2/SSD/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf -v /volume2/SSD/mosquitto/data:/mosquitto/data -v /volume2/SSD/mosquitto/log:/mosquitto/log eclipse-mosquitto

Once created, start it with:

$ docker start mosqii

With it up and running, use the following command to connect via sh and create a password file with a username and password of your choice:

$ docker exec -it mosqii sh
/ # cd mosquitto/config
/mosquitto/config # mosquitto_passwd -c garage_door_auth garage_door
Password:
Reenter password:
/mosquitto/config #

Type exit and get out of docker. Stop the docker container with:

$ docker stop mosqii

Edit mosquitto.conf once again, adding the newly-created password file to our listener configuration. We couldn't do this at the start as the server would crash if the file wasn't found.

# listener port-number [ip address/host name/unix socket path]
listener 1883 0.0.0.0
listener 9001 0.0.0.0
protocol websockets
password_file /mosquitto/config/garage_door_auth

Download MQTT Explorer and connect to the server to test your settings...

Data!

Configure the Gateway for MQTT

With the Gateway connected to my local LAN, I browsed to my router and checked the DHCP listing. duinotech-xxxxx was listed at IP 192.168.1.156 and a quick browse via chrome brought up the internal website. If you've bought one from Jaycar, then the initial password is duinotech.

The unit was quickly upgraded with firmware v4.3.7 and the root password then changed to dragino.

Let it reboot and do its thing... then browse to the Servers and select MQTT with debugging enabled.

Next head to the MQTT Settings page and fill out the private server details. Add a row to the channels table so that we have something to match on when the LoRa node sends data.

With it all configured, return to the system logging and see what's going on. Thankfully the logging is pretty self-explanatory!

Note that initially I had no data flowing to the newly created server. I actually had to SSH into the Gateway to work out what was going on, but even getting in wasn't easy...

$ ssh -l root 192.168.1.156
Unable to negotiate with 192.168.1.156 port 22: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,kexguess2@matt.ucc.asn.au

Turns out it's using old cipher methods and you need to overload your ssh client to force it to connect...

$ ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-rsa -l root 192.168.1.156
root@192.168.1.156's password:


BusyBox v1.23.2 (2019-01-10 15:05:04 CST) built-in shell (ash)

 ____  ____      _    ____ ___ _   _  ___
|  _ \|  _ \    / \  / ___|_ _| \ | |/ _ \
| | | | |_) |  / _ \| |  _ | ||  \| | | | |
| |_| |  _ <  / ___ \ |_| || || |\  | |_| |
|____/|_| \_\/_/   \_\____|___|_| \_|\___/

W i F i, L i n u x, M C U, E m b e d d e d

OpenWRT Chaos Calmer 15.05
Version: Dragino-v2 IoT-4.3.7
Build Wed Sep 11 22:30:26 CST 2019

www.dragino.com
----------------------------------------------------

root@dragino-17b9d2:~#

All scripts are in /etc/iot/scripts/. I was going to inspect mqtt_process.sh, but decided to just follow Jon's instructions and replace the existing file.

root@dragino-17b9d2:~# cd /etc/iot/scripts/
root@dragino-17b9d2:/etc/iot/scripts# ls
lg01_pkt_fwd         mqtt_process.sh      mqtt_process_old.sh  mqtt_sub.sh          polish_mqtt_config   tcp_client           tcp_client.lua       xively_routine.lua
root@dragino-17b9d2:/etc/iot/scripts#

The replacement script is here, but that also caused issues for me. I could see in the web logs that it was complaining that "12345/" didn't match any known configuration keys. It turns out that a trailing slash was causing the issue. This can be fixed on line 66 of Jon's mqt_process.sh by removing the trailing slash so that it reads:

CID=`ls /var/iot/channels/`

With this fix done, the data was flowing to the MQTT Broker and visible in MQTT Explorer!

Web remote

A quick website was spun up in a folder on my Windows machine. It uses MQTT.js and reports the data from the garage.

<html>
	<head>
		<script
		  src="https://code.jquery.com/jquery-3.7.1.min.js"
		  integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
		  crossorigin="anonymous"></script>
		<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
		<script>
		  const url = 'mqtt://someserver.somewhere.org:9001'
		  const options = {
			  // Clean session
			  clean: true,
			  connectTimeout: 4000,
			  // Authentication
			  clientId: 'garage_door_ctrl',
			  username: 'garage_door',
			  password: 'some_password_here',
			}
			const client  = mqtt.connect(url, options)
			client.on('connect', function () {
			  console.log('Connected')
			  // Subscribe to a topic
			  client.subscribe('channels/garage_door/publish/this_is_a_key', function (err) {
				console.log('ERROR: ' + err);
			  })
			})
			
			
			client.on("message", (topic, message) => {
			  // message is Buffer
			  //console.log(topic.toString() + ": " + message.toString());
			  var splitted = message.toString().split('&');
			  $("#temp").text(splitted[0].split("=")[1]);
			  $("#humidity").text(splitted[1].split("=")[1]);
			  
			if (splitted.length > 3) {
				op = splitted[2].split("=")[1];
				cl = splitted[3].split("=")[1]
				
				$("#open_d").text(op);
				$("#closed_d").text(cl);
				
				if (op == "0") {
					$("#open_close_btn").text("Close Door");
					$("#open_close_btn").prop("disabled", "");
				} else if (cl == "0") {
					$("#open_close_btn").text("Open Door");
					$("#open_close_btn").prop("disabled", "");
				} else {
					$("#open_close_btn").text("...moving...");
					$("#open_close_btn").prop("disabled", "disabled");
				}
			}
			});
			
			function open_close() {
				client.publish('channels/garage_commands', 'open_door');
				$("#open_close_btn").prop("disabled", "disabled");
			}
		</script>
	</head>
	<body>
		<center>
			<button onclick="open_close();" id="open_close_btn" 
				disabled="disabled"
				style="width:90%;height:200px;font-family:tahoma; font-size:32pt;">...determining position...</button>
			<table style="font-family:tahoma; font-size:32pt;">
				<tr>
					<td>T:<span id=temp>?</span></td>
					<td>/</td>
					<td>H:<span id=humidity>?</span></td>
					<td>/</td>
					<td>O:<span id=open_d>?</span></td>
					<td>/</td>
					<td>C:<span id=closed_d>?</span></td>
				</tr>
				<tr>
					<td colspan=4>
						<center id=message></center>
					</td>
				</tr>
			</table>
		</center>
	</body>
</html>

It also sends an "open_door" message to the MQTT server on channels/garage_commands when you hit the button. Note that you need to have enabled websockets on 9001 to be able to use the MQTT.js library!

Sending data back to the Garage

One-day data is great, but how do we get the data flowing in the other direction? Turns out we actually need to subscribe to the MQTT Broker on the LG01 and act when data changes. Unfortunately, the LG01-S doesn't support configuring MQTT subscription settings in the Web UI? The documentation here indicates there should be an MQTT Subscribe configuration area, but we don't have it. Fortunately it does tell us the shell commands!

mosquitto_sub -h 192.168.199.148 -p 1883 -i dragino-1b7060 -t command

So, we can use mosquitto_sub to get commands from the MQTT broker... but how do we then get them into the MCU to send over LoRa? Turns out there's a 'talkback' server demo in the github which makes use of the Yun Process Library once again.

The goal would be to store the commands received from MQTT in a file somewhere on the Linux SOC, without bashing the flash too much and causing it to wear out, and then read the file back into the MCU. The Linux SOC offers a /tmp folder which is actually hosted in RAM, so this'll work for us. We can then read the file via the Yun Process Library on the MCU, and, if the content of the file matches a command that we want to react to, we can then send a command via the LoRa network to the node in the garage and clear the local file. Actually, we should clear the local file regardless, as there are no other consumers and we want to know if/when another MQTT message comes in.

So, on the Gateway MCU side I created an mqtt_sub.sh script in the /etc/iot/scripts/ folder:

#!/bin/sh
touch /var/last_command
while true
do
        echo "waiting..."
        mosquitto_sub -C 1 -u garage_door -P l0r@l0r@ -h 192.168.1.61 -p 1883 -t channels/garage_commands > /var/last_command_tmp
        mv /var/last_command_tmp /var/last_command
        cat /var/last_command
done

Since we now have a file to read, I added the following chunk to the gateway node so that it could send out a message over LoRa:

void checkForCommands() {
  String lastCommand = "";

  Process pDown;
  pDown.begin("cat");
  pDown.addParameter("/tmp/last_command");
  pDown.run();    // Run the process and wait for its termination

  while (pDown.available() > 0)
  {
    char c = pDown.read();
    if (c != '\n' && c != '\r') lastCommand += c;
  }
  
  if (lastCommand != "") {
    if (lastCommand == "open_door") {
      Console.println("Opening door!...");
      uint8_t data[] = "OPEN_DOOR";
      rf95.send(data, sizeof(data));
      rf95.waitPacketSent();
    } else {
      Console.print("Unknown command: ");
      Console.println(lastCommand);
    }
    
    File last_cmd = FileSystem.open("/tmp/last_command", FILE_WRITE);
    last_cmd.println("");
    last_cmd.close();
  }
}

And it worked! The message was sent to the LoRa node and the arduino code was updated accordingly to watch for messages and act!

The only note above is that the /var folder is actually a symlink to /tmp, so they can be used interchangeably. Also note that the step to write from the temporary file to the real command file is essential. If you try to pipe out from mosquitto_sub directly then the file will be empty until a message comes in.

I then scheduled this in /etc/rc.local so that it started on boot of the gateway. Make sure you keep the ampersand at the end!

# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

/etc/iot/scripts/mqtt_sub.sh &

exit 0

With this, the unit was listening consistently to the MQTT broker for commands.

Storing the data long-term!

For data persistence... any sane person would use MySql. Unfortunately, I have MS SQL running in docker... because I could... as I use it for other application development. Instead of runnign yet another DB on the NAS, it'd be nice to store this data in there also! Of course, it's never that easy! There's a great example here using python, I need ODBC from Microsoft... and I'm running this raw on the NAS... so no package manager!

So, yeah, this going to have to be ANOTHER docker container? Do I have to? Can this NAS even handle all of this? Can't I run a plugin on the MS SQL docker container? Let's see what's running on the shell inside the SQL container and if I can just run an extra process.

$ docker exec -u 0 -it sql1 /bin/bash
root@sql1:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
root@sql1:/# pip
bash: pip: command not found
root@sql1:/# apt-get install pip
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package pip
root@sql1:/# apt-get update
Get:1 https://packages.microsoft.com/ubuntu/22.04/prod jammy InRelease [3632 B]
Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:3 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Get:4 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main arm64 Packages [40.1 kB]
Get:5 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main amd64 Packages [164 kB]
Get:6 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main all Packages [1035 B]
Get:7 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main armhf Packages [14.6 kB]
Get:8 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [2771 kB]
Get:9 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Get:10 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB]
Get:11 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages [1792 kB]
Get:12 http://security.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [44.7 kB]
Get:13 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1129 kB]
Get:14 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [2104 kB]
Get:15 http://archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [266 kB]
Get:16 http://archive.ubuntu.com/ubuntu jammy/restricted amd64 Packages [164 kB]
Get:17 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [17.5 MB]
Get:18 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [2858 kB]
Get:19 http://archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [51.8 kB]
Get:20 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1420 kB]
Get:21 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [2378 kB]
Get:22 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [81.0 kB]
Get:23 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [33.7 kB]
Fetched 33.4 MB in 14s (2340 kB/s)
Reading package lists... Done
root@sql1:/# apt-get install pip
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'python3-pip' instead of 'pip'
The following additional packages will be installed:
  binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-11 dirmngr dpkg-dev fakeroot fontconfig-config fonts-dejavu-core g++ g++-11 gcc gcc-11 gcc-11-base gnupg gnupg-l10n
  gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan6 libassuan0
  libbinutils libc-dev-bin libc-devtools libc6 libc6-dbg libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libdeflate0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl
  libfontconfig1 libfreetype6 libgcc-11-dev libgd3 libgdbm-compat4 libgdbm6 libgomp1 libisl23 libitm1 libjbig0 libjpeg-turbo8 libjpeg8 libjs-jquery libjs-sphinxdoc libjs-underscore libksba8
  liblocale-gettext-perl liblsan0 libmpc3 libnpth0 libnsl-dev libperl5.34 libpng16-16 libpython3-dev libpython3.10 libpython3.10-dev libpython3.10-minimal libpython3.10-stdlib libquadmath0
  libstdc++-11-dev libtiff5 libtirpc-dev libtsan0 libubsan1 libwebp7 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 linux-libc-dev lto-disabled-list make manpages manpages-dev netbase
  patch perl perl-modules-5.34 pinentry-curses python3-dev python3-distutils python3-lib2to3 python3-pkg-resources python3-setuptools python3-wheel python3.10 python3.10-dev python3.10-minimal
  rpcsvc-proto xz-utils zlib1g-dev
Suggested packages:
  binutils-doc cpp-doc gcc-11-locales dbus-user-session libpam-systemd pinentry-gnome3 tor debian-keyring g++-multilib g++-11-multilib gcc-11-doc gcc-multilib autoconf automake libtool flex
  bison gcc-doc gcc-11-multilib parcimonie xloadimage scdaemon apache2 | lighttpd | httpd glibc-doc git bzr libgd-tools gdbm-l10n libstdc++-11-doc make-doc man-browser ed diffutils-doc perl-doc
  libterm-readline-gnu-perl | libterm-readline-perl-perl libtap-harness-archive-perl pinentry-doc python-setuptools-doc python3.10-venv python3.10-doc binfmt-support
Recommended packages:
  libnss-nis libnss-nisplus
The following NEW packages will be installed:
  binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-11 dirmngr dpkg-dev fakeroot fontconfig-config fonts-dejavu-core g++ g++-11 gcc gcc-11 gcc-11-base gnupg gnupg-l10n
  gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan6 libassuan0
  libbinutils libc-dev-bin libc-devtools libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libdeflate0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libfontconfig1
  libfreetype6 libgcc-11-dev libgd3 libgdbm-compat4 libgdbm6 libgomp1 libisl23 libitm1 libjbig0 libjpeg-turbo8 libjpeg8 libjs-jquery libjs-sphinxdoc libjs-underscore libksba8
  liblocale-gettext-perl liblsan0 libmpc3 libnpth0 libnsl-dev libperl5.34 libpng16-16 libpython3-dev libpython3.10-dev libquadmath0 libstdc++-11-dev libtiff5 libtirpc-dev libtsan0 libubsan1
  libwebp7 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 linux-libc-dev lto-disabled-list make manpages manpages-dev netbase patch perl perl-modules-5.34 pinentry-curses python3-dev
  python3-distutils python3-lib2to3 python3-pip python3-pkg-resources python3-setuptools python3-wheel python3.10-dev rpcsvc-proto xz-utils zlib1g-dev
The following packages will be upgraded:
  libc6 libc6-dbg libpython3.10 libpython3.10-minimal libpython3.10-stdlib python3.10 python3.10-minimal
7 upgraded, 103 newly installed, 0 to remove and 14 not upgraded.
Need to get 113 MB of archives.
After this operation, 318 MB of additional disk space will be used.
Do you want to continue? [Y/n]

That's a positive shiteload of dependencies... but we're on the NAS.. I have ~25tb free... so let's goooooo....

Get:106 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-distutils all 3.10.8-1~22.04 [139 kB]
Get:107 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-dev amd64 3.10.6-1~22.04 [26.0 kB]
Get:108 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-setuptools all 59.6.0-1.2ubuntu0.22.04.1 [339 kB]
Get:109 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-wheel all 0.37.1-2ubuntu0.22.04.1 [32.0 kB]
Get:110 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-pip all 22.0.2+dfsg-1ubuntu0.4 [1305 kB]
Fetched 113 MB in 38s (3007 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
(Reading database ... 9933 files and directories currently installed.)
Preparing to unpack .../libc6-dbg_2.35-0ubuntu3.8_amd64.deb ...
Unpacking libc6-dbg:amd64 (2.35-0ubuntu3.8) over (2.35-0ubuntu3.7) ...
Preparing to unpack .../libc6_2.35-0ubuntu3.8_amd64.deb ...
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 78.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.34.0 /usr/local/share/perl/5.34.0 /usr/lib/x86_64-linux-gnu/perl5/5.34 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.34 /usr/share/perl/5.34 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
debconf: falling back to frontend: Teletype
/var/lib/dpkg/tmp.ci/preinst: 9: arithmetic expression: expecting primary: "5 * 10000 + 13 * 100 + "
dpkg: error processing archive /var/cache/apt/archives/libc6_2.35-0ubuntu3.8_amd64.deb (--unpack):
 new libc6:amd64 package pre-installation script subprocess returned error exit status 2
Errors were encountered while processing:
 /var/cache/apt/archives/libc6_2.35-0ubuntu3.8_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)
root@sql1:/#

Short-lived excitement. Seems it wants to run a configuration screen but it can't work out how to display a text GUI? Anyway, this is the internet... someone has had this error before. So, remove the half-installed , set up apt-utils and go:

apt install apt-utils
echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections

There's actually a second error above regarding arithmetic. It's trying to calculate a version number, but the NAS is reporting an x for the minor version via uname. We need to mask /bin/uname and make it provide the information we need (thanks to the help over here):

root@sql1:/bin# apt-get install nano
...
root@sql1:/bin# mv /bin/uname /bin/uname_old
root@sql1:/bin# nano /bin/uname

Paste in the following, replacing the version number appropriately:

#!/bin/sh
case "$1" in
"-r")
echo 5.13.0
;;
*)
/bin/uname_old $1
esac

Don't forget to chmod a+x it. You should then get:

root@sql1:/bin# uname -r
5.13.0
root@sql1:/bin# uname -a
Linux sql1 5.13.x #1 SMP Wed Jun 12 00:11:51 CST 2024 x86_64 x86_64 x86_64 GNU/Linux

And then, try try try again...

root@sql1:/usr/bin# apt-get install pip
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'python3-pip' instead of 'pip'
The following additional packages will be installed:
  binutils binutils-common binutils-x86-64-linux-gnu build-essential...
Suggested packages:
  binutils-doc cpp-doc gcc-11-locales...
Recommended packages:
  libnss-nis libnss-nisplus
The following NEW packages will be installed:
  binutils binutils-common binutils-x86-64-linux-gnu build-essential...
The following packages will be upgraded:
  libc6 libpython3.10 libpython3.10-minimal libpython3.10-stdlib python3.10 python3.10-minimal
6 upgraded, 103 newly installed, 0 to remove and 14 not upgraded.
Need to get 99.4 MB of archives.
After this operation, 318 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
...
Get:69 http://archive.ubuntu.com/ubuntu jammy/main amd64 fontconfig-config all 2.13.1-4.2ubuntu5 [29.1 kB]
Get:70 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gnupg-l10n all 2.2.27-3ubuntu2.1 [54.4 kB]
Get:71 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gnupg-utils amd64 2.2.27-3ubuntu2.1 [308 kB]
Get:72 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gpg amd64 2.2.27-3ubuntu2.1 [519 kB]
Get:73 http://archive.ubuntu.com/ubuntu jammy/main amd64 pinentry-curses amd64 1.1.1-1build2 [34.4 kB]
Get:74 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gpg-agent amd64 2.2.27-3ubuntu2.1 [209 kB]
...
Fetched 99.4 MB in 46s (2182 kB/s)
Extracting templates from packages: 100%
Preconfiguring packages ...
(Reading database ... 9572 files and directories currently installed.)
Preparing to unpack .../libc6_2.35-0ubuntu3.8_amd64.deb ...
Unpacking libc6:amd64 (2.35-0ubuntu3.8) over (2.35-0ubuntu3.7) ...
...
Setting up libalgorithm-diff-xs-perl (0.04-6build3) ...
Setting up libalgorithm-merge-perl (0.08-3) ...
Setting up libpython3-dev:amd64 (3.10.6-1~22.04) ...
Setting up python3-dev (3.10.6-1~22.04) ...
Processing triggers for libc-bin (2.35-0ubuntu3.7) ...
/sbin/ldconfig.real: /opt/mssql/lib/libc++.so.1 is not a symbolic link

/sbin/ldconfig.real: /opt/mssql/lib/libc++abi.so.1 is not a symbolic link

root@sql1:/# pip install paho-mqtt
Collecting paho-mqtt
  Downloading paho_mqtt-2.1.0-py3-none-any.whl (67 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.2/67.2 KB 40.3 kB/s eta 0:00:00
Installing collected packages: paho-mqtt
Successfully installed paho-mqtt-2.1.0
root@sql1:/#

Errors? But, yey, paho-mqtt is installed! Install pyodbc also, and then grab the scripts and follow the instructions for the MS SQL driver over here. I copied the ubuntu scripts, removed sudo as it's not installed, installed curl as it's required and then kicked it off.

if ! [[ "16.04 18.04 20.04 22.04" == *"$(lsb_release -rs)"* ]];
then
    echo "Ubuntu $(lsb_release -rs) is not currently supported.";
    exit;
fi

curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list

apt-get update
ACCEPT_EULA=Y apt-get install -y msodbcsql17
# optional: for bcp and sqlcmd
ACCEPT_EULA=Y apt-get install -y mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
apt-get install -y unixodbc-dev
root@sql1:/database_tools# ./inst_ms.sh
./inst_ms.sh: line 7: sudo: command not found
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   983  100   983    0     0    231      0  0:00:04  0:00:04 --:--:--   240
curl: (23) Failed writing body
./inst_ms.sh: line 9: sudo: command not found
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    88  100    88    0     0     27      0  0:00:03  0:00:03 --:--:--    27
curl: (23) Failed writing body
Hit:1 https://packages.microsoft.com/ubuntu/22.04/prod jammy InRelease
Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Hit:3 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Hit:5 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Fetched 257 kB in 9s (29.6 kB/s)
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
msodbcsql17 is already the newest version (17.10.6.1-1).
msodbcsql17 set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 14 not upgraded.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
mssql-tools is already the newest version (17.10.1.1-1).
0 upgraded, 0 newly installed, 0 to remove and 14 not upgraded.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libodbccr2
The following NEW packages will be installed:
  libodbccr2 unixodbc-dev
0 upgraded, 2 newly installed, 0 to remove and 14 not upgraded.
Need to get 264 kB of archives.
After this operation, 1895 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 libodbccr2 amd64 2.3.9-5ubuntu0.1 [16.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 unixodbc-dev amd64 2.3.9-5ubuntu0.1 [248 kB]
Fetched 264 kB in 8s (33.1 kB/s)
Selecting previously unselected package libodbccr2:amd64.
(Reading database ... 19952 files and directories currently installed.)
Preparing to unpack .../libodbccr2_2.3.9-5ubuntu0.1_amd64.deb ...
Unpacking libodbccr2:amd64 (2.3.9-5ubuntu0.1) ...
Selecting previously unselected package unixodbc-dev:amd64.
Preparing to unpack .../unixodbc-dev_2.3.9-5ubuntu0.1_amd64.deb ...
Unpacking unixodbc-dev:amd64 (2.3.9-5ubuntu0.1) ...
Setting up libodbccr2:amd64 (2.3.9-5ubuntu0.1) ...
Setting up unixodbc-dev:amd64 (2.3.9-5ubuntu0.1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.7) ...
/sbin/ldconfig.real: /opt/mssql/lib/libc++.so.1 is not a symbolic link

/sbin/ldconfig.real: /opt/mssql/lib/libc++abi.so.1 is not a symbolic link

root@sql1:/database_tools#

Before-long, SQL drivers were installed. Now, the meat. We need a python script to watch MQTT. Using chunks from this tutorial, I came up with the following:

#!/usr/bin/python3
import paho.mqtt.client as mqtt
import pyodbc
from datetime import datetime

#MQTT Settings
brokerAddress = "localhost"
userName = "garage_door"
passWord = "password_here"
subscribeTopic = "garage_door/publish/this_is_a_key"

# Connect to Database
driver = "{ODBC Driver 17 for SQL Server}"
server = "localhost"
database = "MQTT_DATA"
username = "mqtt_user"
password = "password_here"
connectionString = "DRIVER=" + driver + ";SERVER=" + server + ";DATABASE=" + database + ";UID=" + username + ";PWD=" + password
conn = pyodbc.connect(connectionString)
cursor = conn.cursor()

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
        if rc == 0:
                print("Connected successfully")
        else:
                print("Connect returned result code: " + str(rc))

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
        topic = msg.topic
        measurementValue = msg.payload.decode("utf-8")
        SaveToDatabase(topic, measurementValue)

def SaveToDatabase(topic, measurementValue):
        print(topic + " " + measurementValue)
        #Find Date and Time
        now = datetime.now()
        datetimeformat = "%Y-%m-%d %H:%M:%S"
        measurementDateTime = now.strftime(datetimeformat)
        # Insert Data into Database
        query = "INSERT INTO MEASUREMENTDATA (SensorName, MeasurementValue, MeasurementDateTime) VALUES (?,?,?)"
        sensorName = topic
        parameters = sensorName, measurementValue, measurementDateTime
        cursor.execute(query, parameters)
        cursor.commit()

# Create the MQTT client
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
#client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS) #this may cause issues if not set up.
client.username_pw_set(userName, passWord)
client.connect(brokerAddress, 1883)
client.subscribe(subscribeTopic)
client.loop_forever()

With all the correct drivers installed, I got the following:

root@sql1:/database_tools# ./mqtt_watcher.py
Traceback (most recent call last):
  File "/database_tools/./mqtt_watcher.py", line 20, in 
    conn = pyodbc.connect(connectionString)
pyodbc.InterfaceError: ('28000', "[28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user 'mqtt_user'. (18456) (SQLDriverConnect)")

HAHA! Yes. It hates me.. and it should... none of those credentials are correct. I went and corrected the auth, the table and the insert schema and the data was logged!

Filed under: Arduino No Comments
2Jul/240

Green Hills, Nou, Itoigawa – June, 2024

Whilst driving with friends from Osaka to Aizuwakamatsu, we needed a place to split the trip and I started Googling. Toyama was a logical mid-way point, but I didn't want us to have to slug it into a boring business hotel when we just needed a place to sleep. Instead, I wanted to enjoy the summer twilight, rail-side in a country house and I managed to find just the place!: Green Hills in Nou.

This beautiful house is perched directly next to the Nihonkai Hisui Line. This happens to be a private line; but it's also the main trunk up the northern coast of Japan and the fastest route for freight from Hokkaido when trying to get further west than Tokyo. So, whilst you won't see JR Limited express trains (thanks to the Hokuriku Shinkansen), you will see trains of the Echigo-Tokimeki Railway and a parade of freight trains hauled by EF510 locomotives.

So, above was taken from the left window that you can see in the first image above. It was the 'second bedroom' on the second floor of the house. It had a beautiful view of the railway! Despite the morning rain, I managed to get up in time for the first 'daylight' freight just after 4am. Disregard the tapping in the video as it's just a leak from the gutter above, beating on the first floor roof.

The trains thundered by like clockwork... and I really need to emphasise on the word 'thundered'. Due to there being a crossover right in front of the tunnel portal next to the house, the katan-katan of the wheelsets was loud enough to actually rattle the foundations of the house.

On the next trip to Japan, I'll probably book this place for a few days and set up a temporary live camera so everyone can enjoy the sights.

Filed under: JPN No Comments
12Jun/240

Curry Station Niagara, Yutenji, Tokyo – June, 2024

This post has been in draft state since mid-2019... as I'd promised myself to visit this restaurant back then, but had never made it. The restaurant in question is Curry Station Niagara in Yutenji, Tokyo. It's a train-themed curry cafe and it's only open from 11-5pm each day. This timing does make it hard... and somehow I'd always targeted it for dinner. Fortunately, this time I had time for lunch!

It's easy to get to, being just a short walk from Tokyo Metro's Yutenji Subway Station. Note that only local trains stop at Yutenji Station!... don't try and take an express! Exit the station via the east exit and turn left. You'll soon find a hint on a corner that you're heading in the right direction...

Follow the extension cable that powers that sign and you'll arrive at the destination.

Once inside, you'll find a bench on the right to wait, whilst a counter seat or booth becomes free. At the end of the waiting area there is a ticket machine to purchase food and beverage. Talk to the proprietor first to work out where to sit and then purchase your tickets.

I went for a counter seat (pretty cramped!) as the three booths were occupied. There's a G-Scale railway running around the perimiter of the restaurant which delivers food, where possible.

Whilst other passengers receive their lunch...

Make sure you take in the full surroundings!

Before-long, my katsu curry arrived... and it was delicious!

Absolutely worth the visit. You even get a ticket as a souvenir of your visit.

Filed under: JPN No Comments
15May/240

Commodore 64C Set – Refurbishment

It's been while since I last had one of these units. A member of an FB group mentioned they had a C64 + Floppy Disks up for grabs, but only offered for someone to come and collect it. It was a 40 minute drive for me, and a good price, so I went for it. I'd asked for pictures whilst negotiating, but none were provided... so I had no idea what I was in for.

Turns out I was in for a great surprise! Included was a Commodore 64c with Commodore 1802 PAL Monitor. Also included was a 1541-II Disk Drive (with a box of disks!) and a Star NX-1000C Dot Matrix printer. I gave it all a cursory once-over and then applied power... but as you can see from the shot above, the happiness was short-lived.

Commodore 1802 Monitor

This unit was only producing a flat squished pattern. The image could be made-out in the squished pattern on the screen, but there was no dial to adjust vertical height... so something had to be going wrong inside. I spooled up What broke on this Commodore 1802 monitor? from Adrian's Digital Basement and left it playing whilst I started dismantling and reviewing the monitor's guts.

Hilariously, we both pulled out the same loose capacitor at the same time... couldn't believe it.

It was an absolute mess where that capacitor was. Its juices had wrecked a few resistor legs as well.

Anyway, the problematic capacitor was replaced and the vertical picture issue was fixed!

Unfortunately, there was no colour. Every site online pointed to a dead R225 (some places incorrectly mention this as R255), and so I looked at R225 on this board...

Crusty! I had no 1w 5.1Kohm resistors in stock, so I paralleled four 22kohm 0.25w resistors.

Did it work? Not really.. I started getting weird colour bars from the composite (ERROR!, this was an assumption) output of the video cable from the C64C.

So I went on a capacitor rampage and replaced everything on the board. Note that the photo below is whilst I was half-way through... trying to clean the gunk off.

This didn't fix it, so I reviewed the data on the Commodore Monitor Information Site. Unfortunately, the Commodore 1802 (tall) was the NTSC version and there was no PDF for my PAL version. Regardless, the schematics sort-of lined up... I just had issues trusting the resistors? Let's have a closer look at that (supposed) 5.1Kohm:

That resistor above has the visible colour-bands of brown red orange gold? It's meant to be a 5.1kohm? Using Element 14's Resistor Calc, I tapped in the colours I could see and was told it's actually a 12kohm resistor? Double? What gives? I then looked at R329 as seen in the photo above-above... it's meant to be a 560ohm resistor, but the colours are showing green-poo-poo-gold? Brown? Red? No idea... but that second colour is meant to be Blue! So wait... these colours have actually cooked so much that their pigment has changed?

I went back to Jaycar and bought 1w resistors that I could actually use to do proper serial maths on... instead of the parallel maths above...

560ohm was a 1:1 install... 5.1k was 1.8k + 3.3k.

Still a crap picture from the C64. A good lesson here is that you should be absolutely sure that your video signal source works... don't just assume that 40 year-old tech can produce a proper composite signal. For this reason, I tried my Playstation 2:

Oh nup, it works... it's me. I'm stupid. Every time I've written composite above, I need to be punished.

That Momement You Realise You're Stupid

This unit was built in 1987. It's a complete set. It plugs together. Why would the unit have a DIN-8 to RCA cable with Yellow+Red+White plugs if they didn't expect you to plug them into the matching sockets on the monitor?

I had assumed all along that they were stereo sound... because... 1995 called and that was the standard. Of course, that's an incorrect assumption as this machine pre-dates any such standards. So... what happens when you plug in the correct colour plugs into the correct colour sockets and switch to the "SEP" mode (i.e. separated Chroma and Luma, as per the plug names)?

LOL. Didn't I feel a little silly? Turns out a C64 DIN-8 Video cable has Yellow=Luma, Red=Chroma and White=Mono-Audio.

Floppy Drive

I tested the voltages out of the power supply, finding that the 5v line was down near 3.2v. Plugging it in and turning on the drive just saw the disk spinning and all lights on.

I found the nearest spare power supply with the relevant 12 and 5v and wired it in. It worked perfectly!

On the original drive power cable, red was 12v, green was 5v and black was ground... but always test, test and re-test before plugging anything together!

Star NX-1000C

Supposedly this thing is colour. I powered it on and it emitted an annoying beep at first. Turns out it just wanted paper. To test, you just need to hold down the online button as you power it on...

Well I'll be... it just worked. It even printed from GEOS. Time to find some tractor-feed dot-matrix printer paper! A quick google tells me that wont be cheap!

GEOS

Rummaging around in the random box of floppy disks proved to be fruitful. There was a GEOS Applications disk, but no base boot disk. I randomly selected a blank disk with no label from the box and tried LOAD "*",8,1. Would you believe it? GEOS booted!

Unfortunately, the desktop wasn't grey... instead it was a hideous shade of smeared pink. All images I could find on the net showed that GEOS should have a light grey background, similar to a macintosh boot. I did find an eBay auction that had similar issues as mine.

I thought it may be chroma/luma, so I rigged up a composite video cable and tested it:

Seems I might need a LumaFix for this... it's on order. Of course, it might just be how it's meant to be displayed.

S-Video Conversions

I nearly fell for the same fallacy again... make sure you can trust your inputs! The 1802 monitor has S-Video style inputs, but it's using RCA plugs. This makes it hard to both connect something else to this 1802 and connect the C64 to another S-Video display. So, what to do? Build an adapter...

Hideous, right? I read here that I needed a 300ohm resistor inline in the Chroma, so that was wedged in. I then whipped out my trusty Sony PVM LCD and ... well, the C64 looked stunning.

The jailbars are there, so I'm looking forward to receivng the LumaFix... but even without it, this monitor goes very well with the C64! So, with the adapter in hand, I flipped the game and routed my Playstation2 through S-Video and into the C64 1802 Monitor.

Shite. So. What's going on here? I know I twiddled all of the potentiometers inside the monitor to oblivion... but those colours are an entire primary-colour off. Just in case you're wondering...

Right behind the 'external' contrast potentiometer is the "sub-brightness" control. "Tint" is R507, next to the grey-box mid-picture. Anyway, something was off, and I had a hunch! I loaded up Sim-City to check how green the grass was and it proved to be grey! The entire green channel was missing? After an hour of multi-metering... I accidently knocked Q555 on the board that plugs into the back of the picture tube and green came back!

Yup, that's Q555, sitting proud at the top of the PCB. I must've bumped it during capacitation and broken the solder joints. A quick re-solder and ....

It's glorious!

Filed under: C64/Amiga No Comments