HP 54600 Series (First Gen) Module Compatibility Reasoning

The modules are categorized into these characteristics:

  • Plain (oldest, compatible with all): 54650A (GPIB), 54651A (Serial), 54652A (Parallel Printer)
  • Test Automation (TAM) License/Memory: 54655A (GPIB), 54656A (Serial + 5 output lines)
  • FFT/Time & Math License/Memory: 54657A (GPIB), 54659B (Serial+Parallel)
  • Serial + Parallel: 54652B (no FFT), 54659B (with FFT)

The matching oscilloscopes/logic analyzers are sorted into 3 main sub-generations:

  • Too Old (Cannot understand Serial+Parallel): 5460XA, 54610A
  • Everything in between: 5460XB, 54610B, 54620X
  • Too New (Cannot understand TAM): 54615/6B (I suspect C too), 54645A/D

Logic Analyzers (54620A/C) is considered “Everything in between” and it gleefully disregards the Test Automation/FFT features as they are only relevant to analog signals.

Only FFT modules have a RTC to keep time. TAM modules are too primative to have this.

The “Too Old” scopes have newer firmware available that handles FFT (which you need to upgrade by a chip swap if the firmware is too old), but they still don’t understand multiplexing serial & parallel lines they are stuck with 54657A.

54657A covers the broadest range of oscilloscopes (everything)

If you want the FFT and serial port together. There’s only one choice which is 54659B and you have to avold the “Too Old” oscilloscopes

It’s hard to keep track of this compatibility matrix below. That’s why this blog post explained the reasoning by categories above. It really boils down to what features that are too new (multiplexing serial+parallel port) for an old firmware and what features (TAM) the newest firmware dropped support for.

Loading

Spyder traps for MATLAB users (1): By default, Spyder’s F5/Run executes the script from clean workspace.

This is another example of open source projects not going through a comprehensive use case study before changing the default behavior, which end up pulling the rug on some users.

This time it’s Spyder’s good-intentions trying to proactively prevent user mistakes (such as not keeping track of the workspace) throwing the people who meticulously understand their workspace off.

I was working on a FT4222 device which should not be opened again if it’s already opened, aka the ft4222 class object exists. So naturally like in MATLAB, at the top of the script I check if the device object already exist and only create/open it when it’s not already there, like this:

if 'dev' in locals():
    pass
else:
    print('Branch')
    dev = ft4222.openByDescription('FT4222 A')

To my surprise it doesn’t work. 'dev' in locals() always return False every time I press F5, despite when I check again after the script runs, the variable is indeed in there and 'dev' in locals() returns True. WTF?!

Turns out I was not alone! Somebody had the exact same idiom as I did. Spyder 4 changed the default behavior, and we are supposed to manually check this dialog box entry so the scripts do not run off a clean slate when we press F5!

Spyder 5
Spyder 6

It’s an extremely terrible idea to have the IDE muck with the state by default. In MATLAB, if we want the script to start with clean state, we either put clear at the top of the script or clearvars -except to keep the variable.

It’s even harder to catch the new default insidious behavior of Spyder given it runs the script from a clean slate from F5/Run then dump the values to the workspace. It’s now a merge between pre-existing variables in the local() workspace and the results of the script from from a blank state!

The people who decided change to this default behaveior certainly didn’t think through this and rushed to do the obvious to please the careless programmers. If a programmer made a mistake by re-running the script without clearing the workspace and was impacted by the dirty variables, they can always reset everything and get out of this (and learn they should clean up the dirty state through the experience), however, somebody who know what they are doing will not be able to figure out what they did wrong until they search for a behavior that looked more like a bug from Spyder/Python! It’s just horrible design choice! MATLAB doesn’t casually to throw users off like this. Damn!


Also I looked into code cells #%% (MATLAB has the equivalent %%), but there’s another annoyance in Spyder: block commenting through """ or ``` pairs is interpreted as output string from runcelll()! In other words, runcelll() outputs docstrings! So every time you execute the cell, the code you comments will be concatenated into one long raw string with escape characters and pollute your console screen! Damn!


