Computer History Project 2018: Bringing back a Morrow V9054 1.8 GHz spectrum analyzer back to life

After having revived a HP E1498 VXI controller, which is a VXI Slot sized version of a HP9000 UNIX workstation from the late 90ies of the last century (LINK here) and the revival of a military use Subsonic analysis VME mainframe, it was only a question of time and opportunity to start the next computer history project.

The opportunity came in march 2018. Someone at eBay sold several new old stock Spectrum Analyzers.
I always looked for such a tool but was not willing pay 700 Euros or more for it. The eBay offer was roughly 300 Euros including delivery from USofA and customs. The reason for the low price was that the Analyzer came as a VXI slot card. This means no display, no input knobs and switches. A VXI mainframe controls the card and allows to transfer the data to a PC.

For most people, this is not very attractive. But I have a beautiful VXI  mainframe running, no problem to insert the spectrum analyzer card. So I decided to buy it. Some days later the analyzer arrived.

Morrow Technologies V9054 1.8Ghz Spectrum Analyzer

Morrow Technologies is a company that developed complex hardware solution for its customers. At some point in the mid 90s, they decided to develop some measurement devices because they need such tools themselves and to sell them in the VXI market.
They produced several Spectrum Analyzers, most of them are VXI based devices, which was a unique selling point then and as far as I know, is still today. They went out of the Spectrum Analyzer business later but are still
present with their main product line, which are industrial displays. Maybe I am leaving out important things, but this is what I understand from their website and company history.

My device is a Morrow V9054. It can be used in the range 100KHz .. 1.8GHz. It is a C sized VXI card which occupies two slots in the mainframe. Control is completely via VXI Bus. This means all control commands are send via VXI Word Serial Protocol and all responses (e.g. traces) are sent back by the same channel.

Displaying analyzer data in real-time, can this be done?

Displaying trace data with e.g. 25 frames per second requires transferring roughly 25*2K bytes per second from the VXI mainframe to the PC (for 1024 trace points with 16 bit value per point). This is roughly a continuous transfer of 50 KByte/s. Rendering must be able to process 1K data values with a rate of 25 frames per second.

I want to display the data in a web browser and to transfer the data with WebSockets.
So my first evaluation was to check if these requirements can be met with that technology.  I wrote a backend that generates some fake data and runs on the mainframe controller. This backend uses libwebsockets, a C implementation of WebSockets. The frontend was a simple TypeScript browser application that uses a HTML5 Canvas to render the data as pixels like a scope display.

The first test, without rendering, just pure transmission speed test, showed that I can transfer 600KBytes/second between a C written client and server. The VXI mainframe offers only 10MBit LAN access. So the data transfer
will have no problem with the required data transfer rate. The transmission rate would allow more than 200 frames per second.

The second test was to add HTML5 rendering and to use a browser as client. I experimented with several frame rates between 10 and 50 frames per second and found that the browser is not dropping frames up to 40 frames per second. My requirement is 25 fps, so rendering is also no problem.

To summarize, the targeted technologies would allow a nice rendering of the  analyzer data.

The question is then, how fast can the spectrum analyzer deliver its data?

Accessing the Spectrum Analyzer

The Device arrived with one diskette and one CD.
The diskette (20 years old) contained some libraries for Windows 95 and some include files for programmers. The CD contains a Windows 95 application which can access all spectrum analyzers from Morrow.

The libraries for Windows 95 include a PnP driver, a spectrum analyzer library and several transport layer libraries. These libraries include ISA Bus, VISA and TCP/IP. The later supports some Morrow developed protocol for some of their products that allow TCP/IP access. My device does not allow this. It only allows VXI Serial Word Protocol.

The „closest“ library for my environment is the VISA library. It uses SCPI codes to control the  device. My VXI controller supports SCPI so I am able to access the V9054 with that technology.

First test to access the device was successful. The following C program reads  out the firmware version number of the device.

#include <sicl.h>
#include <stdio.h>

int main(int argc, char **argv) { 
 unsigned short response; 
 unsigned short rpe;
 unsigned int ret;

 INST id = iopen("vxi,126");

 unsigned short cmd = 0xc8ff; // abort normal operation
 ret = ivxiws(id, cmd, &response, &rpe);
 if (response != 0xfffe) {
   printf("Error1: %xn", response);
   return;
 }
 cmd = 0xfcff; // begin normal operation
 ret = ivxiws(id, cmd, &response, &rpe);

 cmd = 0x7c00; // get version
 ret = ivxiws(id, cmd, &response, &rpe);
 int major = response >> 4;
 int minor = response & 0xf;
 printf("Version: %d.%dn", *major, *minor );
}

The only two SICL functions used in this low level example are iopen() and ivxiws(). iopen() opens a communication channel to the device and ivxiws() is executing the Word Serial Protocol.

The card was sold with some manuals. I hoped to get a programmer’s guide in paper or on the CD. But I got no programmers guide. At least I have the Windows 95 compiled libraries…

We have 2018, IT has moved to mystical areas today. So hey, let’s decompile the DLLs.
I checked the available free decompilers. My first try was with Snowman (LINK). It was able to decompile, but I was not able to understand the resulting C code 🙁 . After some hours of trying, I gave up.

