From b52abbfdc771896899d3567f258b823f1834b6bc Mon Sep 17 00:00:00 2001 From: akuker <34318535+akuker@users.noreply.github.com> Date: Fri, 7 Jan 2022 12:17:44 -0600 Subject: [PATCH] Output higher-level report from scsimon (#596) * Output JSON file for post-processing * Debug utility for parsing the SCSI data * Prototype app for parsing scsi captures * correct arg parsing * output html * Cleanupt html output * Add missing include * Allow compilation on non-Linux platforms * Refactored scsimon to be in multiple files * Refactored away * Restructured scsimon into smaller pieces * Added ability to read in pre-generated .json file and re-parse it * Delete scsiparse.cpp * Fix argument parsing and code cleanup * Ran vscode c++ formatting utility * Restore the -Wno-psabi flag for Linux only * Address compiler warnings * Updated to use C++ style ostreams * Cleanup conversion to c++ style ostreams * Updated to use ofstream instead of fprintf * Delete src/raspberrypi/scsimon directory Co-authored-by: akuker --- src/raspberrypi/.gitignore | 3 + src/raspberrypi/Makefile | 24 +- src/raspberrypi/gpiobus.cpp | 4 + src/raspberrypi/monitor/data_sample.cpp | 38 ++ src/raspberrypi/monitor/data_sample.h | 49 ++ src/raspberrypi/monitor/sm_html_report.cpp | 205 ++++++++ src/raspberrypi/monitor/sm_json_report.cpp | 98 ++++ src/raspberrypi/monitor/sm_reports.h | 17 + src/raspberrypi/monitor/sm_vcd_report.cpp | 187 +++++++ src/raspberrypi/os.h | 2 + src/raspberrypi/scsi.h | 1 + src/raspberrypi/scsimon.cpp | 555 ++++++++++----------- 12 files changed, 886 insertions(+), 297 deletions(-) create mode 100644 src/raspberrypi/monitor/data_sample.cpp create mode 100644 src/raspberrypi/monitor/data_sample.h create mode 100644 src/raspberrypi/monitor/sm_html_report.cpp create mode 100644 src/raspberrypi/monitor/sm_json_report.cpp create mode 100644 src/raspberrypi/monitor/sm_reports.h create mode 100644 src/raspberrypi/monitor/sm_vcd_report.cpp diff --git a/src/raspberrypi/.gitignore b/src/raspberrypi/.gitignore index d81380e1..321cbbb5 100644 --- a/src/raspberrypi/.gitignore +++ b/src/raspberrypi/.gitignore @@ -5,11 +5,14 @@ *.layout *.log *.vcd +*.json +*.html rascsi scsimon rasctl sasidump rasdump +scisparse obj bin /rascsi_interface.pb.cpp diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index 81ecefdc..e3c47d87 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -24,8 +24,13 @@ else CXXFLAGS += -O3 -Wall -Werror -DNDEBUG BUILD_TYPE = Release endif +ifeq ("$(shell uname -s)","Linux") + # -Wno-psabi might not work on non-Linux platforms + CXXFLAGS += -Wno-psabi +endif + CFLAGS += -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP -CXXFLAGS += -std=c++17 -Wno-psabi -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP +CXXFLAGS += -std=c++17 -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP ## EXTRA_FLAGS : Can be used to pass special purpose flags CFLAGS += $(EXTRA_FLAGS) @@ -105,9 +110,8 @@ SRC_SCSIMON = \ scsimon.cpp \ scsi.cpp \ gpiobus.cpp \ - filepath.cpp \ - fileio.cpp \ rascsi_version.cpp +SRC_SCSIMON += $(shell find ./monitor -name '*.cpp') SRC_RASCTL = \ rasctl.cpp\ @@ -135,8 +139,8 @@ SRC_SASIDUMP = \ fileio.cpp\ rascsi_version.cpp -vpath %.h ./ ./controllers ./devices -vpath %.cpp ./ ./controllers ./devices +vpath %.h ./ ./controllers ./devices ./monitor +vpath %.cpp ./ ./controllers ./devices ./monitor vpath %.o ./$(OBJDIR) vpath ./$(BINDIR) @@ -193,6 +197,16 @@ $(BINDIR)/$(SASIDUMP): $(OBJ_SASIDUMP) | $(BINDIR) $(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR) $(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread + +# Phony rules for building individual utilities +.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON) +$(RASCSI) : $(BINDIR)/$(RASCSI) +$(RASCTL) : $(BINDIR)/$(RASCTL) +$(RASDUMP) : $(BINDIR)/$(RASDUMP) +$(SASIDUMP): $(BINDIR)/$(SASIDUMP) +$(SCSIMON) : $(BINDIR)/$(SCSIMON) + + ## clean : Remove all of the object files, intermediate ## compiler files and executable files .PHONY: clean diff --git a/src/raspberrypi/gpiobus.cpp b/src/raspberrypi/gpiobus.cpp index a931f102..10a6f985 100644 --- a/src/raspberrypi/gpiobus.cpp +++ b/src/raspberrypi/gpiobus.cpp @@ -1385,6 +1385,7 @@ BOOL GPIOBUS::WaitSignal(int pin, BOOL ast) //--------------------------------------------------------------------------- void GPIOBUS::DisableIRQ() { +#ifdef __linux__ if (rpitype == 4) { // RPI4 is disabled by GICC giccpmr = gicc[GICC_PMR]; @@ -1399,6 +1400,9 @@ void GPIOBUS::DisableIRQ() irptenb = irpctl[IRPT_ENB_IRQ_1]; irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf; } +#else + (void)0; +#endif } //--------------------------------------------------------------------------- diff --git a/src/raspberrypi/monitor/data_sample.cpp b/src/raspberrypi/monitor/data_sample.cpp new file mode 100644 index 00000000..ea8ec048 --- /dev/null +++ b/src/raspberrypi/monitor/data_sample.cpp @@ -0,0 +1,38 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi +// +// Copyright (C) 2020-2021 akuker +// +// [ SCSI Bus Monitor ] +// +//--------------------------------------------------------------------------- +#include "os.h" +#include "scsi.h" +#include "data_sample.h" + +const char *GetPhaseStr(const data_capture *sample) +{ + return BUS::GetPhaseStrRaw(GetPhase(sample)); +} + +BUS::phase_t GetPhase(const data_capture *sample) +{ + // Selection Phase + if (GetSel(sample)) + { + return BUS::selection; + } + + // Bus busy phase + if (!GetBsy(sample)) + { + return BUS::busfree; + } + + // Get target phase from bus signal line + DWORD mci = GetMsg(sample) ? 0x04 : 0x00; + mci |= GetCd(sample) ? 0x02 : 0x00; + mci |= GetIo(sample) ? 0x01 : 0x00; + return BUS::GetPhase(mci); +} diff --git a/src/raspberrypi/monitor/data_sample.h b/src/raspberrypi/monitor/data_sample.h new file mode 100644 index 00000000..e153dc2c --- /dev/null +++ b/src/raspberrypi/monitor/data_sample.h @@ -0,0 +1,49 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2020-2021 akuker +// +// [ SCSI Bus Monitor ] +// +//--------------------------------------------------------------------------- + +#pragma once + +#include "scsi.h" +#include "gpiobus.h" + +typedef struct data_capture +{ + DWORD data; + uint64_t timestamp; +} data_capture_t; + +#define GET_PIN(SAMPLE, PIN) ((bool)((SAMPLE->data >> PIN) & 1)) + +inline bool GetBsy(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_BSY); } +inline bool GetSel(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_SEL); } +inline bool GetAtn(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_ATN); } +inline bool GetAck(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_ACK); } +inline bool GetRst(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_RST); } +inline bool GetMsg(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_MSG); } +inline bool GetCd(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_CD); } +inline bool GetIo(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_IO); } +inline bool GetReq(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_REQ); } +inline bool GetDp(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_DP); } +inline BYTE GetData(const data_capture *sample) +{ + DWORD data = sample->data; + return (BYTE)((data >> (PIN_DT0 - 0)) & (1 << 0)) | + ((data >> (PIN_DT1 - 1)) & (1 << 1)) | + ((data >> (PIN_DT2 - 2)) & (1 << 2)) | + ((data >> (PIN_DT3 - 3)) & (1 << 3)) | + ((data >> (PIN_DT4 - 4)) & (1 << 4)) | + ((data >> (PIN_DT5 - 5)) & (1 << 5)) | + ((data >> (PIN_DT6 - 6)) & (1 << 6)) | + ((data >> (PIN_DT7 - 7)) & (1 << 7)); +} + +const char *GetPhaseStr(const data_capture *sample); +BUS::phase_t GetPhase(const data_capture *sample); diff --git a/src/raspberrypi/monitor/sm_html_report.cpp b/src/raspberrypi/monitor/sm_html_report.cpp new file mode 100644 index 00000000..30f45b96 --- /dev/null +++ b/src/raspberrypi/monitor/sm_html_report.cpp @@ -0,0 +1,205 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Powered by XM6 TypeG Technology. +// Copyright (C) 2016-2020 GIMONS +// +//--------------------------------------------------------------------------- + +#include +#include +#include +#include "os.h" +#include "log.h" +#include "sm_reports.h" +#include "rascsi_version.h" + +using namespace std; + +const static string html_header = R"( + + + + +)"; + +static void print_copyright_info(ofstream& html_fp) +{ + html_fp << "" << endl \ + << "

RaSCSI scsimon Capture Tool

" << endl \ + << "
Version " << rascsi_get_version_string() \
+            << __DATE__ << " " << __TIME__ << endl \
+            << "Copyright (C) 2016-2020 GIMONS" << endl \
+            << "Copyright (C) 2020-2021 Contributors to the RaSCSI project" << endl \
+            << "
" << endl \ + << "
" << endl; +} + +static const string html_footer = R"( + + + +)"; + + +static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, DWORD capture_count) +{ + const data_capture *data; + bool prev_data_valid = false; + bool curr_data_valid; + DWORD selected_id = 0; + BUS::phase_t prev_phase = BUS::busfree; + bool close_row = false; + int data_space_count = 0; + bool collapsible_div_active = false; + bool button_active = false; + + html_fp << "" << endl; + + for (DWORD idx = 0; idx < capture_count; idx++) + { + data = &data_capture_array[idx]; + curr_data_valid = GetAck(data) && GetReq(data); + BUS::phase_t phase = GetPhase(data); + if (phase == BUS::selection && !GetBsy(data)) + { + selected_id = GetData(data); + } + if (prev_phase != phase) + { + if (close_row) + { + if (collapsible_div_active) + { + html_fp << ""; + } + else if (button_active) + { + html_fp << ""; + } + html_fp << ""; + if (data_space_count < 1) + { + html_fp << ""; + } + else + { + html_fp << ""; + } + html_fp << "" << endl; + data_space_count = 0; + } + html_fp << ""; + close_row = true; // Close the row the next time around + html_fp << ""; + html_fp << ""; + html_fp << ""; + html_fp << "
--wc: " << std::dec << "(0x" << std::hex << data_space_count << ")
" << (double)data->timestamp / 100000 << "" << GetPhaseStr(data) << "" << std::hex << selected_id << ""; + } + if (curr_data_valid && !prev_data_valid) + { + if (data_space_count == 0) + { + button_active = true; + html_fp << "
" << endl; + collapsible_div_active = true; + button_active = false; + } + if (((data_space_count % 16) == 0) && (data_space_count > 17)) + { + html_fp << "
" << endl; + } + } + prev_data_valid = curr_data_valid; + prev_phase = phase; + } +} + +void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count) +{ + LOGINFO("Creating HTML report file (%s)", filename); + + ofstream html_ofstream; + + html_ofstream.open(filename, ios::out); + + html_ofstream << html_header; + print_copyright_info(html_ofstream); + print_html_data(html_ofstream, data_capture_array, capture_count); + + html_ofstream << html_footer; + + html_ofstream.close(); +} diff --git a/src/raspberrypi/monitor/sm_json_report.cpp b/src/raspberrypi/monitor/sm_json_report.cpp new file mode 100644 index 00000000..2da7942b --- /dev/null +++ b/src/raspberrypi/monitor/sm_json_report.cpp @@ -0,0 +1,98 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Powered by XM6 TypeG Technology. +// Copyright (C) 2016-2020 GIMONS +// +//--------------------------------------------------------------------------- + +#include "sm_reports.h" +#include "log.h" +#include "spdlog/spdlog.h" +#include "string.h" +#include +#include +using namespace std; + +const char timestamp_label[] = "\"timestamp\":\"0x"; +const char data_label[] = "\"data\":\"0x"; + +DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz) +{ + char str_buf[1024]; + FILE *fp = fopen(json_filename, "r"); + DWORD sample_count = 0; + + while (fgets(str_buf, sizeof(str_buf), fp)) + { + + char timestamp[1024]; + char data[1024]; + uint64_t timestamp_uint; + uint32_t data_uint; + char *ptr; + + char *timestamp_str; + char *data_str; + timestamp_str = strstr(str_buf, timestamp_label); + if (!timestamp_str) + continue; + strncpy(timestamp, ×tamp_str[strlen(timestamp_label)], 16); + timestamp[16] = '\0'; + timestamp_uint = strtoull(timestamp, &ptr, 16); + + data_str = strstr(str_buf, data_label); + if (!data_str) + continue; + strncpy(data, &data_str[strlen(data_label)], 8); + data[8] = '\0'; + data_uint = strtoul(data, &ptr, 16); + + // printf("Time: %016llX Data: %08X\n", timestamp_uint, data_uint); + + data_capture_array[sample_count].timestamp = timestamp_uint; + data_capture_array[sample_count].data = data_uint; + sample_count++; + if (sample_count >= max_sz) + { + LOGWARN("File exceeds maximum buffer size. Some data may be missing."); + LOGWARN("Try re-running the tool with a larger buffer size"); + break; + } + } + fclose(fp); + + return sample_count; +} + +//--------------------------------------------------------------------------- +// +// Generate JSON Output File +// +//--------------------------------------------------------------------------- +void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count) +{ + LOGTRACE("Creating JSON file (%s)", filename); + ofstream json_ofstream; + json_ofstream.open(filename, ios::out); + + json_ofstream << "[" << endl; + + DWORD i = 0; + while (i < capture_count) + { + json_ofstream << fmt::format("{{\"id\": \"{0:d}\", \"timestamp\":\"{1:#016x}\", \"data\":\"{2:#08x}\"}}", i, data_capture_array[i].timestamp, data_capture_array[i].data); + + if (i != (capture_count - 1)) + { + json_ofstream << ","; + } + json_ofstream << endl; + i++; + } + json_ofstream << "]" << endl; + json_ofstream.close(); + +} diff --git a/src/raspberrypi/monitor/sm_reports.h b/src/raspberrypi/monitor/sm_reports.h new file mode 100644 index 00000000..3976e133 --- /dev/null +++ b/src/raspberrypi/monitor/sm_reports.h @@ -0,0 +1,17 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi +// +// Copyright (C) 2020-2021 akuker +// +// [ SCSI Bus Monitor ] +// +//--------------------------------------------------------------------------- + +#include "data_sample.h" + +DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz); + +void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count); +void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count); +void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count); diff --git a/src/raspberrypi/monitor/sm_vcd_report.cpp b/src/raspberrypi/monitor/sm_vcd_report.cpp new file mode 100644 index 00000000..762a949b --- /dev/null +++ b/src/raspberrypi/monitor/sm_vcd_report.cpp @@ -0,0 +1,187 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi +// +// Copyright (C) 2020-2021 akuker +// +// [ SCSI Bus Monitor ] +// +//--------------------------------------------------------------------------- + +#include "os.h" +#include "log.h" +#include "spdlog/spdlog.h" +#include +#include +#include +#include "data_sample.h" +#include "sm_reports.h" +#include "gpiobus.h" + +using namespace std; + +//--------------------------------------------------------------------------- +// +// Constant declarations +// +//--------------------------------------------------------------------------- + +// Symbol definition for the VCD file +// These are just arbitrary symbols. They can be anything allowed by the VCD file format, +// as long as they're consistently used. +const char SYMBOL_PIN_DAT = '#'; +const char SYMBOL_PIN_ATN = '+'; +const char SYMBOL_PIN_RST = '$'; +const char SYMBOL_PIN_ACK = '%'; +const char SYMBOL_PIN_REQ = '^'; +const char SYMBOL_PIN_MSG = '&'; +const char SYMBOL_PIN_CD = '*'; +const char SYMBOL_PIN_IO = '('; +const char SYMBOL_PIN_BSY = ')'; +const char SYMBOL_PIN_SEL = '-'; +const char SYMBOL_PIN_PHASE = '='; + +// We'll use position 0 in the prev_value array to store the previous phase +#define PIN_PHASE 0 + +//--------------------------------------------------------------------------- +// +// Variable declarations +// +//--------------------------------------------------------------------------- +static BYTE prev_value[32] = {0xFF}; + +extern double ns_per_loop; + +static BOOL get_pin_value(DWORD data, int pin) +{ + return (data >> pin) & 1; +} + +static BYTE get_data_field(DWORD data) +{ + DWORD data_out = + ((data >> (PIN_DT0 - 0)) & (1 << 7)) | + ((data >> (PIN_DT1 - 1)) & (1 << 6)) | + ((data >> (PIN_DT2 - 2)) & (1 << 5)) | + ((data >> (PIN_DT3 - 3)) & (1 << 4)) | + ((data >> (PIN_DT4 - 4)) & (1 << 3)) | + ((data >> (PIN_DT5 - 5)) & (1 << 2)) | + ((data >> (PIN_DT6 - 6)) & (1 << 1)) | + ((data >> (PIN_DT7 - 7)) & (1 << 0)); + + return (BYTE)data_out; +} + +static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol) +{ + BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data); + if (prev_value[pin] != new_value) + { + prev_value[pin] = new_value; + fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl; + } +} + +static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol) +{ + BOOL new_value = get_pin_value(data, pin); + if (prev_value[pin] != new_value) + { + prev_value[pin] = new_value; + fp << new_value << symbol << endl; + } +} + +static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char symbol) +{ + BYTE new_value = get_data_field(data); + if (prev_value[pin] != new_value) + { + prev_value[pin] = new_value; + fp << "b" + << fmt::format("{0:b}", get_pin_value(data, PIN_DT7)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT6)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT5)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT4)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT3)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT2)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT1)) + << fmt::format("{0:b}", get_pin_value(data, PIN_DT0)) + << " " << symbol << endl; + } +} + +void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count) +{ + LOGTRACE("Creating Value Change Dump file (%s)", filename); + ofstream vcd_ofstream; + vcd_ofstream.open(filename, ios::out); + + // Get the current time + time_t rawtime; + time(&rawtime); + struct tm *timeinfo = localtime(&rawtime); + char timestamp[256]; + strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo); + + vcd_ofstream + << "$date" << endl + << timestamp << endl + << "$end" << endl + << "$version" << endl + << " VCD generator tool version info text." << endl + << "$end" << endl + << "$comment" << endl + << " Tool build date:" << __TIMESTAMP__ << endl + << "$end" << endl + << "$timescale 1 ns $end" << endl + << "$scope module logic $end" << endl + << "$var wire 1 " << SYMBOL_PIN_BSY << " BSY $end" << endl + << "$var wire 1 " << SYMBOL_PIN_SEL << " SEL $end" << endl + << "$var wire 1 " << SYMBOL_PIN_CD << " CD $end" << endl + << "$var wire 1 " << SYMBOL_PIN_IO << " IO $end"<< endl + << "$var wire 1 " << SYMBOL_PIN_MSG << " MSG $end"<< endl + << "$var wire 1 " << SYMBOL_PIN_REQ << " REQ $end" << endl + << "$var wire 1 " << SYMBOL_PIN_ACK << " ACK $end" << endl + << "$var wire 1 " << SYMBOL_PIN_ATN << " ATN $end" << endl + << "$var wire 1 " << SYMBOL_PIN_RST << " RST $end" << endl + << "$var wire 8 " << SYMBOL_PIN_DAT << " data $end" << endl + << "$var string 1 " << SYMBOL_PIN_PHASE << " phase $end" << endl + << "$upscope $end" << endl + << "$enddefinitions $end" << endl; + + // Initial values - default to zeros + vcd_ofstream + << "$dumpvars" << endl + << "0" << SYMBOL_PIN_BSY << endl + << "0" << SYMBOL_PIN_SEL << endl + << "0" << SYMBOL_PIN_CD << endl + << "0" << SYMBOL_PIN_IO << endl + << "0" << SYMBOL_PIN_MSG << endl + << "0" << SYMBOL_PIN_REQ << endl + << "0" << SYMBOL_PIN_ACK << endl + << "0" << SYMBOL_PIN_ATN << endl + << "0" << SYMBOL_PIN_RST << endl + << "b00000000 " << SYMBOL_PIN_DAT << endl + << "$end" << endl; + + DWORD i = 0; + while (i < capture_count) + { + vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl; + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_IO, SYMBOL_PIN_IO); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_MSG, SYMBOL_PIN_MSG); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_REQ, SYMBOL_PIN_REQ); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_ACK, SYMBOL_PIN_ACK); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_ATN, SYMBOL_PIN_ATN); + vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_RST, SYMBOL_PIN_RST); + vcd_output_if_changed_byte(vcd_ofstream, data_capture_array[i].data, PIN_DT0, SYMBOL_PIN_DAT); + vcd_output_if_changed_phase(vcd_ofstream, data_capture_array[i].data, PIN_PHASE, SYMBOL_PIN_PHASE); + i++; + } + vcd_ofstream.close(); +} diff --git a/src/raspberrypi/os.h b/src/raspberrypi/os.h index 4d6a1a34..29de7867 100644 --- a/src/raspberrypi/os.h +++ b/src/raspberrypi/os.h @@ -58,7 +58,9 @@ #include #include #include +#if defined(__linux__) #include +#endif #include #if defined(__linux__) diff --git a/src/raspberrypi/scsi.h b/src/raspberrypi/scsi.h index 7a6558bd..b911130a 100644 --- a/src/raspberrypi/scsi.h +++ b/src/raspberrypi/scsi.h @@ -10,6 +10,7 @@ //--------------------------------------------------------------------------- #pragma once +#include "os.h" //=========================================================================== // diff --git a/src/raspberrypi/scsimon.cpp b/src/raspberrypi/scsimon.cpp index 7c994280..d16fc893 100644 --- a/src/raspberrypi/scsimon.cpp +++ b/src/raspberrypi/scsimon.cpp @@ -9,8 +9,6 @@ //--------------------------------------------------------------------------- #include "os.h" -#include "filepath.h" -#include "fileio.h" #include "log.h" #include "gpiobus.h" #include "rascsi_version.h" @@ -19,7 +17,11 @@ #include #include #include +#include #include "rascsi.h" +#include +#include "monitor/sm_reports.h" +#include "monitor/data_sample.h" using namespace std; @@ -28,48 +30,47 @@ using namespace std; // Constant declarations // //--------------------------------------------------------------------------- -#define MAX_BUFF_SIZE 1000000 // Symbol definition for the VCD file // These are just arbitrary symbols. They can be anything allowed by the VCD file format, // as long as they're consistently used. -#define SYMBOL_PIN_DAT '#' -#define SYMBOL_PIN_ATN '+' -#define SYMBOL_PIN_RST '$' -#define SYMBOL_PIN_ACK '%' -#define SYMBOL_PIN_REQ '^' -#define SYMBOL_PIN_MSG '&' -#define SYMBOL_PIN_CD '*' -#define SYMBOL_PIN_IO '(' -#define SYMBOL_PIN_BSY ')' -#define SYMBOL_PIN_SEL '-' +#define SYMBOL_PIN_DAT '#' +#define SYMBOL_PIN_ATN '+' +#define SYMBOL_PIN_RST '$' +#define SYMBOL_PIN_ACK '%' +#define SYMBOL_PIN_REQ '^' +#define SYMBOL_PIN_MSG '&' +#define SYMBOL_PIN_CD '*' +#define SYMBOL_PIN_IO '(' +#define SYMBOL_PIN_BSY ')' +#define SYMBOL_PIN_SEL '-' #define SYMBOL_PIN_PHASE '=' -// We'll use position 0 in the prev_value array to store the previous phase -#define PIN_PHASE 0 - //--------------------------------------------------------------------------- // // Variable declarations // //--------------------------------------------------------------------------- -static BYTE prev_value[32] = {0xFF}; -static volatile bool running; // Running flag -GPIOBUS *bus; // GPIO Bus -typedef struct data_capture{ - DWORD data; - uint64_t timestamp; -} data_capture_t; +static volatile bool running; // Running flag +GPIOBUS *bus; // GPIO Bus -data_capture data_buffer[MAX_BUFF_SIZE]; +DWORD buff_size = 1000000; +data_capture *data_buffer; DWORD data_idx = 0; double ns_per_loop; +bool print_help = false; +bool import_data = false; + // We don't really need to support 256 character file names - this causes // all kinds of compiler warnings when the log filename can be up to 256 // characters. _MAX_FNAME/2 is just an arbitrary value. -char log_file_name[_MAX_FNAME/2] = "log.vcd"; +char file_base_name[_MAX_FNAME / 2] = "log"; +char vcd_file_name[_MAX_FNAME]; +char json_file_name[_MAX_FNAME]; +char html_file_name[_MAX_FNAME]; +char input_file_name[_MAX_FNAME]; //--------------------------------------------------------------------------- // @@ -78,8 +79,84 @@ char log_file_name[_MAX_FNAME/2] = "log.vcd"; //--------------------------------------------------------------------------- void KillHandler(int sig) { - // Stop instruction - running = false; + // Stop instruction + running = false; +} + +void parse_arguments(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "-Hhb:i:")) != -1) + { + switch (opt) + { + // The three options below are kind of a compound option with two letters + case 'h': + case 'H': + print_help = true; + break; + case 'b': + buff_size = atoi(optarg); + break; + case 'i': + strncpy(input_file_name, optarg, sizeof(input_file_name)-1); + import_data = true; + break; + case 1: + strncpy(file_base_name, optarg, sizeof(file_base_name) - 5); + break; + default: + cout << "default: " << optarg << endl; + break; + } + } + + /* Process any remaining command line arguments (not options). */ + if (optind < argc) + { + while (optind < argc) + strncpy(file_base_name, argv[optind++], sizeof(file_base_name)-1); + } + + strcpy(vcd_file_name, file_base_name); + strcat(vcd_file_name, ".vcd"); + strcpy(json_file_name, file_base_name); + strcat(json_file_name, ".json"); + strcpy(html_file_name, file_base_name); + strcat(html_file_name, ".html"); +} +//--------------------------------------------------------------------------- +// +// Copyright text +// +//--------------------------------------------------------------------------- +void print_copyright_text(int argc, char *argv[]) +{ + LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) "); + LOGINFO("version %s (%s, %s)", + rascsi_get_version_string(), + __DATE__, + __TIME__); + LOGINFO("Powered by XM6 TypeG Technology "); + LOGINFO("Copyright (C) 2016-2020 GIMONS"); + LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project"); + LOGINFO(" "); +} + +//--------------------------------------------------------------------------- +// +// Help text +// +//--------------------------------------------------------------------------- +void print_help_text(int argc, char *argv[]) +{ + LOGINFO("%s -i [input file json] -b [buffer size] [output file]", argv[0]); + LOGINFO(" -i [input file json] - scsimon will parse the json file instead of capturing new data"); + LOGINFO(" If -i option is not specified, scsimon will read the gpio pins"); + LOGINFO(" -b [buffer size] - Override the default buffer size of %d.", buff_size); + LOGINFO(" [output file] - Base name of the output files. The file extension (ex: .json)"); + LOGINFO(" will be appended to this file name"); } //--------------------------------------------------------------------------- @@ -87,30 +164,23 @@ void KillHandler(int sig) // Banner Output // //--------------------------------------------------------------------------- -void Banner(int argc, char* argv[]) +void Banner(int argc, char *argv[]) { - LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) "); - LOGINFO("version %s (%s, %s)\n", - rascsi_get_version_string(), - __DATE__, - __TIME__); - LOGINFO("Powered by XM6 TypeG Technology "); - LOGINFO("Copyright (C) 2016-2020 GIMONS"); - LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project"); - LOGINFO("Connect type : %s", CONNECT_DESC); - LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", log_file_name); - - if ((argc > 1 && strcmp(argv[1], "-h") == 0) || - (argc > 1 && strcmp(argv[1], "--help") == 0)){ - LOGINFO("Usage: %s [log filename]...", argv[0]); - exit(0); - } + if (import_data) + { + LOGINFO("Reading input file: %s", input_file_name); + } else { - LOGINFO(" "); - LOGINFO("Now collecting data.... Press CTRL-C to stop.") - LOGINFO(" "); + LOGINFO("Reading live data from the GPIO pins"); + LOGINFO(" Connection type : %s", CONNECT_DESC); } + LOGINFO(" Data buffer size: %u", buff_size); + LOGINFO(" "); + LOGINFO("Generating output files:"); + LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", vcd_file_name); + LOGINFO(" %s - JSON file with raw data", json_file_name); + LOGINFO(" %s - HTML file with summary of commands", html_file_name); } //--------------------------------------------------------------------------- @@ -120,246 +190,101 @@ void Banner(int argc, char* argv[]) //--------------------------------------------------------------------------- bool Init() { - // Interrupt handler settings - if (signal(SIGINT, KillHandler) == SIG_ERR) { - return FALSE; - } - if (signal(SIGHUP, KillHandler) == SIG_ERR) { - return FALSE; - } - if (signal(SIGTERM, KillHandler) == SIG_ERR) { - return FALSE; - } + // Interrupt handler settings + if (signal(SIGINT, KillHandler) == SIG_ERR) + { + return FALSE; + } + if (signal(SIGHUP, KillHandler) == SIG_ERR) + { + return FALSE; + } + if (signal(SIGTERM, KillHandler) == SIG_ERR) + { + return FALSE; + } - // GPIO Initialization - bus = new GPIOBUS(); - if (!bus->Init()) { + // GPIO Initialization + bus = new GPIOBUS(); + if (!bus->Init()) + { LOGERROR("Unable to intiailize the GPIO bus. Exiting...."); - return false; - } - - // Bus Reset - bus->Reset(); - - // Other - running = false; - - return true; -} - -BOOL get_pin_value(DWORD data, int pin) -{ - return (data >> pin) & 1; -} - -BYTE get_data_field(DWORD data) -{ - DWORD data_out = - ((data >> (PIN_DT0 - 0)) & (1 << 7)) | - ((data >> (PIN_DT1 - 1)) & (1 << 6)) | - ((data >> (PIN_DT2 - 2)) & (1 << 5)) | - ((data >> (PIN_DT3 - 3)) & (1 << 4)) | - ((data >> (PIN_DT4 - 4)) & (1 << 3)) | - ((data >> (PIN_DT5 - 5)) & (1 << 2)) | - ((data >> (PIN_DT6 - 6)) & (1 << 1)) | - ((data >> (PIN_DT7 - 7)) & (1 << 0)); - - return (BYTE)data_out; -} - -void vcd_output_if_changed_phase(FILE *fp, DWORD data, int pin, char symbol) -{ - BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data); - if (prev_value[pin] != new_value) - { - prev_value[pin] = new_value; - fprintf(fp, "s%s %c\n", GPIOBUS::GetPhaseStrRaw(new_value), symbol); + return false; } -} -void vcd_output_if_changed_bool(FILE *fp, DWORD data, int pin, char symbol) -{ - BOOL new_value = get_pin_value(data,pin); - if (prev_value[pin] != new_value) - { - prev_value[pin] = new_value; - fprintf(fp, "%d%c\n", new_value, symbol); - } -} + // Bus Reset + bus->Reset(); -void vcd_output_if_changed_byte(FILE *fp, DWORD data, int pin, char symbol) -{ - BYTE new_value = get_data_field(data); - if(prev_value[pin] != new_value) - { - prev_value[pin] = new_value; - fprintf(fp, "b%d%d%d%d%d%d%d%d %c\n", - get_pin_value(data,PIN_DT7), - get_pin_value(data,PIN_DT6), - get_pin_value(data,PIN_DT5), - get_pin_value(data,PIN_DT4), - get_pin_value(data,PIN_DT3), - get_pin_value(data,PIN_DT2), - get_pin_value(data,PIN_DT1), - get_pin_value(data,PIN_DT0), symbol); - } -} + // Other + running = false; -void create_value_change_dump() -{ - LOGINFO("Creating Value Change Dump file (%s)", log_file_name); - FILE *fp = fopen(log_file_name,"w"); - - // Get the current time - time_t rawtime; - time(&rawtime); - struct tm *timeinfo = localtime(&rawtime); - char timestamp[256]; - strftime (timestamp,sizeof(timestamp),"%d-%m-%Y %H-%M-%S",timeinfo); - - fprintf(fp, "$date\n"); - fprintf(fp, "%s\n", timestamp); - fprintf(fp, "$end\n"); - fprintf(fp, "$version\n"); - fprintf(fp, " VCD generator tool version info text.\n"); - fprintf(fp, "$end\n"); - fprintf(fp, "$comment\n"); - fprintf(fp, " Tool build date:%s\n", __TIMESTAMP__); - fprintf(fp, "$end\n"); - fprintf(fp, "$timescale 1 ns $end\n"); - fprintf(fp, "$scope module logic $end\n"); - fprintf(fp, "$var wire 1 %c BSY $end\n", SYMBOL_PIN_BSY); - fprintf(fp, "$var wire 1 %c SEL $end\n", SYMBOL_PIN_SEL); - fprintf(fp, "$var wire 1 %c CD $end\n", SYMBOL_PIN_CD); - fprintf(fp, "$var wire 1 %c IO $end\n", SYMBOL_PIN_IO); - fprintf(fp, "$var wire 1 %c MSG $end\n", SYMBOL_PIN_MSG); - fprintf(fp, "$var wire 1 %c REQ $end\n", SYMBOL_PIN_REQ); - fprintf(fp, "$var wire 1 %c ACK $end\n", SYMBOL_PIN_ACK); - fprintf(fp, "$var wire 1 %c ATN $end\n", SYMBOL_PIN_ATN); - fprintf(fp, "$var wire 1 %c RST $end\n", SYMBOL_PIN_RST); - fprintf(fp, "$var wire 8 %c data $end\n", SYMBOL_PIN_DAT); - fprintf(fp, "$var string 1 %c phase $end\n", SYMBOL_PIN_PHASE); - fprintf(fp, "$upscope $end\n"); - fprintf(fp, "$enddefinitions $end\n"); - - // Initial values - default to zeros - fprintf(fp, "$dumpvars\n"); - fprintf(fp, "0%c\n", SYMBOL_PIN_BSY); - fprintf(fp, "0%c\n", SYMBOL_PIN_SEL); - fprintf(fp, "0%c\n", SYMBOL_PIN_CD); - fprintf(fp, "0%c\n", SYMBOL_PIN_IO); - fprintf(fp, "0%c\n", SYMBOL_PIN_MSG); - fprintf(fp, "0%c\n", SYMBOL_PIN_REQ); - fprintf(fp, "0%c\n", SYMBOL_PIN_ACK); - fprintf(fp, "0%c\n", SYMBOL_PIN_ATN); - fprintf(fp, "0%c\n", SYMBOL_PIN_RST); - fprintf(fp, "b00000000 %c\n", SYMBOL_PIN_DAT); - fprintf(fp, "$end\n"); - - DWORD i = 0; - while (i < data_idx) - { - ostringstream s; - s << (uint64_t)(data_buffer[i].timestamp*ns_per_loop); - fprintf(fp, "#%s\n",s.str().c_str()); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_BSY, SYMBOL_PIN_BSY); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_SEL, SYMBOL_PIN_SEL); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_CD, SYMBOL_PIN_CD); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_IO, SYMBOL_PIN_IO); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_MSG, SYMBOL_PIN_MSG); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_REQ, SYMBOL_PIN_REQ); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ACK, SYMBOL_PIN_ACK); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ATN, SYMBOL_PIN_ATN); - vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_RST, SYMBOL_PIN_RST); - vcd_output_if_changed_byte(fp, data_buffer[i].data, PIN_DT0, SYMBOL_PIN_DAT); - vcd_output_if_changed_phase(fp, data_buffer[i].data, PIN_PHASE, SYMBOL_PIN_PHASE); - i++; - } - fclose(fp); + return true; } void Cleanup() { - LOGINFO("Stopping data collection...."); - create_value_change_dump(); + if (!import_data) + { + LOGINFO("Stopping data collection...."); + } + LOGINFO(" "); + LOGINFO("Generating %s...", vcd_file_name); + scsimon_generate_value_change_dump(vcd_file_name, data_buffer, data_idx); + LOGINFO("Generating %s...", json_file_name); + scsimon_generate_json(json_file_name, data_buffer, data_idx); + LOGINFO("Generating %s...", html_file_name); + scsimon_generate_html(html_file_name, data_buffer, data_idx); - // Cleanup the Bus - bus->Cleanup(); - - delete bus; + if (bus) + { + // Cleanup the Bus + bus->Cleanup(); + delete bus; + } } void Reset() { - // Reset the bus - bus->Reset(); + // Reset the bus + bus->Reset(); } //--------------------------------------------------------------------------- // -// Pin the thread to a specific CPU +// Pin the thread to a specific CPU (Only applies to Linux) // //--------------------------------------------------------------------------- +#ifdef __linux__ void FixCpu(int cpu) { - // Get the number of CPUs - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - sched_getaffinity(0, sizeof(cpu_set_t), &cpuset); - int cpus = CPU_COUNT(&cpuset); + // Get the number of CPUs + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + sched_getaffinity(0, sizeof(cpu_set_t), &cpuset); + int cpus = CPU_COUNT(&cpuset); - // Set the thread affinity - if (cpu < cpus) { - CPU_ZERO(&cpuset); - CPU_SET(cpu, &cpuset); - sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); - } + // Set the thread affinity + if (cpu < cpus) + { + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); + } } +#endif #ifdef DEBUG static DWORD high_bits = 0x0; static DWORD low_bits = 0xFFFFFFFF; -#endif +#endif //--------------------------------------------------------------------------- // // Main processing // //--------------------------------------------------------------------------- -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { - ostringstream s; - - #ifdef DEBUG - DWORD prev_high = high_bits; - DWORD prev_low = low_bits; -#endif - DWORD prev_sample = 0xFFFFFFFF; - DWORD this_sample = 0; - struct sched_param schparam; - timeval start_time; - timeval stop_time; - uint64_t loop_count = 0; - timeval time_diff; - uint64_t elapsed_us; - int str_len; - - // If there is an argument specified and it is NOT -h or --help - if((argc > 1) && (strcmp(argv[1], "-h")) && (strcmp(argv[1], "--help"))){ - str_len = strlen(argv[1]); - if ((str_len >= 1) && (str_len < _MAX_FNAME)) - { - strncpy(log_file_name, argv[1], sizeof(log_file_name)); - // Append .vcd if its not already there - if((str_len < 4) || strcasecmp(log_file_name + (str_len - 4), ".vcd")) { - strcat(log_file_name, ".vcd"); - } - } - else - { - printf("Invalid log name specified. Using log.vcd"); - } - } #ifdef DEBUG spdlog::set_level(spdlog::level::trace); @@ -367,53 +292,98 @@ int main(int argc, char* argv[]) spdlog::set_level(spdlog::level::info); #endif spdlog::set_pattern("%^[%l]%$ %v"); - // Output the Banner - Banner(argc, argv); - memset(data_buffer,0,sizeof(data_buffer)); - // Initialize - int ret = 0; - if (!Init()) { - ret = EPERM; - goto init_exit; - } + print_copyright_text(argc, argv); + parse_arguments(argc, argv); - // Reset - Reset(); +#ifdef DEBUG + DWORD prev_high = high_bits; + DWORD prev_low = low_bits; +#endif + ostringstream s; + DWORD prev_sample = 0xFFFFFFFF; + DWORD this_sample = 0; + timeval start_time; + timeval stop_time; + uint64_t loop_count = 0; + timeval time_diff; + uint64_t elapsed_us; + if (print_help) + { + print_help_text(argc, argv); + exit(0); + } + + // Output the Banner + Banner(argc, argv); + + data_buffer = (data_capture *)malloc(sizeof(data_capture_t) * buff_size); + bzero(data_buffer, sizeof(data_capture_t) * buff_size); + + if (import_data) + { + data_idx = scsimon_read_json(input_file_name, data_buffer, buff_size); + if (data_idx > 0) + { + LOGDEBUG("Read %d samples from %s", data_idx, input_file_name); + Cleanup(); + } + exit(0); + } + + LOGINFO(" "); + LOGINFO("Now collecting data.... Press CTRL-C to stop.") + LOGINFO(" "); + + // Initialize + int ret = 0; + if (!Init()) + { + ret = EPERM; + goto init_exit; + } + + // Reset + Reset(); + +#ifdef __linux__ // Set the affinity to a specific processor core - FixCpu(3); + FixCpu(3); - // Scheduling policy setting (highest priority) - schparam.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_setscheduler(0, SCHED_FIFO, &schparam); + // Scheduling policy setting (highest priority) + struct sched_param schparam; + schparam.sched_priority = sched_get_priority_max(SCHED_FIFO); + sched_setscheduler(0, SCHED_FIFO, &schparam); +#endif - // Start execution - running = true; - bus->SetACT(FALSE); + // Start execution + running = true; + bus->SetACT(FALSE); (void)gettimeofday(&start_time, NULL); - LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS); + LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS); // Main Loop - while (running) { - // Work initialization - this_sample = (bus->Aquire() & ALL_SCSI_PINS); + while (running) + { + // Work initialization + this_sample = (bus->Aquire() & ALL_SCSI_PINS); loop_count++; - if (loop_count > LLONG_MAX -1) + if (loop_count > LLONG_MAX - 1) { LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating."); - running=false; + running = false; } - if (data_idx >= (MAX_BUFF_SIZE-2)) + if (data_idx >= (buff_size - 2)) { LOGINFO("Internal data buffer is full. SCSIMON is terminating."); - running=false; + running = false; } - if (this_sample != prev_sample) - { + if (this_sample != prev_sample) + { #ifdef DEBUG // This is intended to be a debug check to see if every pin is set @@ -422,27 +392,28 @@ int main(int argc, char* argv[]) low_bits &= this_sample; if ((high_bits != prev_high) || (low_bits != prev_low)) { - LOGDEBUG(" %08X %08X\n",high_bits, low_bits); + LOGDEBUG(" %08X %08X\n", high_bits, low_bits); } prev_high = high_bits; prev_low = low_bits; - if((data_idx % 1000) == 0){ - s.str(""); - s << "Collected " << data_idx << " samples..."; - LOGDEBUG("%s", s.str().c_str()); + if ((data_idx % 1000) == 0) + { + s.str(""); + s << "Collected " << data_idx << " samples..."; + LOGDEBUG("%s", s.str().c_str()); } #endif data_buffer[data_idx].data = this_sample; data_buffer[data_idx].timestamp = loop_count; data_idx++; prev_sample = this_sample; - } + } - continue; - } + continue; + } // Collect one last sample, otherwise it looks like the end of the data was cut off - if (data_idx < MAX_BUFF_SIZE) + if (data_idx < buff_size) { data_buffer[data_idx].data = this_sample; data_buffer[data_idx].timestamp = loop_count; @@ -453,7 +424,7 @@ int main(int argc, char* argv[]) timersub(&stop_time, &start_time, &time_diff); - elapsed_us = ((time_diff.tv_sec*1000000) + time_diff.tv_usec); + elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec); s.str(""); s << "Elapsed time: " << elapsed_us << " microseconds (" << elapsed_us / 1000000 << " seconds)"; LOGINFO("%s", s.str().c_str()); @@ -461,14 +432,14 @@ int main(int argc, char* argv[]) s << "Collected " << data_idx << " changes"; LOGINFO("%s", s.str().c_str()); - // Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps. + // Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps. ns_per_loop = (elapsed_us * 1000) / (double)loop_count; s.str(""); s << "Read the SCSI bus " << loop_count << " times with an average of " << ns_per_loop << " ns for each read"; LOGINFO("%s", s.str().c_str()); - Cleanup(); + Cleanup(); init_exit: - exit(ret); + exit(ret); }