Spyder annoyances (3): The shortcut key Ctrl+D to reset console doesn’t work unless there’s nothing half typed in the console.

Loading

Norton Ghost Behavior for NTFS images modified by GhostExplorer

I discovered today in a hard way (wasted time) to find out that NTFS images modified by new Ghost (AFTER and not including v8.3) Explorer (files injected deleted) will behave as if it’s unmodified (changes not committed) when you try to restore the said image IF YOU DID NOT RECOMPILE!

First of all, injecting/deleting files with Ghost Explorer is like a journaling file system, where the changes are tacked at the end of the file (added files are appended to the end, and deletion doesn’t actually delete, but append extra info saying such file is marked as deleted).

This means until you RECOMPILE (File -> Compile, which shows up as a “Save As” dialog box) the original image stays there.

New Ghosts compatible with file injection/deletion mechanism will respect the extra info tacked at the end and correctly skip the old files that are available when deploying the image. Old Ghosts that doesn’t recognize the extra stuff tacked on at the end that’s written by new Ghost Explorer will just ignore it and your image works as if it’s the old, unmodified image when restored with old Ghosts.

Turns out Ghost Explorer 8.3 or before cannot update files in NTFS partition images.

I’ve experimented with that and realize new Ghosts clones the updates (before compiling) correctly while old Ghosts clones as if it’s the unmodified image. Of course both of them clones correctly after recompilation.

Recompile is a lengthy process that actually go in and delete the orphan files and inject the new files but this needs to be done if you want to save space.

As for compatibility, recompiled ghost images do not work on older ghosts. So you’ll need to restore the image on a physical disk (or a mounted vhd) using new ghost and create the image with old ghost.

Loading

Exploiting Short-Circuit Evaluation for conditional execution

TLDR:

T && X is equivalent to "if( T) then run X"
T || X is equivalent to "if(!T) then run X"

I don’t exploit this too much in C/C++ because it’s hard to read (and therefore hard to keep track of it to make sure it’s bug free) and most often I’m interested in the output value so I have to watch out for the side effects. However this is common in Bash scripts

Domination Property

In languages that expressions evaluates to a value, sometimes if-statements can be replaced by short-circuit evaluation because short-circuit evaluation exploits the domination property of AND and OR logic operations:

\newcommand{\Hquad}{\hspace{0.5em}}
\begin{alignat*}{2}
0 \Hquad & \mathrm{AND} &  \Hquad X  =  0 \\
1 \Hquad & \mathrm{OR} & \Hquad X =  1
\end{alignat*}

When you FIRST run into the dominant value for the binary operation (0 for AND) and (1 for OR), evaluate no further (i.e. skip the rest) because rest won’t change the overall result away from the dominant value.

So in this use case (emulating if-then statements), what the latter expression X evaluates to or what the combined logic value is irrelevant. We are merely tricking the short-circuit mechanism to trip (short) to NOT evaluate based on what the earlier expression turned out. Action is the ‘norm’. Conditional inaction is the essence of this idiom.

The dual of domination property is idempotent, which is easier to reason because if pre-condition (say T) forces overall expression to boil down to the expression we want to conditionally execute (say X), we are stuck evaluating X if condition T is met.

\newcommand{\Hquad}{\hspace{0.5em}}
\begin{alignat*}{2}
1 \Hquad & \mathrm{AND} &  \Hquad X  =  X \\
0 \Hquad & \mathrm{OR} & \Hquad X =  X
\end{alignat*}

These 2 possibilities (domination and idempotency) partitions to space (choices) of possibilities (i.e. cover all possible combinations), in other words there are no other scenarios than described. So the precondition T decides whether you run X or not, which is the equivalent of an if-then statement.

Operator (function) view of logic domination [Functional programming perspective]

By grouping the first value and the binary logic operator with a pair of parenthesis, in dominance view

  • (0 AND) is also called the ‘clear’ operator
  • (1 OR) is also called the ‘set’ operator