Second try was with RetDec. The results were much more  understandable for me, but I need two days to get the first clue whats going on in the decompiled source. Each DLL decompiled in a ~40.000 line of code file.
Most of the functions were named function_0xabfdssada() or so, and so were the parameters and variables.

I searched for known command values in the C Code. I knew some of the codes from the technical guide.  Some other codes are standard codes defined by the VXI spec. All codes are 2 byte words like 0x7c00 or 0xc7ff.
After several hours of searching, I found a function in the code that inquires the firmware version from the Spectrum Analyzer. Yahoo!
Soon I found further codes, all in the Visa library. This was the first sign that that what I was trying was possible with my means.

One of the header files describe a very large struct SA9052 which contains all configuration for the device. This device is used all through the spectrum analyzer library mtcsa32.dll .
The decompiler of course did not know anything about that header file. This means an original code like:

analyzer_config->start = 0.0; // a float value

was decompiled to:

(a1 + 16) = 0;
(a1 + 20) = 0;

So it is very important to know / calculate all byte offsets in the struct. Then the decompiled code can be converted to the original lines, which are of course much more readable.

I needed 2 further days to analyze the struct byte offsets. The compiler aligns contained datataypes to addresses. E.g. a double value is 8 bytes size and its start address inside the struct must then be a multiple of 8.
If the address which would be possible as next free address (e.g. 12) is not a multiple of 8, the next higher value dividable by 8 is used as offset (here: 16). The same is true for 4 byte data types like int32 and two byte data types
like int16.

My calculated offset values were mostly correct, but not all. By analyzing the code, I found a field used by the code but not contained in the struct definition. All offsets after that missing fields were wrong. Puh!
After inserting that field in the struct definition, I could decode all assignments back to the original source code.
I can do that manually. But when looking at ~130.000 LOC, this is not possible. An automated replacement is more or less required, but currently I am still doing this manually at the code pieces I am working on.
The replacement must be quite smart and requires a C code parser…

Going forward

After having a basic understanding what to do and how to do it, I wrote a simple test program for the first API function called mr90xx_init() .

#include <sicl.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <sapform.h>
#include <sa_defin.h>
#include <str_9052.h>
#include <mr_defin.h>
#include <mrapp.h>
#include "helper.h"

int main(int argc, char **argv) {
  char sessionString[50];
  ViChar message[128];
  ViStatus mr90xxStatus;
  ViSession sessionId;

  sprintf(sessionString, "vxi,126");
  mr90xxStatus = mr90xx_init(sessionString, VI_TRUE, VI_TRUE, &sessionId);
  if (mr90xxStatus != MR90XX_IE_SUCCESS) {
    printf("Error mr90xx_initn");
    exit(-1);
  } else {
    printf("mr90xx_init OKnn");
  }
}

Then I created empty files for the three decompiled DLLs named sa.c (for mrtsa32.dll), pnp.c (for mrtpnp32.dll) and visa.c for (mrtvsa32.dll). These files should contain at the end the manually changed code. I call these files the Clean Room Files.

The API function mr90xx_init() is inside mrtpnp.dll. So I copied that function to pnp.c The function calls other functions, so I copied all functions that were called by any function into the file.

By trying to compile and link my test.c , the Linker tells me what functions are still missing.

Result was that I have the complete code from the PnP DLL for the single function mr90xx_init() in a source file and not more.
Remaining are references to functions outside (to other DLLs) and to Windows APIs.

For all referenced functions in mrtsa32.dll, I did the same job and copied everything into the file sa.c. This results in a file sa.c that contains the complete code from the mrtsa32 DLL for the single function mr90xx_init() in a source file and not more.

I found that for the last library, the libvsa32.dll, the Morrow developers used another approach. There is no direct reference to VISA functions in the PnP code. They use a function table to call the transport driver function. This is a feature and allows to call different transport drivers. The driver DLL is loaded by the library depending on its configuration.

The issue here is to find the mapping and to understand how function parameters and return values are handled. I see offsets that are outside the SA9052 struct and that maybe the function pointers. But how are the functions are actually called?

At about that time I started to move my code to github. The complete project is there.

This post will be continued… newest development is always on github…

Amerika, San Diego, 2002

[Den folgenden Text habe ich während einer Dienstreise 2002 aufgeschrieben. Die Fotos wurden noch mit einer Analog-Kamera gemacht.]

