Apr 09

Replacing headlights in an Athearn SD40

A few years ago, I got an Athearn SD40 in C&O livery:

Unfortunately, the incandescent lights that the Athearn locomotives come with by default are terrible and don’t last very long, so this locomotive has been running without lights for a while. To replace the lights with LEDs I got two replacement LEDs from Athearn, part numbers ATHG67143(standard length 3mm) and ATHG67145(long length 6.5mm). This is what the LEDs look like next to each other:

It’s not clear from the description on Athearn’s website, but you can see that the 7.5mm and 3mm refers to the length of the lens on the LED.

This is the original LED in the locomotive:

As you can see, the 3mm LED is the best replacement for it. However, this is only true for the rear lights. The front headlights work much better with the 7.5mm LEDs, as the hole fro the LEDs is much longer. So if you plan on doing this mod yourself, you will probably need to buy both sets of LEDs.

Now in my SD40, I had replaced the original circuit board with an NCE DA-SR. The directions for the Athearn LEDs say that you should not wire a resistor in-line with the LEDs. However, NCE recommends that you cut the trace around the pre-populated resistor on the board. In the end, I decided to follow Athearn’s directions and not put a resistor in-line with the LED.

I wired the lights up as I thought they should be, and then it didn’t work. I had wired the black to the ‘common’ pin on the DA-SR. After reversing that, the LEDs turned on! Briefly. And then they immediately burned out.

So after burning out a set of LEDs, I decided to do the correct thing and wire a resistor in-series. With the DA-SR, this is as easy as cutting the trace around the resistor. Since the DA-SR has a ~1k resistor, I also did a quick test wiring the resistors in series. This worked much better:

The lights still have a bit of a glow when they are off, so I tried setting CV120 and CV121 to 129, however this did not do anything. According to the DA-SR manual, setting the value to 128 should tell the decoder that this is an LED. What exactly this does is not clear however, as it does not seem to have any change on the LED. I will have to investigate using JMRI later, as that makes it much easier to set the CV values.

The end result looks pretty good, albeit very bright:

So, in conclusion:
* The Athearn system of individual lights for each real light is terrible. The lenses that other manufacturers use(e.g. Atlas, Kato, maybe others) are much easier to work with
* If you’re using a DA-SR decoder in your locomotive, make sure to cut the resistor bypass and wire the LEDs in series. This may not be needed if you use the standard Athearn board that your locomotive came with
* If you want to replace both the front and rear lights, make sure that you get both the 3mm and 7.5mm LED replacements

Aug 21

Stupid C++ Threads and Lambdas

For a unit test that I’m writing for some code at the moment, I need to create a thread that doesn’t do anything. Well, the easiest way to do this is to do a lambda function. And since we don’t need to capture anything, and the thread doesn’t need to do anything, I have written the following line of code:

std::thread thr = std::thread( [](){} );

Just look at it in its simplicity. In case you missed it:

[](){}

I actually started laughing after I had written that, it’s just so stupid that it’s funny!

Jun 27

Fixing a Gamecube Disk read error

I recently wanted to play my Gamecube again, so I turned it on for the first time in a while. Unfortunately, it would no longer read any of the disks that I had. Upon some internet searching, it seemed like this is a well-known problem with Gamecubes, in that they will eventually stop reading disks. Fortunately, the fix is pretty simple: you need to adjust a variable resistor on the board in order to get the disks to read again.

I’d like to first say that the information that I got on how to adjust the laser was mostly from this very informative Youtube video, so I would recommend watching that video first. In terms of tools to open the Gamecube, I have the ifixit Moray set of screw bits, which has the special bit required to open the Gamecube.

In my particular case, I have a DOL-001 model of Gamecube. According to the information that I have found online, the value of VR-401 should be between 200-500 ohms for this model(other sources say it should be between 450-600 ohms). Upon opening up my Gamecube however, I noticed that it was below what the minimum level should be(I think it was about 195 ohms). I then spent quite a while adjusting the pot to try and get it to a good value, and was unsuccessful. I was tweaking it in very small increments(~5 ohm), putting it back in, and trying it out. Having finally gotten very frustrated with it, I turned it down to 152 ohms, and all of a sudden it started working! It didn’t work 100% of the time(it seems to need to warm up first), but it started working again.

Upon some further adjustment(after I discovered that it wasn’t super reliable), I eventually got it to reliably read disks at 100 ohms! This is much lower than I would have expected based on the model number and expected range of values for this resistor.

Hints when doing this:
* Make sure to take down the original value of VR-401 before you start.
* Try to go in very small increments. At least in my case, there is a very narrow band that VR-401 needs to be in for the disk to be read reliably
* Had I gone down in my adjustments first, I probably wouldn’t have wasted much time adjusting. I was confused because the original value that I got for VR-401 was so much lower than was was to be expected. My guess is that if you need to adjust the value of VR-401, the new value will probably be near the old value.
* Write down the values that you have done. I have probably adjusted VR-401 a hundred times at this point, so knowing where you have gone is good!
* Once you have a good value, write it on the housing inside of the Gamecube near the laser so that if you need to adjust it again, you know what worked!

May 10

C++ pimpl thoughts

Recently, I’ve been writing some C++ code that I would like to be ABI compliant. Because of that, I’ve been writing the code that uses a private class that holds all of the private data members. This results in code that looks something like the following:

// myclass.h

#include <memory>