but this view is not too interesting for our case because we are not interested in what the conditional expression and the overall expression evaluates to, which is signified by ‘clear’ and ‘set’.

On the other hand, (1 AND) and (0 OR) are pass-through (idempotent) operators which passes the evaluation to the latter expression X.

\newcommand{\Hquad}{\hspace{0.5em}}
\begin{alignat*}{2}
(1 \Hquad & \mathrm{AND}) \Hquad & \circ &  \Hquad X  =  X \\
(0 \Hquad & \mathrm{OR}) \Hquad & \circ & \Hquad X =  X
\end{alignat*}

This reads

  • (1 AND): pass-through (evaluate latter expression) if (earlier expression is) TRUE
  • (0 OR): pass-through (evaluate latter expression) if (earlier expression is) FALSE

Let’s call T the condition to test (the ‘if’-condition). The expression to run remain X.

\newcommand{\Hquad}{\hspace{0.5em}}
\begin{alignat}{2}
(T \Hquad \mathrm{AND}) X & = \overline{f_T}(X) \\
(T \Hquad \mathrm{OR}) X & = f_T(X)
\end{alignat}

where

  • \overline{f_T} reads “Run if T is false”
  • f_T reads “Run if T is true”.

Loading

SoftEther VPN Server Firewall instructions

The firewall rules in MerlinWRT just quit working so the table I entered doesn’t do anything. Seems like other people had the same problem too. So if you just use the WebUI, it’s either turning the firewall all on or all off.

There’s a twist in configuring the firewall with iptables in routers: the instruction you got on the Internet often append the entry to the end of the table in the section (they use the -A switch) and they didn’t explicitly tell you that’s what they are doing and what the implications are.

Turns out when you enable the firewall in the router, it enters a table of DROP ALL lines, which is supposed to be a catch all after all the exceptions you spelled out! You are supposed to enter the exceptions BEFORE the default entries set by the router, not append after, so the packet you want to accept gets fished out before it reaches the catch all (drop all) entries entered by the router automatically when you turn on firewall. So the solution is to replace the -A (append) switch with -I (insert) switch

As for putting SoftEther VPN on MerlinWRT, here’s the commands to type in SSH to add the firewall rules to open the port, which is what the broken WebUI interface was supposed to do:

iptables -I INPUT -p tcp -m multiport --dport 443,992,5555,8888 -j ACCEPT

This line opens SoftEther’s standard ports 443,992,5555,8888, all TCP only.

Don’t even think of using iptables-save as the router do not have persistent storage other than /jffs or USB. I suspect iptables-save merely writes to RAM disk so the changes will be lost on next boot.

You’ll need to put this line in /jffs/scripts/firewall-start script instead. If this is a new file, make sure you chmod +x /jffs/scripts/firewall-start to make the file executable.

Well it’s not too bad of a design after-all since it’s a mess to fish out the iptable lines you want to delete, so keeping your changes in a file to be loaded with the firewall on boot is a smart move.

If all your devices downstream that you forward incoming traffic to (aka servers) has firewalls, the built-in firewall mainly protect the router itself, so if it gets too frustrating, it might not be too big of a deal to turn the router’s firewall off.

There’s also another weird behavior that if the port is firewall blocked, the server admin program intermittently still connect but it connects to a blank state server (blank config). WTF!

More bonus: open ports for UDP acceleration

Setup L2TP/IPsec VPN Server on SoftEther VPN Server – SoftEther VPN Project

I believe UDP port 500 is IKE and UDP port 4500 is IPSec NAT transverasal, which I think it’s used by L2TP/IPsec if you turn it on.

If you use OpenVPN server part of it, open UDP port 1194:

But according to this forum discussion, it simply look up the source code for UDP acceleration to determine the UDP port range they are using:

So I’ll add this line to /jffs/scripts/firewall-start to open UDP ports 500,4500,40000:44999 as well

iptables -I INPUT -p udp -m multiport --dport 500,4500,40000:44999 -j ACCEPT

Loading