mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-21 23:29:39 +00:00
52c2aa474f
* Rebrand project to PiSCSI - rascsi ->piscsi - rasctl -> scsictl - rasdump -> scsidump - ras* -> piscsi* (rasutil -> piscsi_util, etc.) * Refined the formatting and wording of the app startup banner * Kept some references to rascsi and rasctl where backwards compatibility is concerned * Point to the new github repo URL Co-authored-by: nucleogenic <nr@nucleogenic.com> Co-authored-by: Uwe Seimet <Uwe.Seimet@seimet.de>
592 lines
22 KiB
C++
592 lines
22 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator PiSCSI for Raspberry Pi
|
|
// Loopback tester utility
|
|
//
|
|
// Copyright (C) 2022 akuker
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "scsiloop/scsiloop_gpio.h"
|
|
#include "hal/gpiobus_factory.h"
|
|
#include "hal/sbc_version.h"
|
|
#include "scsiloop/scsiloop_cout.h"
|
|
#include "shared/log.h"
|
|
|
|
#if defined CONNECT_TYPE_STANDARD
|
|
#include "hal/connection_type/connection_standard.h"
|
|
#elif defined CONNECT_TYPE_FULLSPEC
|
|
#include "hal/connection_type/connection_fullspec.h"
|
|
#elif defined CONNECT_TYPE_AIBOM
|
|
#include "hal/connection_type/connection_aibom.h"
|
|
#elif defined CONNECT_TYPE_GAMERNIUM
|
|
#include "hal/connection_type/connection_gamernium.h"
|
|
#else
|
|
#error Invalid connection type or none specified
|
|
#endif
|
|
|
|
ScsiLoop_GPIO::ScsiLoop_GPIO()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
|
|
bus = GPIOBUS_Factory::Create(BUS::mode_e::TARGET);
|
|
if (bus == nullptr) {
|
|
throw bus_exception("Unable to create bus");
|
|
}
|
|
|
|
// At compile time, we don't know which type of board we're using. So, we'll build these at runtime.
|
|
// TODO: This logic should be re-structured when/if other variants of SBCs are added in.
|
|
if (SBC_Version::IsRaspberryPi()) {
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT0, .connected_pin = PIN_ACK, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT1, .connected_pin = PIN_SEL, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT2, .connected_pin = PIN_ATN, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT3, .connected_pin = PIN_RST, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT4, .connected_pin = PIN_CD, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT5, .connected_pin = PIN_IO, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT6, .connected_pin = PIN_MSG, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DT7, .connected_pin = PIN_REQ, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_DP, .connected_pin = PIN_BSY, .dir_ctrl_pin = PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_ATN, .connected_pin = PIN_DT2, .dir_ctrl_pin = PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_RST, .connected_pin = PIN_DT3, .dir_ctrl_pin = PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_ACK, .connected_pin = PIN_DT0, .dir_ctrl_pin = PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_REQ, .connected_pin = PIN_DT7, .dir_ctrl_pin = PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_MSG, .connected_pin = PIN_DT6, .dir_ctrl_pin = PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_CD, .connected_pin = PIN_DT4, .dir_ctrl_pin = PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_IO, .connected_pin = PIN_DT5, .dir_ctrl_pin = PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_BSY, .connected_pin = PIN_DP, .dir_ctrl_pin = PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = PIN_SEL, .connected_pin = PIN_DT1, .dir_ctrl_pin = PIN_IND});
|
|
pin_name_lookup[PIN_DT0] = " d0";
|
|
pin_name_lookup[PIN_DT1] = " d1";
|
|
pin_name_lookup[PIN_DT2] = " d2";
|
|
pin_name_lookup[PIN_DT3] = " d3";
|
|
pin_name_lookup[PIN_DT4] = " d4";
|
|
pin_name_lookup[PIN_DT5] = " d5";
|
|
pin_name_lookup[PIN_DT6] = " d6";
|
|
pin_name_lookup[PIN_DT7] = " d7";
|
|
pin_name_lookup[PIN_DP] = " dp";
|
|
pin_name_lookup[PIN_ATN] = "atn";
|
|
pin_name_lookup[PIN_RST] = "rst";
|
|
pin_name_lookup[PIN_ACK] = "ack";
|
|
pin_name_lookup[PIN_REQ] = "req";
|
|
pin_name_lookup[PIN_MSG] = "msg";
|
|
pin_name_lookup[PIN_CD] = " cd";
|
|
pin_name_lookup[PIN_IO] = " io";
|
|
pin_name_lookup[PIN_BSY] = "bsy";
|
|
pin_name_lookup[PIN_SEL] = "sel";
|
|
pin_name_lookup[PIN_IND] = "ind";
|
|
pin_name_lookup[PIN_TAD] = "tad";
|
|
pin_name_lookup[PIN_DTD] = "dtd";
|
|
|
|
local_pin_dtd = PIN_DTD;
|
|
local_pin_tad = PIN_TAD;
|
|
local_pin_ind = PIN_IND;
|
|
local_pin_ack = PIN_ACK;
|
|
local_pin_sel = PIN_SEL;
|
|
local_pin_atn = PIN_ATN;
|
|
local_pin_rst = PIN_RST;
|
|
local_pin_cd = PIN_CD;
|
|
local_pin_io = PIN_IO;
|
|
local_pin_msg = PIN_MSG;
|
|
local_pin_req = PIN_REQ;
|
|
local_pin_bsy = PIN_BSY;
|
|
local_pin_dt0 = PIN_DT0;
|
|
local_pin_dt1 = PIN_DT1;
|
|
local_pin_dt2 = PIN_DT2;
|
|
local_pin_dt3 = PIN_DT3;
|
|
local_pin_dt4 = PIN_DT4;
|
|
local_pin_dt5 = PIN_DT5;
|
|
local_pin_dt6 = PIN_DT6;
|
|
local_pin_dt7 = PIN_DT7;
|
|
local_pin_dp = PIN_DP;
|
|
|
|
} else if (SBC_Version::GetSbcVersion() == SBC_Version::sbc_version_type::sbc_bananapi_m2_plus) {
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT0, .connected_pin = BPI_PIN_ACK, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT1, .connected_pin = BPI_PIN_SEL, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT2, .connected_pin = BPI_PIN_ATN, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT3, .connected_pin = BPI_PIN_RST, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT4, .connected_pin = BPI_PIN_CD, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT5, .connected_pin = BPI_PIN_IO, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT6, .connected_pin = BPI_PIN_MSG, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DT7, .connected_pin = BPI_PIN_REQ, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_DP, .connected_pin = BPI_PIN_BSY, .dir_ctrl_pin = BPI_PIN_DTD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_ATN, .connected_pin = BPI_PIN_DT2, .dir_ctrl_pin = BPI_PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_RST, .connected_pin = BPI_PIN_DT3, .dir_ctrl_pin = BPI_PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_ACK, .connected_pin = BPI_PIN_DT0, .dir_ctrl_pin = BPI_PIN_IND});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_REQ, .connected_pin = BPI_PIN_DT7, .dir_ctrl_pin = BPI_PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_MSG, .connected_pin = BPI_PIN_DT6, .dir_ctrl_pin = BPI_PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_CD, .connected_pin = BPI_PIN_DT4, .dir_ctrl_pin = BPI_PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_IO, .connected_pin = BPI_PIN_DT5, .dir_ctrl_pin = BPI_PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_BSY, .connected_pin = BPI_PIN_DP, .dir_ctrl_pin = BPI_PIN_TAD});
|
|
loopback_conn_table.push_back(
|
|
loopback_connection{.this_pin = BPI_PIN_SEL, .connected_pin = BPI_PIN_DT1, .dir_ctrl_pin = BPI_PIN_IND});
|
|
|
|
pin_name_lookup[BPI_PIN_DT0] = " d0";
|
|
pin_name_lookup[BPI_PIN_DT1] = " d1";
|
|
pin_name_lookup[BPI_PIN_DT2] = " d2";
|
|
pin_name_lookup[BPI_PIN_DT3] = " d3";
|
|
pin_name_lookup[BPI_PIN_DT4] = " d4";
|
|
pin_name_lookup[BPI_PIN_DT5] = " d5";
|
|
pin_name_lookup[BPI_PIN_DT6] = " d6";
|
|
pin_name_lookup[BPI_PIN_DT7] = " d7";
|
|
pin_name_lookup[BPI_PIN_DP] = " dp";
|
|
pin_name_lookup[BPI_PIN_ATN] = "atn";
|
|
pin_name_lookup[BPI_PIN_RST] = "rst";
|
|
pin_name_lookup[BPI_PIN_ACK] = "ack";
|
|
pin_name_lookup[BPI_PIN_REQ] = "req";
|
|
pin_name_lookup[BPI_PIN_MSG] = "msg";
|
|
pin_name_lookup[BPI_PIN_CD] = " cd";
|
|
pin_name_lookup[BPI_PIN_IO] = " io";
|
|
pin_name_lookup[BPI_PIN_BSY] = "bsy";
|
|
pin_name_lookup[BPI_PIN_SEL] = "sel";
|
|
pin_name_lookup[BPI_PIN_IND] = "ind";
|
|
pin_name_lookup[BPI_PIN_TAD] = "tad";
|
|
pin_name_lookup[BPI_PIN_DTD] = "dtd";
|
|
|
|
local_pin_dtd = BPI_PIN_DTD;
|
|
local_pin_tad = BPI_PIN_TAD;
|
|
local_pin_ind = BPI_PIN_IND;
|
|
local_pin_ack = BPI_PIN_ACK;
|
|
local_pin_sel = BPI_PIN_SEL;
|
|
local_pin_atn = BPI_PIN_ATN;
|
|
local_pin_rst = BPI_PIN_RST;
|
|
local_pin_cd = BPI_PIN_CD;
|
|
local_pin_io = BPI_PIN_IO;
|
|
local_pin_msg = BPI_PIN_MSG;
|
|
local_pin_req = BPI_PIN_REQ;
|
|
local_pin_bsy = BPI_PIN_BSY;
|
|
local_pin_dt0 = BPI_PIN_DT0;
|
|
local_pin_dt1 = BPI_PIN_DT1;
|
|
local_pin_dt2 = BPI_PIN_DT2;
|
|
local_pin_dt3 = BPI_PIN_DT3;
|
|
local_pin_dt4 = BPI_PIN_DT4;
|
|
local_pin_dt5 = BPI_PIN_DT5;
|
|
local_pin_dt6 = BPI_PIN_DT6;
|
|
local_pin_dt7 = BPI_PIN_DT7;
|
|
local_pin_dp = BPI_PIN_DP;
|
|
|
|
} else {
|
|
LOGERROR("Unsupported board version: %s", SBC_Version::GetString()->c_str());
|
|
}
|
|
}
|
|
|
|
void ScsiLoop_GPIO::Cleanup()
|
|
{
|
|
bus->Cleanup();
|
|
}
|
|
|
|
// Set transceivers IC1 and IC2 to OUTPUT
|
|
void ScsiLoop_GPIO::set_dtd_out()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_dtd, DTD_OUT);
|
|
}
|
|
|
|
// Set transceivers IC1 and IC2 to INPUT
|
|
void ScsiLoop_GPIO::set_dtd_in()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_dtd, DTD_IN);
|
|
}
|
|
// Set transceiver IC4 to OUTPUT
|
|
void ScsiLoop_GPIO::set_ind_out()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_ind, IND_OUT);
|
|
}
|
|
// Set transceiver IC4 to INPUT
|
|
void ScsiLoop_GPIO::set_ind_in()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_ind, IND_IN);
|
|
}
|
|
// Set transceiver IC3 to OUTPUT
|
|
void ScsiLoop_GPIO::set_tad_out()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_tad, TAD_OUT);
|
|
}
|
|
// Set transceiver IC3 to INPUT
|
|
void ScsiLoop_GPIO::set_tad_in()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
bus->SetControl(local_pin_tad, TAD_IN);
|
|
}
|
|
|
|
// Set the specified transciever to an OUTPUT. All of the other transceivers
|
|
// will be set to inputs. If a non-existent direction gpio is specified, this
|
|
// will set all of the transceivers to inputs.
|
|
void ScsiLoop_GPIO::set_output_channel(int out_gpio)
|
|
{
|
|
LOGTRACE("%s tad: %d dtd: %d ind: %d", CONNECT_DESC.c_str(), (int)local_pin_tad, (int)local_pin_dtd,
|
|
(int)local_pin_ind);
|
|
if (out_gpio == local_pin_tad)
|
|
set_tad_out();
|
|
else
|
|
set_tad_in();
|
|
if (out_gpio == local_pin_dtd)
|
|
set_dtd_out();
|
|
else
|
|
set_dtd_in();
|
|
if (out_gpio == local_pin_ind)
|
|
set_ind_out();
|
|
else
|
|
set_ind_in();
|
|
}
|
|
|
|
// Initialize the GPIO library, set all of the gpios associated with SCSI signals to outputs and set
|
|
// all of the direction control gpios to outputs
|
|
void ScsiLoop_GPIO::loopback_setup()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
|
|
for (loopback_connection cur_gpio : loopback_conn_table) {
|
|
if (cur_gpio.this_pin == -1) {
|
|
continue;
|
|
}
|
|
bus->PinConfig(cur_gpio.this_pin, GPIO_OUTPUT);
|
|
bus->PullConfig(cur_gpio.this_pin, GPIO_PULLNONE);
|
|
}
|
|
|
|
// Setup direction control
|
|
if (local_pin_ind != -1) {
|
|
bus->PinConfig(local_pin_ind, GPIO_OUTPUT);
|
|
}
|
|
if (local_pin_tad != -1) {
|
|
bus->PinConfig(local_pin_tad, GPIO_OUTPUT);
|
|
}
|
|
if (local_pin_dtd != -1) {
|
|
bus->PinConfig(local_pin_dtd, GPIO_OUTPUT);
|
|
}
|
|
}
|
|
|
|
// Main test procedure.This will execute for each of the SCSI pins to make sure its connected
|
|
// properly.
|
|
int ScsiLoop_GPIO::test_gpio_pin(loopback_connection &gpio_rec, vector<string> &error_list, bool &loopback_adapter_missing)
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
|
|
int err_count = 0;
|
|
int sleep_time = 1000;
|
|
|
|
LOGTRACE("dir ctrl pin: %d", (int)gpio_rec.dir_ctrl_pin);
|
|
set_output_channel(gpio_rec.dir_ctrl_pin);
|
|
usleep(sleep_time);
|
|
|
|
// Set all GPIOs high (initialize to a known state)
|
|
for (auto cur_gpio : loopback_conn_table) {
|
|
// bus->SetSignal(cur_gpio.this_pin, OFF);
|
|
bus->SetMode(cur_gpio.this_pin, GPIO_INPUT);
|
|
}
|
|
|
|
usleep(sleep_time);
|
|
bus->Acquire();
|
|
|
|
// ############################################
|
|
// set the test gpio low
|
|
bus->SetMode(gpio_rec.this_pin, GPIO_OUTPUT);
|
|
bus->SetSignal(gpio_rec.this_pin, ON);
|
|
|
|
usleep(sleep_time);
|
|
|
|
bus->Acquire();
|
|
// loop through all of the gpios
|
|
for (auto cur_gpio : loopback_conn_table) {
|
|
printf(".");
|
|
// all of the gpios should be high except for the test gpio and the connected gpio
|
|
LOGTRACE("calling bus->GetSignal(%d)", (int)cur_gpio.this_pin);
|
|
auto cur_val = bus->GetSignal(cur_gpio.this_pin);
|
|
LOGDEBUG("%d [%s] is %d", (int)cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin).c_str(), (int)cur_val);
|
|
|
|
if (cur_gpio.this_pin == gpio_rec.this_pin) {
|
|
if (cur_val != ON) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: Test commanded GPIO {} [{}] to be low, but it did not respond",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
} else if (cur_gpio.this_pin == gpio_rec.connected_pin) {
|
|
if (cur_val != ON) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: GPIO {} [{}] should be driven low, but {} [{}] did not affect it",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin), cur_gpio.connected_pin,
|
|
pin_name_lookup.at(cur_gpio.connected_pin)));
|
|
|
|
err_count++;
|
|
}
|
|
else{
|
|
loopback_adapter_missing = false;
|
|
}
|
|
} else {
|
|
if (cur_val != OFF) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: GPIO {} [{}] was incorrectly pulled low, when it shouldn't be",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ############################################
|
|
// set the transceivers to input
|
|
set_output_channel(-1);
|
|
|
|
usleep(sleep_time);
|
|
|
|
bus->Acquire();
|
|
// # loop through all of the gpios
|
|
for (auto cur_gpio : loopback_conn_table) {
|
|
printf(".");
|
|
// all of the gpios should be high except for the test gpio
|
|
LOGTRACE("calling bus->GetSignal(%d)", (int)cur_gpio.this_pin);
|
|
auto cur_val = bus->GetSignal(cur_gpio.this_pin);
|
|
LOGDEBUG("%d [%s] is %d", (int)cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin).c_str(), (int)cur_val);
|
|
|
|
if (cur_gpio.this_pin == gpio_rec.this_pin) {
|
|
if (cur_val != ON) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: Test commanded GPIO {} [{}] to be low, but it did not respond",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
} else {
|
|
if (cur_val != OFF) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: GPIO {} [{}] was incorrectly pulled low, when it shouldn't be",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the transceiver back to output
|
|
set_output_channel(gpio_rec.dir_ctrl_pin);
|
|
usleep(sleep_time);
|
|
|
|
// #############################################
|
|
// set the test gpio high
|
|
bus->SetMode(gpio_rec.this_pin, GPIO_OUTPUT);
|
|
bus->SetSignal(gpio_rec.this_pin, OFF);
|
|
|
|
usleep(sleep_time);
|
|
|
|
bus->Acquire();
|
|
// loop through all of the gpios
|
|
for (auto cur_gpio : loopback_conn_table) {
|
|
printf(".");
|
|
|
|
auto cur_val = bus->GetSignal(cur_gpio.this_pin);
|
|
LOGTRACE("%d [%s] is %d", (int)cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin).c_str(), (int)cur_val);
|
|
|
|
if (cur_gpio.this_pin == gpio_rec.this_pin) {
|
|
if (cur_val != OFF) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: Test commanded GPIO {} [{}] to be high, but it did not respond",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
} else {
|
|
if (cur_val != OFF) {
|
|
error_list.push_back(
|
|
fmt::format("Loopback test: GPIO {} [{}] was incorrectly pulled low, when it shouldn't be",
|
|
cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin)));
|
|
err_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
ScsiLoop_Cout::FinishTest(fmt::format("GPIO {:<3} [{}]", gpio_rec.this_pin, pin_name_lookup.at(gpio_rec.this_pin)),
|
|
err_count);
|
|
return err_count;
|
|
}
|
|
|
|
int ScsiLoop_GPIO::RunLoopbackTest(vector<string> &error_list)
|
|
{
|
|
int errors = 0;
|
|
bool loopback_adapter_missing = true;
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
loopback_setup();
|
|
|
|
for (auto cur_gpio : loopback_conn_table) {
|
|
ScsiLoop_Cout::StartTest(
|
|
fmt::format("GPIO {:<3}[{}]", cur_gpio.this_pin, pin_name_lookup.at(cur_gpio.this_pin).c_str()));
|
|
|
|
errors += test_gpio_pin(cur_gpio, error_list, loopback_adapter_missing);
|
|
}
|
|
|
|
if(loopback_adapter_missing){
|
|
error_list.push_back("All of the loop-backed signals failed. Is the loopback adapter missing? (A special cable is required to use scsiloop)");
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
void ScsiLoop_GPIO::dat_input_test_setup()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
|
|
for (loopback_connection cur_gpio : loopback_conn_table) {
|
|
if (cur_gpio.this_pin == -1) {
|
|
continue;
|
|
}
|
|
bus->PinConfig(cur_gpio.this_pin, GPIO_OUTPUT);
|
|
bus->PullConfig(cur_gpio.this_pin, GPIO_PULLNONE);
|
|
}
|
|
|
|
bus->PinConfig(local_pin_dt0, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt1, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt2, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt3, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt4, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt5, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt6, GPIO_INPUT);
|
|
bus->PinConfig(local_pin_dt7, GPIO_INPUT);
|
|
|
|
set_dtd_in();
|
|
set_tad_out();
|
|
set_ind_out();
|
|
}
|
|
|
|
void ScsiLoop_GPIO::dat_output_test_setup()
|
|
{
|
|
LOGTRACE("%s", __PRETTY_FUNCTION__);
|
|
|
|
for (loopback_connection cur_gpio : loopback_conn_table) {
|
|
if (cur_gpio.this_pin == -1) {
|
|
continue;
|
|
}
|
|
bus->PinConfig(cur_gpio.this_pin, GPIO_INPUT);
|
|
bus->PullConfig(cur_gpio.this_pin, GPIO_PULLNONE);
|
|
}
|
|
|
|
bus->PinConfig(local_pin_dt0, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt1, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt2, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt3, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt4, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt5, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt6, GPIO_OUTPUT);
|
|
bus->PinConfig(local_pin_dt7, GPIO_OUTPUT);
|
|
|
|
set_dtd_out();
|
|
set_tad_in();
|
|
set_ind_in();
|
|
}
|
|
|
|
void ScsiLoop_GPIO::set_dat_inputs_loop(uint8_t value)
|
|
{
|
|
bus->SetSignal(local_pin_ack, (value >> 0) & 0x1);
|
|
bus->SetSignal(local_pin_sel, (value >> 1) & 0x1);
|
|
bus->SetSignal(local_pin_atn, (value >> 2) & 0x1);
|
|
bus->SetSignal(local_pin_rst, (value >> 3) & 0x1);
|
|
bus->SetSignal(local_pin_cd, (value >> 4) & 0x1);
|
|
bus->SetSignal(local_pin_io, (value >> 5) & 0x1);
|
|
bus->SetSignal(local_pin_msg, (value >> 6) & 0x1);
|
|
bus->SetSignal(local_pin_req, (value >> 7) & 0x1);
|
|
}
|
|
|
|
uint8_t ScsiLoop_GPIO::get_dat_outputs_loop()
|
|
{
|
|
uint8_t value = 0;
|
|
value |= ((bus->GetSignal(local_pin_ack) & 0x1) << 0);
|
|
value |= ((bus->GetSignal(local_pin_sel) & 0x1) << 1);
|
|
value |= ((bus->GetSignal(local_pin_atn) & 0x1) << 2);
|
|
value |= ((bus->GetSignal(local_pin_rst) & 0x1) << 3);
|
|
value |= ((bus->GetSignal(local_pin_cd) & 0x1) << 4);
|
|
value |= ((bus->GetSignal(local_pin_io) & 0x1) << 5);
|
|
value |= ((bus->GetSignal(local_pin_msg) & 0x1) << 6);
|
|
value |= ((bus->GetSignal(local_pin_req) & 0x1) << 7);
|
|
return value;
|
|
}
|
|
|
|
int ScsiLoop_GPIO::RunDataInputTest(vector<string> &error_list)
|
|
{
|
|
int err_count = 0;
|
|
int delay_time_us = 1000;
|
|
dat_input_test_setup();
|
|
|
|
ScsiLoop_Cout::StartTest("data inputs ");
|
|
|
|
for (uint32_t val = 0; val < UINT8_MAX; val++) {
|
|
set_dat_inputs_loop(val);
|
|
usleep(delay_time_us);
|
|
|
|
bus->Acquire();
|
|
uint8_t read_val = bus->GetDAT();
|
|
|
|
if (read_val != (uint8_t)(val & 0xFF)) {
|
|
error_list.push_back(fmt::format("DAT Inputs: Expected value {} but got {}", val, read_val));
|
|
err_count++;
|
|
}
|
|
if ((val % 0x7) == 0) {
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
ScsiLoop_Cout::FinishTest("DAT Inputs", err_count);
|
|
|
|
set_dat_inputs_loop(0);
|
|
return err_count;
|
|
}
|
|
|
|
int ScsiLoop_GPIO::RunDataOutputTest(vector<string> &error_list)
|
|
{
|
|
int err_count = 0;
|
|
int delay_time_us = 1000;
|
|
dat_output_test_setup();
|
|
|
|
ScsiLoop_Cout::StartTest("data outputs ");
|
|
|
|
for (uint32_t val = 0; val < UINT8_MAX; val++) {
|
|
bus->SetDAT(val);
|
|
usleep(delay_time_us);
|
|
|
|
bus->Acquire();
|
|
uint8_t read_val = get_dat_outputs_loop();
|
|
|
|
if (read_val != (uint8_t)(val & 0xFF)) {
|
|
error_list.push_back(fmt::format("DAT Outputs: Expected value {} but got {}", val, read_val));
|
|
err_count++;
|
|
}
|
|
if ((val % 0x7) == 0) {
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
ScsiLoop_Cout::FinishTest("DAT Outputs", err_count);
|
|
|
|
return err_count;
|
|
} |