class MyClass{
public:
	MyClass();
	~MyClass();

	int foo() const;
	void setFoo( int val );

private:
	class priv;

	std::unique_ptr<priv> m_priv;
};

// myclass.cpp
#include "myclass.h"

class MyClass::priv {
public:
	priv() :
	m_foo( 5 )
	{}

	int m_foo;
};

MyClass::MyClass(){
	m_priv = std::make_unique<priv>();
}

MyClass::~MyClass(){
}

int MyClass::foo() const {
	return m_priv->m_foo;
}

void MyClass::setFoo( int foo ){
	m_priv->m_foo = foo;
}

However, after some further reading I realized that this creates a new problem with const methods: mainly that you can’t ensure const correctness! That is, if we change MyClass::foo to be the following, it’s perfectly legal:

int MyClass::foo() const {
	m_priv->m_foo += 10;
	return m_priv->m_foo;
}

Obviously, this particular design results in code that may look const-correct, but actually is not. You can get around that with having an actual pointer to the implementation and not just the private data members, but this seems like a lot of overhead and is really just a lot of boilerplate in my mind.

This leads me to some thoughts on what would make this nicer. The main problem seems to be this facet of C++:

Size and Layout: The calling code must know the size and layout of the class, including private data members.

https://herbsutter.com/gotw/_100/

Since the calling code needs to know the size and layout, any change to this causes ABI breakage, which is certainly not ideal, thus needing the pimpl pattern. What would be nice is if we didn’t have to do this. Thus, I bring my very simple 5-minute solution that hasn’t been thought out fully.

Add a new keyword! Called ‘privdata’.

Example usage:

// myclass.h

#include <memory>

class MyClass{
public:
	MyClass();
	~MyClass();

	int foo() const;
	void setFoo( int val );

private:
	privdata int m_foo;
};

// myclass.cpp
#include "myclass.h"

MyClass::MyClass() : m_foo( 5 ){
}

MyClass::~MyClass(){
}

int MyClass::foo() const {
	return m_foo;
}

void MyClass::setFoo( int foo ){
	m_foo = foo;
}

The idea behind this is that just by declaring a private variable with ‘privdata’ effectively turns the code into what I posted before with the unique_ptr, so that no matter how many private variables you add(with the ‘privdata’ keyword) the class will stay the same size.

Advantages:

  • One keyword to add
  • Very easily make a class ABI compatible.
  • No need to worry about a layer of indirection – the compiler takes care of this for you.
  • Most tools(e.g. IDEs) will still work correctly. One problem with how I’ve been implementing is that Qt Creator doesn’t have nice auto completion for m_priv->…. That’s not the end of the world, but it would be nice!
  • The compiler could still check for const correctness and only allow access in const methods and editing in non-const methods.

Disadvantages:

  • I’ve spent longer writing this post than thinking about this, so I’m certainly missing something.
  • Compilation speedups may not be possible at this point(assuming that you’re using make), since changing something in the header would cause all dependent files to be rebuilt. Maybe we need a new version of make that can parse code to know when things change and only rebuild when something important changes?
  • This requires a lot of compiler changes. New standards require compiler changes anyway, but this probably can’t be implemented without compiler changes.

I did also start looking at some more recent posts from Herb Sutter, and I found this interesting post on making a clonable class. This makes me wonder if this would be possible to do using just standard C++ and some sort of reflection library…


If you want to learn more about the pimpl patter, check out the cppreference page, which also leads to Herb Sutter’s GotW page on pimpl. Herb Sutter’s page was useful for me in terms of learning about the alternatives and how they work.


ADDENDUM NEXT DAY: It turns out, this is possible using some experimental features(std::propagate_const). See this post on Stack Overflow for more information, or on cppreference!

May 02

SSH Key Length Error

I wanted to SSH into a server of mine earlier today, but I was met with this error when I tried to SSH in using the key:

$ ssh -i private-key username@host
Load key "private-key": Invalid key length
username@host's password:

There is some information on this about the exact SSH version that I was using, but one thing that was not clear was if this was a server error or a client error.

As it turns out, this is a client error, the server itself is still fine. There’s a lot of information on the internet, but suffice to say that as of OpenSSH 7.9, you need a key at least 2048 bits long. So to solve this issue, you just need to use an older version of ssh.

If you don’t have an older version of the SSH client available, you could probably get around the issue by installing a virtual machine with an older version of the SSH client. Debian 9(stretch) comes with a version of openssh-client that will work.

Jan 05

Signing VMWare Drivers for UEFI

Earlier today, I had to install VMWare on a Linux host that had UEFI. Fortunately, there is a guide to how to do this on the VMWare KB, however at the end, the part “Reboot your machine. Follow the instructions to complete the enrollment from the UEFI console” is not clear on what exactly you need to do.

In order to get this to work on my Acer Aspire, I did the following(note: I’m not sure what exactly is required, as I was messing around with several settings).

  1. Reboot your system and add a password in the BIOS. Smash F2 when the system boots. Alternatively, GRUB should have an option to go to the BIOS. (this step may not be required)
  2. Generate the keys as shown in the VMWare KB article.
  3. Copy the .der file to /boot/efi/EFI/debian
  4. Reboot the system.
  5. You should get a screen that says ‘Perform MOK Management’. Enroll your key from here. See this site for more details.

And that should be it. It’s not hard to do, but it is not clear and may be different for each manufacturer.