Wie schon in Miami und San Francisco fallen mir die vielen Obdachlosen extrem auf. Wegen der sehr milden Witterung (im Winter kaum unter 10° C) ist Obdachlos-Sein einfacher als bei uns. Die Obdachlosen sind deutlich zu erkennen, weil ungepflegt und oft mit schmutziger Kleidung. Es sind meist Männer, das Alter liegt wohl zwischen 30 und 60, die meisten würde ich auf um die 40 schätzen. „Ungepflegt“ heißt, sie haben teilweise enorme Bärte, die offensichtlich nicht geschnitten werden. Oft erscheinen die Gesichter sehr bewachsen oder ungewaschen, so ganz genau kann man es nicht sagen. Untenherum meist eine eher schmutzige Jeans. Obenherum ein Hemd mit Holzfällermuster, so ein dickeres wolliges evtl. Flanellhemd. Mehr braucht man hier nicht an Kleidung. Bessere Ladenpassagen halten sich mit Wachpersonal frei von diesen Leuten. Die öffentlichen Plätze, vor allem wo weniger Betrieb ist, sind aber nicht ohne Obdachlose zu denken. Es sind immer ein paar, die sich einen Platz auf einer Mauer, auf einer Bank oder auf einer Wiese gesucht haben und dort schlafen oder wie im Traum herumstehen oder wandern und manchmal mit sich selbst reden.

Manche sitzen am Straßenrand mit einem Schild und betteln „Vet needs help“ (Vet=Kriegsveteran) und ähnliches. Im Bilboa Park in San Diego beobachte ich, wie ein Obdachloser die vielen Mülleimer, alle in Form großer mittelalterlicher Tonbehälter, systematisch nach verwertbaren Inhalten durchwühlt. Er hat mehrere Tüten bei sich, in einer sind Plastikflaschen drin. Er macht also eine Art Mülltrennung. Mir kommt der Gedanke in den Sinn, dass dies der amerikanische Weg des Recyclings ist: Entnahme aller Wertstoffe durch Obdachlose, denen nicht anderes bleibt um zu leben. Wozu einen teuren grünen Punkt bezahlen, wenn man genug Penner hat.

Vom Hotel sehe ich auf den Parkplatz. Ein Obdachloser kommt über den Parkplatz. Es ist ein „typischer“ obdachloser Mann mit Schiebewagen auf dem eine Kiste befestigt ist, der Schiebegriff des Wagens ist behangen mit Beuteln und Taschen. Die Kleidung: beige Stoffhose, kariertes dickes Flanellhemd hellbeige/blau. Er untersucht die Zahleinheit der Parkplatzschranke sehr genau, möglicherweise hofft er Geld zu finden. Dann schaut er in die Büsche neben der Schranke, wo dann die Parkplätze beginnen. Was ich erst nicht verstehe, offenbart sich schnell. Er zieht eine braune Tüte aus dem Busch. Scheinbar hat jemand Pommes Frites oder ähnliches gekauft und den Beutel vor dem Wegfahren weggeworfen. Der Penner entnimmt etwas dem Beutel und isst es. Während ein Passant vorbeikommt, isst er das nächste Stück aus dem Beutel. Wer weiß, wie lange der da schon lag. Als er fertig ist geht er mit seinem Wagen über die Straße, dort ist ein weiterer großer Parkplatz.

Überhaupt erkenne ich aus meinem Hotelzimmer im 10. Stock, dass viele Stadtviertel einfach Parkplätze sind Wenn man nichts besseres hat bzw. keinen Mieter für ein Geschäftshaus mehr hat, reist man es einfach ab und macht einen Parkplatz. Manchmal wird auf das Asphaltieren verzichtet, dann sieht man den alten Boden der Häuser, darauf stehen Autos.

Gestern Abend sah ich während des Essens, bei dem ich aus dem Restaurant-Fenster sehen konnte, wie sich auf dem Gehweg gegenüber mehrere Obdachlose für die Nacht einrichteten. Es war ca. 7 Uhr und gerade dunkel geworden. Der letzte Obdachlose, den ich beobachtete, entnahm seinem Wagen mit Habseligkeiten Kartonteile, die er als Unterlage auf den Boden legte. Er hatte auch eine Art Schlafsack. Zum Schlafen war es wohl noch zu früh, so setzte er sich mit einem Kollegen darauf und schaute von draußen über die Straße.

Der Flughafen ist mitten in San Diego gelegen. Vom Hotel aus sehe ich auf das Rollfeld, sehe die Flugzeuge herumfahren bzw. parken. Einfliegende Flugzeuge donnern über die Häuser. Die Stadt selbst macht auf mich einen „vergewaltigten“ Eindruck. Irgendetwas menschenfreundliches oder Umweltgesichtspunkte haben keinerlei Rolle beim Ausbau der Stadt gespielt.

Gott sei Dank habe ich den Bilboa Park gefunden. Der ist wunderbar bewachsen mit Palmen, Kakteen und sonstigen grünen ausgefallenen Pflanzen. Häuser im mexikanischen Stil. Der entschädigt für den Rest der Stadt.

Von meinem Hotelbett aus kann ich auf den umliegenden Häusern insgesamt 4 große amerikanische Flaggen sehen. Gestern sah ich ein Feuerwehrfahrzeug vorüberfahren, riesengroß und schöner als unsere, und, das war das besondere, mit einer großen amerikanischen Flagge obendrauf gesteckt. So ca. 1,20 lang und 80cm hoch. Da fiel mir ein: Wohl das einzige Land der Welt, indem sich Feuerwehrleute als so staatstragend sehen, gewissermaßen ein verlängerter Arm des State Department. An mindestens 1/3 der Privathäuser sind ebenfalls irgendwo amerikanische Flaggen angebracht.