Evoluent Vertical Mouse 4 Cable Mod

The mouse cable for Evoluent Vertical Mouse 4 is extremely long, which creates a lot of clutters especially when my keyboard has a USB hub relay built in (it’s the mouse is less than a feet away from it). Instead of splicing the cable, which creates a hard junction that’s not flexible, I modified the mouse to take a micro-USB cable instead.

 4 total views

Flashing router firmware through Serial Port: CFE bootloader (usually Broadcom) based routers

Here’s a summary of learnings from dd-wrt’s serial recovery instructions:

  1. Use a UART controller that signals at 3.3V (e.g. FTDI TTL-232R-3V3) to talk to the board. Regular serial RS-232 ports requires a voltage level shifter converting the signal to swing between 0V to 3.3V.
  2. You only need 3 pins: Tx, Rx and Ground. There’s voltage contention if you plug in the Vcc from TTL-232R-3V3 (It’s the USB’s 5V despite the signaling is 3.3V) to the 3.3V supply of the router. You don’t need the Vcc pin. It didn’t harm anything or do anything when I connected the Vcc pin.
  3. Stick with all serial port defaults and only set the baud to 115200 (default is 9600) and turn off flow control (default is xon/xoff). I use Putty for terminal.
  4. The terminal serves as the monitor for the computer on the router that shows a text console. Broadcom uses CFE bootloader (others use U-Boot with busybox).
  5. CFE bootloader defaults to with subnet mask (aka /24). Set up the network interface to have a static IP on the same subnet to talk to the board.
  6. Good habit: nvram erase
  7. The flash program relies on TFTP protocol to receive the firmware file. So get your TFTP client ready. Microsoft included a TFTP client/server since Windows 7 but usually disabled (turn it on in Windows OptionalFeatures.exe).
  8. TFTP is a simple push(put)/pull(get) design. You can either “push a file on your computer” or “get a file as filename”. You’d want to specify -i switch (binary image transfer) with Windows tftp.exe.
  9. So type this command at the command prompt but don not press enter until your router is ready to grab the file: tftp -i put {path to whatever TRX firmware file}
  10. Go back to the serial terminal and tell the router to accept a TFTP push (in a window of a few seconds before it time out) and flash the memory region flash1.trx with this command: flash -ctheader : flash1.trx
  11. Immediately initiate the TFTP push from your computer (Windows command line example in Step #9 above)
  12. Wait for a couple of hours! The terminal might tell you that it has received the file completely, but it won’t show anything when it’s writing to the flash! It’s a painfully slow process with no feedback. Just be patient!

Some observations

  • FreshTomato firmware absolutely won’t tell you on the screen after it has done flashing (Merlin-WRT does). Just turn the router back on after a couple of hours.
  • Merlin firmware repeats (exposes) the raw passwords to the serial port!
  • FreshTomato firmware boots to a linux prompt on the serial port

 18 total views

Asus-wrt Merlin Firmware DDNS update interval hack

The “WAN – DDNS” page only allows users to set the DDNS updater to check as frequently as every 30 minutes. My DDNS provider does not have an update frequency limit, so I’d like to have the update client check for every 1 minute. The setting is called “Verify every”:

Attempting to set it to every 1 minute gives this error message:

I searched for the “WAN-DDNS” config webpage file (Advanced_ASUSDDNS_Content.asp) in the firmware source code, and found that it’s under /www folder in the router’s linux root.

Since “Verify every” is such generic words, and Github does not support exact phrase match in search (I use “in:file” specifier in the search box), I pick “WAN IP and hostname verification” (the closest setting which I expect the code to be in the proximity of the one corresponding to “Verify every”) so it has more unique keywords. The first jump:

Since it’s just a dictionary files, we search for the associated internal variable name
DDNS_verification_enable” which points to the this line in Advanced_ASUSDDNS_Content.asp:

Since this name appeared nowhere else, I traced the “id” attribute above, which is “check_ddns_field” and I see a Javascript (.js) file that process the data from the web page forms:

The variable check_ddns_field appears in the if-else-if branches of change_ddns_settings(), so one of the few next few variables after it is likely to correspond to “Verify with”.

The variable name showed up in 4 branches of if-elseif-else switches (switching DDNS service providers), which ddns_regular_period comes right after

Searching for the class member (or struct field)

Bingo. Here’s the entry value range check code. I’ll change the “30” minutes to “1” minute to enable checking at 1 minute intervals (which I think it’s reasonably responsive for testing and general use).

I’d prefer to check if the input range check is there out of feasibility (i.e. what is the smallest increment) or it’s just set to prevent people from getting banned by the DDNS provider for checking too frequently. I looked into the last occurrence of ddns_regular_period and found this:

Which means the web forms is updating NVRAM (environmental) variable of the same name ddns_regular_period, which appears to be called only in watchdog.c:

And Dang! The code enforces if the ddns_regular_period (on NVRAM) is set to be less than the original 30 minute minimum (invalid condition), it’d be set to the default 60 minutes (1 hr).

It’s actually sloppy coding because the defaults are specified in struct fields in defaults.c:

yet that 60 minutes is hard-coded in watchdog.c. That means if I don’t catch it and only changed the default in one place, the behavior will not be what I expected given the right conditions. This is an example of why software feature expansion are likely to break things. If you have solid code, bugs on updates are likely to happen.

I was curious why it says (period*2)

and suspected the ddns_check_count is incremented in 30 second (half-minute) interval. Since it’s watchdog.c, my natural guess is that the watchdog checks every 30 seconds for these event hooks. Turns out the notes (comments) in the code has “30 seconds periods” noted everywhere.

I searched a little bit more about linux watchdogs and found this useful webpage which explained how it works. I didn’t see /dev/watchdog in my router’s rootfs (root file system) so I assumed it’s a hardware watchdog (embedded linux, so duh).

I was about to dig up the hardware manual for the chipset for my router, but I search for they string HW_RTC_WATCHDOG  first and it showed up in linux kernel code (duh):

Note that the HW_RTC_WATCHDOG is a register in this code base, not the number of seconds from Christian’s Blog. i.e. they are completely different things, but it provided a good keyword lead for me to start digging.

The code seems to be the same for various kernel version so I picked any one of them to understand the behavior. First occurrence is in wdt_enable():

The other places are suspend/resume, so I’ll ignore those for now. Note that wdt_enable() is a static function, so only need to search within the same file. The only active place that calls it is wdt_ping():

So there are only 2 things I’ll need to find out: heartbeat and WDOG_COUNTER_RATE:

…. unfinished


While it’s a lot of useful learning about Embedded Linux and hunting down source code, for the meantime, given that namecheap does not care if you blindly update every minute, it’s easier to just set up a cron job that runs at every N minutes using curl/wget.

dd-wrt has a place for you to enter the cron scripts with the web interface, but you might need to log into the router using SSH and register the cron job yourself:

The core command is called ‘cru‘, which typing it in the command prompt will show you the very simple usage:

admin@Router:/tmp/home/root# cru

Cron Utility
add:    cru a <unique id> <"min hour day month week command">
delete: cru d <unique id>
list:   cru l

<unique id> is just a tag that you make up to name your task. Again the one-liner command needs to be direct absolute path. My ‘curl‘ program is located in /usr/sbin, so the command is:

cru a ncddns * * * * * /usr/sbin/curl "https://dynamicdns.park-your-domain.com/update?host={subdomain or @ for root}&domain={registered domain name}&password={DDNS-specific password generated by namecheap's domain administration page under Advanced DNS}"

The “* * * * *” refers to run at every “minute, hour, date of month, month, date of week”, in other words, run at every minute in every waking moment. The wild card * means ALL-OF.

Cron job registration through CRU is not persistent, so to make it survive reboots, add the above cru command as a line to /jffs/scripts/services-start script. It should be executable by default, if not, make sure you set it to be executable or it won’t run.

 17 total views

Namecheap Dynamic DNS setup in dd-wrt

Namecheap support page explained the process of configuring your dd-wrt router firmware to use Namecheap’s REST (HTTP URL) update interface to dynamically update the IP of your (sub-)domain. The instruction works, but there are few items which doesn’t quite make sense to me as a programmer, and I did a few experiments to figured that it’s bogus and developed a few insights about what’s necessary and why they do it.

Their instructions looks like this:

and specific verbal instructions are:

  • DDNS Service: Custom
  • DYNDNS Server: dynamicdns.park-your-domain.com – the name of the server should not be changed
  • Username: yourdomain.com – replace it with your domain name
  • Password: Dynamic DNS password for your domain (Domain List >> click on the Manage button next to the domain >> the Advanced DNS tab >> Dynamic DNS)
  • Hostname: Your subdomain (@ for yourdomain.comwww for www.yourdomain.com, etc.)
  • URL/update?domain=yourdomain.com&password=DynamicDNSPassword&host=

I stroke out Username and Password fields because they are not used!

If you look at the URL, namecheap’s instructions are asking you to re-enter the domain and the password key-value pair AGAIN, which means Username and Password fields are not used.

My programmer instinct immediate screams the updater is assuming certain REST API syntax that are not properly substituted so they need to be entered manually, exposing the password without the benefit of the masks (forget about keeping the password top secret, router firmware guys aren’t top security engineers. Just re-generate one in Namecheap’s admin interface if it gets compromised).

I checked by entering bogus Username and Password fields (the web’s GUI/forms checks if they are blank, so you can’t get away with not entering). It worked as expected. This means the two fields are dummies with Namecheap’s instructions.

Based on the fact that Namecheap’s instructions being unable to substitute Username and Password fields and the host key must be put at the end for Hostname field to substitute correctly, I can safely speculate that the one who wrote this couldn’t find out what the syntax for the variables are, and exploit that the last parameter hostname gets attached at the end in the absence of substitution variables in the URL syntax.

Apparent people are doing something stupid like this because nobody in the chain remember to document the substitution variable names! It’s not in dd-wrt’s user interface (should have that printed the ‘usage’ info next to the URL box) and neither it’s in INADYN’s github readmes!

I decided to dig deeper and go after the dynamic DNS updater package in question. dd-wrt is using inadyn package to do the dynamic DNS update, as “INADYN” is shown in “DDNS status” box gives it away (confirmed by dd-wrt’s docs):

The service itself is called ddns though.

I ended up reading the /examples folder on the repository and found this:

Bingo! Here it is:

URL substitution stringdd-wrt fieldsNamecheap REST key

generic.c is a plugin also shows the above table as well

Since namecheap’s dynamic DNS service do not mandate how frequently you can update nor they charge per update, it’s easiest and most reliable to just blindly update the IP every N minutes instead of checking against a local cache to see if the external IP has really changed before updating at each poll interval

This user interface does not have the option to set the updater to run every 1 minute, so why bother since it’s just a simple program that creates a simple URL and do a curl/wget? At the end of the day, I decided to just do a cron job:

* * * * * root curl "https://dynamicdns.park-your-domain.com/update?host={subdomain or @}&domain={domain name bought}&password={generated by namecheap's account management page}"

There are 3 things that you will need to know:

  • Paths is from a clean slate. Need to define it first
  • * * * * * means every minute. Specify numbers/range for each time unit (minute, hour, day of month, month, day of week) if desired. Asterisk means ON EVERY.
  • Need to specify the user after the time syntax and before the actual command

 16 total views

dd-wrt gotchas

dd-wrt is very a powerful firmware compared to ASUS Merlin, but the UI leaves a lot to be desired. It’s very close to editing a config file and there’s little help to what each setting. The developers of dd-wrt didn’t invest time in designing the web administration interface and used the most basic primitive HTML forms so there are no tooltip that explains the features and the interaction between different settings.

There are also some confusing (nonsensical) UI design that are a lot less work to the developer but confused users to no end. Here are the examples I’ve found so far:

  • Enabling remote admin through SSH (for embedded linux command prompt) is a two step process out of the box. You’ll need to first enable SSHd from Services -> Secure Shell before enabling SSH Management from Administration -> Management (otherwise it’s greyed out)
  • The router username (user modifiable) for dd-wrt applies to web UI only. SSH’s username remains root. They share the same password though (so login and password are decoupled in dd-wrt, they are effectively two passwords in practice except they don’t put asterisk over the username as you type). ASUS Merlin firmware’s login is consistent across both web page and SSH
  • Cron jobs is from a bare environment which means you need to manually define the paths and specify the user in the cron job syntax. e.g.
    * * * * * root {command_to_execute}

 15 total views

XFX TS Series 550W Power Supply – Made In China – Bulging Capacitor because it was installed backwards

I opened up my ATX Power Supply as I had it for quite a few years but it has been stowed away and used intermittently until I use it a lot more in my office computer in recent years. I just don’t trust any power supplies Made in China, even from a reputable brand as a couple of decades of working with computers tells me that they are bound to break after a few years, and very often it is the capacitor that rotted and the rest are collateral damages. Lo and behold there is one:

After I took the capacitor out, I noticed something odd: the polarity marker on the circuit board is the reverse of how the capacitor was installed! Holy smokes! I just want to verify if the PCB markings is right or the installer was right, so I installed wires to the capacitor to lift it up so I can connect the multimeter leads across it to measure the voltage polarity. This picture also shows the PCB’s capacitor orientation marking:

And the multimeter reads -5V following the original orientation of the capacitor before I took it out. This means the polarity was reversed!! No wonder the capacitor bulged. I was lucky that it didn’t blow up after a few years of use! Probably it was rated 16V yet only -5V was passed to it so the electrolytic capacitor rotted slowly.

To give XFX Force credit, they didn’t slap the power supply together with the cheapest white label components from the gutters. It uses proper Nichicon and Hitachi capacitor, so it might be the reason that reversed capacitor lasted so many years.

It’s the workmanship in China. If you go with a Red Chinese (Yellow-Soviets) brand, they might use junk components, but don’t think you are safe with foreign companies that has a solid process and design. The cheap labor in China who doesn’t give a crap can still manage to fuck it up. So trust nothing


 28 total views

Tomato OpenVPN client assigned for specific computers

Setting Redirect Internet traffic to “Policy Rules” opens a table where you can specify which computer goes through VPN and which ones uses direct connection. Leave the destination IP unspecified and it’ll pick the as intended

However, there’s a logical trap when you blindly follow instructions setting “Accept DNS configuration” to “Exclusive” as given by most instructions assuming all computers go on the network through VPN. Setting it as “Exclusive” means even the computer not intending to use VPN will still need to go through your VPN provider’s DNS! For slow VPN connection, this will be painfully slow for ALL computers! Set it to “Relaxed” instead.

 49 total views

Aria2 WebUI Notes

Aria2 is a convenient command line downloader that works like curl/wget on http/ftp, but it also support many other protocols, and it aria2 natively multipart download!

Instructions for Aria2 on Entware hosted by Lighttpd (defaults to Port 81): https://www.snbforums.com/threads/aria2-webui-on-asuswrt-merlin.63290/

Instructions for Nginx on Entware (defaults to Port 82): https://hqt.ro/nginx-web-server-with-php-support-through-entware/

Instructions for Aria2 on Entware: https://hqt.ro/aria2-download-manager-through-entware/

There are some minor details that changed.

# Install the base (core) software first
# This example is for entware
opkg install aria2

# Download the package from Github zip to /opt/tmp
wget -c -O /opt/tmp/webui-aria2.zip https://github.com/ziahamza/webui-aria2/archive/master.zip --no-check-certificate

# Make sure you have some web server installed (nginx, httpd, apache, etc.)
# Nginx HTTP server instructions
# https://hqt.ro/nginx-web-server-with-php-support-through-entware/
# Make sure you know what {Webroot} is
# for Nginx, {Webroot} is /opt/share/nginx/html

# Unpack to the zip file at /opt/tmp and clean up the zip
unzip /opt/tmp/webui-aria2.zip -d /opt/tmp/ && rm /opt/tmp/webui-aria2.zip
# Move/rename to desired location
mv /opt/tmp/webui-aria2-master {Webroot}/aria2

Nginx defaults to port 82 (change it to where you set your web server). The WebUI can be accessed at http://your_server_here:82/aria2/docs.

/doc is inconvenient, so I created a redirection by placing this index.html under aria2’s root folder:

<meta http-equiv="Refresh" content="0; url='./docs'" />

The RPC host breaks out of the box because the you’ll need to make a few adjustments to /opt/etc/aria2.conf before you can start the service without crashing it (so the WebUI of course will complain with a lot of cryptic error messages):

# Basic Options
dir={Change it to a viable folder that has enough space if /opt/var/aria2/downloads
 is is not big enough}

# RPC Options
# Unless you want to get a certificate, you'll need to use unsecure mode:
# Change your rpc-secret to be matched in "Connection Settings" in the WebUI

After you get the config file correct

# Start the installed aria2 service 
$ (the package already have a service wrap over aria2c)
# aria2 seem to assume it's port 81 so the init.d script has a "S81" prefix, but aria2 does not control the port, where you put the WebUI in http. So it's just a cosmetic filename naming convention.
/opt/etc/init.d/S81aria2 start

If the service wouldn’t start (some bad configs might have the service reported as “done” and after you check again in a second with “S81aria2 check“, it’ll report as “dead”. You can debug by looking at what went wrong at /opt/var/log/aria2.log. That’s how I figured I need to turn off “rpc-secure” parameter.

 67 total views

Namecheap DDNS does not work in Asus Merlin (Tomato) Firmware until 384.7_2

My router only supported Merlin (Tomato) firmware up to 380.70_0 (2018-04-08) and there are no more updated from that branch.

Turns out the Namecheap DDNS client is not working. I searched its source code at Github for “Namecheap” to see if I can fix the HTTP 400 error (seen in router log) using “in:file” hoping to see if I can fix the bug myself (since it’s just a simple REST API, aka URL call) command and found this:

It means Asuswrt-Merlin (Tomato)’s firmware’s Namecheap DDNS service is broken UNTIL 384.7_2, which is for newer routers than what I have.

I compared the “namecheap” keyword search for the two versions and it seems like they are written very differently, so it might not be worth the effort to fix the obsolete Merlin branch. Doing a bit of additional search and discussions about John’s Merlin fork from the early days are still updated until 2019-04-17 :

It took me a while to find John’s forum post to get to the said 2019-04-18 release. The download link he provided has more updates up to Update-44EA (2020-07-12) and it still worked on my old router, so it’s not just the Update-39L3 previously discussed in the forum:

Do not get discouraged when John’s Merlin fork says version 374.43 instead of 380 (a lower number). All updates, even the latest one from John still use 374.43, which I suppose it’s to mark when the two code branches part ways. It’s not an older version.

 97 total views

ATX Motherboard 433Mhz Wireless Remote Soft Power Button

I tucked away my PC a little away from my workstation desk and the power switch is located at an inconvenient location. I tried to keep the wiring minimal so I’d rather not wire a dedicated ATX power switch onto my desk.

Unfortunately my motherboard does not support turn on by USB keyboard, and I’m not ready to upgrade because I am using it to test PCI data acquisition cards and it’s the fastest one that has 4 PCI slots and they are hard to find nowadays.

I found a $2.5 wireless module on eBay that claims to switch LED lamps which works on the standard 433Mhz channel and it replicates momentary switch pattern and can operate on 5V (My motherboard is new enough to have 5Vsb from onboard USB header).

Initially I was tempted to get the built-in relay version, but I was worried about the current draw from 5Vsb and those are 12V relays., not to mention the footprint is much bigger (the one above is 22.5mmx 11mm x 8mm).

I thought I can figure out with some sort of BJT switch instead of using a relay that has a much bigger current draw requirement, but I realized it’s a pain in the ass because the output is ‘floating’ differential. The OUT- does not tie to the power ground (it’ll short out the unit when I tried to. That’s why I added quotes to ‘floating’ because it’s only relative to OUT+). I also measured OUT+ which is +5V with respect to power ground.

I tried to power a LED and it only works if current flows from OUT+ to OUT- so it’s really sinking current from source power to do that, and it’s unidirectional.

I’d just take a gamble and hook up with a 5V NO relay that I have around. Turned out it actuates with the 5Vsb from the USB header. I glued the relay to the back of the PCB and hook up a flyback/snubber diode (reverse biased) across the relay coil so the back EMF won’t fry my motherboard.

Seems like the transmitter-receiver pair is on momentary switch mode by default, so no addition configuration is needed other than pressing the learn button and immediately press the transmitter button to pair.

I wired a jumper extension cable (male – female) to the relay output from the middle as a by-pass since I’d like to keep the original power switch’s functionality (so it’s basically OR-ing between hardwired switch and the wireless remote 433Mhz switch)

Here’s an example of taking 5Vsb from USB header and tapping into the power switch jumper in Front-Panel jumper block:

Note that the PWR SW- pin is connected to the ground. Since I’m using a relay, the relay output is floating so the polarity does not matter.

 121 total views,  1 views today