571/Repairs
Jump to navigation
Jump to search
It is possible with a logic analyzer to digitally capture the image the 571 is sending to its internal monitor.
This can be used for distinguishing whether a problem is with the digital parts of the 571 versus the internal monitor.
It can also be used for grabbing a screenshot in normal operation.
It produces an image like this:
Code:
// vcd_to_image converts a Value Change Dump (VCD) file from a logic analyzer into a PBM image file. // The inputs to the logic analyzer are the HSYNC, VSYNC, and VIDEO signals intended for a monitor. // A VCD file was captured from a Tektronix 571 using this command: // sigrok-cli -d fx2lafw --config 'samplerate=24 MHz' -o cap.vcd -O vcd -C D0=VSYNC,D1=HSYNC,D2=VID --time 400 // Capturing for longer than the duration of a single frame improves image quality. // The vcd_shorthand map needs to reflect the shorthand symbols in the VCD file. // Compile: g++ -O2 -std=c++11 vcd_to_image.cc -o vcd_to_image // Run: ./vcd_to_image < cap.vcd > cap.pbm #include <cmath> #include <iostream> #include <map> #include <regex> #include <string> #include <vector> using namespace std; map<string, string> vcd_shorthand = { {"!", "VSYNC"}, {"\"", "HSYNC"}, {"#", "VID"} }; int tek_571_rows = 351; int tek_571_cols = 640; int image_upscaling = 8; // Small values hurt legibility. Large values hurt efficiency. int ns_per_col = 100 / image_upscaling; int image_rows = tek_571_rows * image_upscaling; int image_cols = tek_571_cols * image_upscaling; int vertical_spreading_amount = image_upscaling; int main() { string line; // Skip the VCD file header lines. for (int line_number = 1; line_number <= 13; line_number++) { getline(std::cin, line); } int row_start_ns = -1; vector<vector<int>> frame_buf(image_rows, vector<int>(image_cols, 0)); int white_start_col = -1; int row_number = -1; int frame_number = -1; bool seen_vsync_low = false; while (getline(std::cin, line)) { regex vcd_format("#([0-9]+) ([0-9])(.)"); smatch s; regex_search(line, s, vcd_format); if (s.size() != 4) continue; int timestamp_ns = stoi(s[1]); int new_state = stoi(s[2]); string signal = vcd_shorthand[s[3]]; if (signal == "VSYNC" && new_state == 1 && seen_vsync_low) { // The rising edge of the VSYNC signal marks the beginning of a frame. row_number = 0; frame_number++; } if (signal == "VSYNC" && new_state == 0) { seen_vsync_low = true; } if (signal == "HSYNC" && new_state == 1) { row_start_ns = timestamp_ns; row_number += image_upscaling; } if (frame_number < 0) continue; // Ignore pixels if we haven't seen a VSYNC rising edge. if (signal == "VID" && new_state == 0) { // We've reached the end of a run of white pixels. int black_start_col = round((double)(timestamp_ns - row_start_ns) / ns_per_col); for (int col = white_start_col; col < black_start_col; col++) { for (int row = row_number; row < row_number + vertical_spreading_amount; row++) { frame_buf[row][col] = 1; } } } if (signal == "VID" && new_state == 1) { // We've reached the end of a run of black pixels. white_start_col = round((double)(timestamp_ns - row_start_ns) / ns_per_col); } } // Output a PBM file. cout << "P1" << endl; cout << image_cols << " " << image_rows << endl; for (int i = 0; i < image_rows; i++) { for (int j = 0; j < image_cols; j++) { // Invert the intensity values so the PBM looks like a monochrome monitor. cout << ((frame_buf[i][j] == 0) ? 1 : 0) << " "; } cout << endl; } return 0; }