mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-21 23:29:39 +00:00
Initial merge of (incomplete) Banana Pi updates (#993)
This commit is contained in:
parent
a403ec3ded
commit
eb71c31cf1
34
cpp/Makefile
34
cpp/Makefile
@ -58,6 +58,7 @@ RASCTL = rasctl
|
||||
RASDUMP = rasdump
|
||||
SCSIMON = scsimon
|
||||
RASCSI_TEST = rascsi_test
|
||||
SCSILOOP = scsiloop
|
||||
|
||||
SYSTEMD_CONF = /etc/systemd/system/rascsi.service
|
||||
RSYSLOG_CONF = /etc/rsyslog.d/rascsi.conf
|
||||
@ -77,7 +78,8 @@ BIN_ALL = \
|
||||
$(BINDIR)/$(RASCSI) \
|
||||
$(BINDIR)/$(RASCTL) \
|
||||
$(BINDIR)/$(SCSIMON) \
|
||||
$(BINDIR)/$(RASDUMP)
|
||||
$(BINDIR)/$(RASDUMP) \
|
||||
$(BINDIR)/$(SCSILOOP)
|
||||
|
||||
SRC_PROTOC = rascsi_interface.proto
|
||||
|
||||
@ -114,8 +116,16 @@ SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp')
|
||||
SRC_RASCSI_TEST += $(shell find ./rasdump -name '*.cpp')
|
||||
SRC_RASCSI_TEST += $(shell find ./monitor -name '*.cpp')
|
||||
|
||||
vpath %.h ./ ./shared ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump
|
||||
vpath %.cpp ./ ./shared ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump ./test
|
||||
SRC_SCSILOOP = scsiloop.cpp
|
||||
SRC_SCSILOOP += $(shell find ./scsiloop -name '*.cpp')
|
||||
SRC_SCSILOOP += $(shell find ./hal -name '*.cpp')
|
||||
|
||||
vpath %.h ./ ./shared ./controllers ./devices ./monitor ./hal \
|
||||
./hal/boards ./hal/pi_defs ./rascsi ./rasctl ./rasdump \
|
||||
./scsiloop
|
||||
vpath %.cpp ./ ./shared ./controllers ./devices ./monitor ./hal \
|
||||
./hal/boards ./hal/pi_defs ./rascsi ./rasctl ./rasdump \
|
||||
./scsiloop ./test
|
||||
vpath %.o ./$(OBJDIR)
|
||||
vpath ./$(BINDIR)
|
||||
|
||||
@ -127,16 +137,21 @@ OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
|
||||
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
|
||||
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
||||
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.cpp=%.o)))
|
||||
OBJ_SCSILOOP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSILOOP:%.cpp=%.o)))
|
||||
OBJ_SHARED := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SHARED:%.cpp=%.o)))
|
||||
OBJ_PROTOBUF := $(addprefix $(OBJDIR)/,$(notdir $(SRC_PROTOBUF:%.cpp=%.o)))
|
||||
OBJ_GENERATED := $(addprefix $(OBJDIR)/,$(notdir $(SRC_GENERATED:%.cpp=%.o)))
|
||||
|
||||
GENERATED_DIR := generated
|
||||
|
||||
# For the unit tests, the following functions will be "wrapped" by the linker, meaning the
|
||||
# __wrap_xxxx() function will be called instead of the real function. These linker flags
|
||||
# should only be used for testing purposes!
|
||||
TEST_WRAPS = -Wl,--wrap=fopen64
|
||||
|
||||
# The following will include all of the auto-generated dependency files (*.d)
|
||||
# if they exist. This will trigger a rebuild of a source file if a header changes
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SCSIMON) $(OBJ_SHARED) $(OBJ_PROTOBUF) $(OBJ_RASCSI_TEST))
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SCSIMON) $(OBJ_SHARED) $(OBJ_PROTOBUF) $(OBJ_RASCSI_TEST) $(OBJ_SCSILOOP))
|
||||
-include $(ALL_DEPS)
|
||||
|
||||
$(OBJDIR) $(BINDIR):
|
||||
@ -179,7 +194,7 @@ lcov: test
|
||||
lcov -q -c -d . --include '*/cpp/*' -o $(COVERAGE_FILE) --exclude '*/test/*' --exclude '*/interfaces/*' --exclude '*/rascsi_interface.pb*'
|
||||
genhtml -q -o $(COVERAGE_DIR) --legend $(COVERAGE_FILE)
|
||||
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt $(DOC_DIR)/rasdump_man_page.txt
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt $(DOC_DIR)/rasdump_man_page.txt $(DOC_DIR)/scsiloop_man_page.txt
|
||||
|
||||
$(SRC_RASCSI_CORE) $(SRC_RASCTL_CORE) : $(OBJ_GENERATED)
|
||||
|
||||
@ -196,16 +211,19 @@ $(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) $(OBJ_SHARED) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) $(OBJ_SHARED)
|
||||
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_GENERATED) $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_RASCTL_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) $(OBJ_GENERATED) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) $(OBJ_GENERATED) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
$(CXX) $(CXXFLAGS) $(TEST_WRAPS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) $(OBJ_GENERATED) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
|
||||
$(BINDIR)/$(SCSILOOP): $(OBJ_SHARED) $(OBJ_SCSILOOP) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SHARED) $(OBJ_SCSILOOP)
|
||||
|
||||
# Phony rules for building individual utilities
|
||||
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SCSIMON) $(RASCSI_TEST)
|
||||
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SCSIMON) $(RASCSI_TEST) $(SCSILOOP)
|
||||
$(RASCSI) : $(BINDIR)/$(RASCSI)
|
||||
$(RASCTL) : $(BINDIR)/$(RASCTL)
|
||||
$(RASDUMP) : $(BINDIR)/$(RASDUMP)
|
||||
$(SCSIMON) : $(BINDIR)/$(SCSIMON)
|
||||
$(RASCSI_TEST): $(BINDIR)/$(RASCSI_TEST)
|
||||
$(SCSILOOP) : $(BINDIR)/$(SCSILOOP)
|
||||
|
||||
## clean : Remove all of the object files, intermediate
|
||||
## compiler files and executable files
|
||||
@ -230,10 +248,12 @@ install: \
|
||||
$(MAN_PAGE_DIR)/rascsi.1 \
|
||||
$(MAN_PAGE_DIR)/rasctl.1 \
|
||||
$(MAN_PAGE_DIR)/scsimon.1 \
|
||||
$(MAN_PAGE_DIR)/scsiloop.1 \
|
||||
$(MAN_PAGE_DIR)/rasdump.1 \
|
||||
$(USR_LOCAL_BIN)/$(RASCTL) \
|
||||
$(USR_LOCAL_BIN)/$(RASCSI) \
|
||||
$(USR_LOCAL_BIN)/$(SCSIMON) \
|
||||
$(USR_LOCAL_BIN)/$(SCSILOOP) \
|
||||
$(USR_LOCAL_BIN)/$(RASDUMP) \
|
||||
$(SYSTEMD_CONF) \
|
||||
$(RSYSLOG_CONF) \
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "devices/primary_device.h"
|
||||
#include "abstract_controller.h"
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
void AbstractController::AllocateCmd(size_t size)
|
||||
{
|
||||
if (size > ctrl.cmd.size()) {
|
||||
@ -52,7 +54,7 @@ shared_ptr<PrimaryDevice> AbstractController::GetDeviceForLun(int lun) const {
|
||||
|
||||
void AbstractController::Reset()
|
||||
{
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
SetPhase(phase_t::busfree);
|
||||
|
||||
ctrl.status = status::GOOD;
|
||||
ctrl.message = 0x00;
|
||||
@ -70,35 +72,35 @@ void AbstractController::Reset()
|
||||
void AbstractController::ProcessPhase()
|
||||
{
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::busfree:
|
||||
case phase_t::busfree:
|
||||
BusFree();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::selection:
|
||||
case phase_t::selection:
|
||||
Selection();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
case phase_t::dataout:
|
||||
DataOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::datain:
|
||||
case phase_t::datain:
|
||||
DataIn();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::command:
|
||||
case phase_t::command:
|
||||
Command();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::status:
|
||||
case phase_t::status:
|
||||
Status();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
case phase_t::msgout:
|
||||
MsgOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgin:
|
||||
case phase_t::msgin:
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include "hal/bus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BUS;
|
||||
class AbstractController;
|
||||
class PrimaryDevice;
|
||||
|
||||
|
@ -11,9 +11,11 @@
|
||||
|
||||
#include "shared/scsi.h"
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
class PhaseHandler
|
||||
{
|
||||
BUS::phase_t phase = BUS::phase_t::busfree;
|
||||
phase_t phase = phase_t::busfree;
|
||||
|
||||
public:
|
||||
|
||||
@ -29,18 +31,18 @@ public:
|
||||
virtual void MsgIn() = 0;
|
||||
virtual void MsgOut() = 0;
|
||||
|
||||
virtual BUS::phase_t Process(int) = 0;
|
||||
virtual phase_t Process(int) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
BUS::phase_t GetPhase() const { return phase; }
|
||||
void SetPhase(BUS::phase_t p) { phase = p; }
|
||||
bool IsSelection() const { return phase == BUS::phase_t::selection; }
|
||||
bool IsBusFree() const { return phase == BUS::phase_t::busfree; }
|
||||
bool IsCommand() const { return phase == BUS::phase_t::command; }
|
||||
bool IsStatus() const { return phase == BUS::phase_t::status; }
|
||||
bool IsDataIn() const { return phase == BUS::phase_t::datain; }
|
||||
bool IsDataOut() const { return phase == BUS::phase_t::dataout; }
|
||||
bool IsMsgIn() const { return phase == BUS::phase_t::msgin; }
|
||||
bool IsMsgOut() const { return phase == BUS::phase_t::msgout; }
|
||||
phase_t GetPhase() const { return phase; }
|
||||
void SetPhase(phase_t p) { phase = p; }
|
||||
bool IsSelection() const { return phase == phase_t::selection; }
|
||||
bool IsBusFree() const { return phase == phase_t::busfree; }
|
||||
bool IsCommand() const { return phase == phase_t::command; }
|
||||
bool IsStatus() const { return phase == phase_t::status; }
|
||||
bool IsDataIn() const { return phase == phase_t::datain; }
|
||||
bool IsDataOut() const { return phase == phase_t::dataout; }
|
||||
bool IsMsgIn() const { return phase == phase_t::msgin; }
|
||||
bool IsMsgOut() const { return phase == phase_t::msgout; }
|
||||
};
|
||||
|
@ -52,7 +52,7 @@ void ScsiController::Reset()
|
||||
SetByteTransfer(false);
|
||||
}
|
||||
|
||||
BUS::phase_t ScsiController::Process(int id)
|
||||
phase_t ScsiController::Process(int id)
|
||||
{
|
||||
GetBus().Acquire();
|
||||
|
||||
@ -89,7 +89,7 @@ void ScsiController::BusFree()
|
||||
if (!IsBusFree()) {
|
||||
logger.Trace("Bus free phase");
|
||||
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
SetPhase(phase_t::busfree);
|
||||
|
||||
GetBus().SetREQ(false);
|
||||
GetBus().SetMSG(false);
|
||||
@ -165,7 +165,7 @@ void ScsiController::Selection()
|
||||
|
||||
logger.Trace("Selection phase");
|
||||
|
||||
SetPhase(BUS::phase_t::selection);
|
||||
SetPhase(phase_t::selection);
|
||||
|
||||
// Raise BSY and respond
|
||||
GetBus().SetBSY(true);
|
||||
@ -188,7 +188,7 @@ void ScsiController::Command()
|
||||
if (!IsCommand()) {
|
||||
logger.Trace("Command phase");
|
||||
|
||||
SetPhase(BUS::phase_t::command);
|
||||
SetPhase(phase_t::command);
|
||||
|
||||
GetBus().SetMSG(false);
|
||||
GetBus().SetCD(true);
|
||||
@ -307,7 +307,7 @@ void ScsiController::Status()
|
||||
s << "Status Phase, status is $" << setfill('0') << setw(2) << hex << static_cast<int>(GetStatus());
|
||||
logger.Trace(s.str());
|
||||
|
||||
SetPhase(BUS::phase_t::status);
|
||||
SetPhase(phase_t::status);
|
||||
|
||||
// Signal line operated by the target
|
||||
GetBus().SetMSG(false);
|
||||
@ -331,7 +331,7 @@ void ScsiController::MsgIn()
|
||||
if (!IsMsgIn()) {
|
||||
logger.Trace("Message In phase");
|
||||
|
||||
SetPhase(BUS::phase_t::msgin);
|
||||
SetPhase(phase_t::msgin);
|
||||
|
||||
GetBus().SetMSG(true);
|
||||
GetBus().SetCD(true);
|
||||
@ -356,7 +356,7 @@ void ScsiController::MsgOut()
|
||||
scsi.msb = {};
|
||||
}
|
||||
|
||||
SetPhase(BUS::phase_t::msgout);
|
||||
SetPhase(phase_t::msgout);
|
||||
|
||||
GetBus().SetMSG(true);
|
||||
GetBus().SetCD(true);
|
||||
@ -389,7 +389,7 @@ void ScsiController::DataIn()
|
||||
|
||||
logger.Trace("Entering Data In phase");
|
||||
|
||||
SetPhase(BUS::phase_t::datain);
|
||||
SetPhase(phase_t::datain);
|
||||
|
||||
GetBus().SetMSG(false);
|
||||
GetBus().SetCD(false);
|
||||
@ -419,7 +419,7 @@ void ScsiController::DataOut()
|
||||
|
||||
logger.Trace("Data Out phase");
|
||||
|
||||
SetPhase(BUS::phase_t::dataout);
|
||||
SetPhase(phase_t::dataout);
|
||||
|
||||
// Signal line operated by the target
|
||||
GetBus().SetMSG(false);
|
||||
@ -537,7 +537,7 @@ void ScsiController::Send()
|
||||
logger.Trace("Moving to next phase: " + string(BUS::GetPhaseStrRaw(GetPhase())));
|
||||
switch (GetPhase()) {
|
||||
// Message in phase
|
||||
case BUS::phase_t::msgin:
|
||||
case phase_t::msgin:
|
||||
// Completed sending response to extended message of IDENTIFY message
|
||||
if (scsi.atnmsg) {
|
||||
// flag off
|
||||
@ -552,13 +552,13 @@ void ScsiController::Send()
|
||||
break;
|
||||
|
||||
// Data-in Phase
|
||||
case BUS::phase_t::datain:
|
||||
case phase_t::datain:
|
||||
// status phase
|
||||
Status();
|
||||
break;
|
||||
|
||||
// status phase
|
||||
case BUS::phase_t::status:
|
||||
case phase_t::status:
|
||||
// Message in phase
|
||||
SetLength(1);
|
||||
SetBlocks(1);
|
||||
@ -605,7 +605,7 @@ void ScsiController::Receive()
|
||||
// Processing after receiving data (by phase)
|
||||
logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase())));
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::dataout:
|
||||
case phase_t::dataout:
|
||||
if (GetBlocks() == 0) {
|
||||
// End with this buffer
|
||||
result = XferOut(false);
|
||||
@ -615,7 +615,7 @@ void ScsiController::Receive()
|
||||
}
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
case phase_t::msgout:
|
||||
SetMessage(GetBuffer()[0]);
|
||||
if (!XferMsg(GetMessage())) {
|
||||
// Immediately free the bus if message output fails
|
||||
@ -646,15 +646,15 @@ void ScsiController::Receive()
|
||||
|
||||
// Move to next phase
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::command:
|
||||
case phase_t::command:
|
||||
ProcessCommand();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
case phase_t::msgout:
|
||||
ProcessMessage();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
case phase_t::dataout:
|
||||
// Block-oriented data have been handled above
|
||||
DataOutNonBlockOriented();
|
||||
|
||||
@ -694,11 +694,11 @@ void ScsiController::ReceiveBytes()
|
||||
// Processing after receiving data (by phase)
|
||||
logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase())));
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::dataout:
|
||||
case phase_t::dataout:
|
||||
result = XferOut(false);
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
case phase_t::msgout:
|
||||
SetMessage(GetBuffer()[0]);
|
||||
if (!XferMsg(GetMessage())) {
|
||||
// Immediately free the bus if message output fails
|
||||
@ -722,15 +722,15 @@ void ScsiController::ReceiveBytes()
|
||||
|
||||
// Move to next phase
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::command:
|
||||
case phase_t::command:
|
||||
ProcessCommand();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
case phase_t::msgout:
|
||||
ProcessMessage();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
case phase_t::dataout:
|
||||
Status();
|
||||
break;
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
|
||||
void Reset() override;
|
||||
|
||||
BUS::phase_t Process(int) override;
|
||||
phase_t Process(int) override;
|
||||
|
||||
int GetEffectiveLun() const override;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -30,7 +31,7 @@ int BUS::GetCommandByteCount(uint8_t opcode)
|
||||
// Phase Acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BUS::phase_t BUS::GetPhase()
|
||||
phase_t BUS::GetPhase()
|
||||
{
|
||||
// Selection Phase
|
||||
if (GetSEL()) {
|
||||
@ -66,7 +67,7 @@ const char* BUS::GetPhaseStrRaw(phase_t current_phase) {
|
||||
// This determines the phase based upon the Msg, C/D and I/O signals.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const array<BUS::phase_t, 8> BUS::phase_table = {
|
||||
const array<phase_t, 8> BUS::phase_table = {
|
||||
// | MSG|C/D|I/O |
|
||||
phase_t::dataout, // | 0 | 0 | 0 |
|
||||
phase_t::datain, // | 0 | 0 | 1 |
|
||||
@ -83,7 +84,7 @@ const array<BUS::phase_t, 8> BUS::phase_table = {
|
||||
// Phase string to phase mapping
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const unordered_map<BUS::phase_t, const char*> BUS::phase_str_mapping = {
|
||||
const unordered_map<phase_t, const char*> BUS::phase_str_mapping = {
|
||||
{ phase_t::busfree, "busfree" },
|
||||
{ phase_t::arbitration, "arbitration" },
|
||||
{ phase_t::selection, "selection" },
|
||||
|
119
cpp/hal/bus.h
119
cpp/hal/bus.h
@ -9,18 +9,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample.h"
|
||||
#include "hal/pin_control.h"
|
||||
#include "shared/config.h"
|
||||
#include "shared/scsi.h"
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
using namespace std;
|
||||
|
||||
class BUS
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (bus control timing)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
// SCSI Bus timings taken from:
|
||||
// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html
|
||||
const static int SCSI_DELAY_ARBITRATION_DELAY_NS = 2400;
|
||||
const static int SCSI_DELAY_ASSERTION_PERIOD_NS = 90;
|
||||
const static int SCSI_DELAY_BUS_CLEAR_DELAY_NS = 800;
|
||||
const static int SCSI_DELAY_BUS_FREE_DELAY_NS = 800;
|
||||
const static int SCSI_DELAY_BUS_SET_DELAY_NS = 1800;
|
||||
const static int SCSI_DELAY_BUS_SETTLE_DELAY_NS = 400;
|
||||
const static int SCSI_DELAY_CABLE_SKEW_DELAY_NS = 10;
|
||||
const static int SCSI_DELAY_DATA_RELEASE_DELAY_NS = 400;
|
||||
const static int SCSI_DELAY_DESKEW_DELAY_NS = 45;
|
||||
const static int SCSI_DELAY_DISCONNECTION_DELAY_US = 200;
|
||||
const static int SCSI_DELAY_HOLD_TIME_NS = 45;
|
||||
const static int SCSI_DELAY_NEGATION_PERIOD_NS = 90;
|
||||
const static int SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S = 10; // (recommended)
|
||||
const static int SCSI_DELAY_RESET_TO_SELECTION_TIME_US = 250 * 1000; // (recommended)
|
||||
const static int SCSI_DELAY_RESET_HOLD_TIME_US = 25;
|
||||
const static int SCSI_DELAY_SELECTION_ABORT_TIME_US = 200;
|
||||
const static int SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS = 250 * 1000; // (recommended)
|
||||
const static int SCSI_DELAY_FAST_ASSERTION_PERIOD_NS = 30;
|
||||
const static int SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS = 5;
|
||||
const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20;
|
||||
const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10;
|
||||
const static int SCSI_DELAY_FAST_NEGATION_PERIOD_NS = 30;
|
||||
|
||||
// The DaynaPort SCSI Link do a short delay in the middle of transfering
|
||||
// a packet. This is the number of uS that will be delayed between the
|
||||
// header and the actual data.
|
||||
const static int SCSI_DELAY_SEND_DATA_DAYNAPORT_US = 100;
|
||||
|
||||
|
||||
class bus_exception : public runtime_error
|
||||
{
|
||||
public:
|
||||
using runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
class BUS : public PinControl
|
||||
{
|
||||
public:
|
||||
// Operation modes definition
|
||||
enum class mode_e {
|
||||
TARGET = 0,
|
||||
@ -28,24 +72,6 @@ public:
|
||||
MONITOR = 2,
|
||||
};
|
||||
|
||||
// Phase definitions
|
||||
enum class phase_t : int {
|
||||
busfree,
|
||||
arbitration,
|
||||
selection,
|
||||
reselection,
|
||||
command,
|
||||
datain,
|
||||
dataout,
|
||||
status,
|
||||
msgin,
|
||||
msgout,
|
||||
reserved
|
||||
};
|
||||
|
||||
BUS() = default;
|
||||
virtual ~BUS() = default;
|
||||
|
||||
static int GetCommandByteCount(uint8_t);
|
||||
|
||||
virtual bool Init(mode_e mode) = 0;
|
||||
@ -59,57 +85,20 @@ public:
|
||||
}
|
||||
|
||||
// Get the string phase name, based upon the raw data
|
||||
static const char* GetPhaseStrRaw(phase_t current_phase);
|
||||
|
||||
// Extract as specific pin field from a raw data capture
|
||||
static inline uint32_t GetPinRaw(uint32_t raw_data, uint32_t pin_num)
|
||||
{
|
||||
return ((raw_data >> pin_num) & 1);
|
||||
}
|
||||
|
||||
virtual bool GetBSY() const = 0;
|
||||
virtual void SetBSY(bool ast) = 0;
|
||||
|
||||
virtual bool GetSEL() const = 0;
|
||||
virtual void SetSEL(bool ast) = 0;
|
||||
|
||||
virtual bool GetATN() const = 0;
|
||||
virtual void SetATN(bool ast) = 0;
|
||||
|
||||
virtual bool GetACK() const = 0;
|
||||
virtual void SetACK(bool ast) = 0;
|
||||
|
||||
virtual bool GetRST() const = 0;
|
||||
virtual void SetRST(bool ast) = 0;
|
||||
|
||||
virtual bool GetMSG() const = 0;
|
||||
virtual void SetMSG(bool ast) = 0;
|
||||
|
||||
virtual bool GetCD() const = 0;
|
||||
virtual void SetCD(bool ast) = 0;
|
||||
|
||||
virtual bool GetIO() = 0;
|
||||
virtual void SetIO(bool ast) = 0;
|
||||
|
||||
virtual bool GetREQ() const = 0;
|
||||
virtual void SetREQ(bool ast) = 0;
|
||||
|
||||
virtual uint8_t GetDAT() = 0;
|
||||
virtual void SetDAT(uint8_t dat) = 0;
|
||||
virtual bool GetDP() const = 0; // Get parity signal
|
||||
static const char *GetPhaseStrRaw(phase_t current_phase);
|
||||
virtual int GetMode(int pin) = 0;
|
||||
|
||||
virtual uint32_t Acquire() = 0;
|
||||
virtual int CommandHandShake(vector<uint8_t>&) = 0;
|
||||
virtual unique_ptr<DataSample> GetSample(uint64_t timestamp = 0) = 0;
|
||||
virtual int CommandHandShake(vector<uint8_t> &) = 0;
|
||||
virtual int ReceiveHandShake(uint8_t *buf, int count) = 0;
|
||||
virtual int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) = 0;
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal event polling
|
||||
virtual bool PollSelectEvent() = 0;
|
||||
|
||||
// Clear SEL signal event
|
||||
virtual void ClearSelectEvent() = 0;
|
||||
#endif
|
||||
|
||||
virtual bool GetSignal(int pin) const = 0;
|
||||
// Get SCSI input signal value
|
||||
@ -117,7 +106,7 @@ public:
|
||||
// Set SCSI output signal value
|
||||
static const int SEND_NO_DELAY = -1;
|
||||
// Passed into SendHandShake when we don't want to delay
|
||||
private:
|
||||
private:
|
||||
static const array<phase_t, 8> phase_table;
|
||||
|
||||
static const unordered_map<phase_t, const char *> phase_str_mapping;
|
||||
|
87
cpp/hal/connection_type/connection_aibom.h
Normal file
87
cpp/hal/connection_type/connection_aibom.h
Normal file
@ -0,0 +1,87 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/pi_defs/bpi-m2p.h"
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI Adapter Aibom version
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "AIBOM PRODUCTS version"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 2; // SCSI positive logic specification
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN OFF // DATA SIGNAL INPUT
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 17; // ENABLE
|
||||
const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 18; // DATA DIRECTION
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 6; // Data 0
|
||||
const static int PIN_DT1 = 12; // Data 1
|
||||
const static int PIN_DT2 = 13; // Data 2
|
||||
const static int PIN_DT3 = 16; // Data 3
|
||||
const static int PIN_DT4 = 19; // Data 4
|
||||
const static int PIN_DT5 = 20; // Data 5
|
||||
const static int PIN_DT6 = 26; // Data 6
|
||||
const static int PIN_DT7 = 21; // Data 7
|
||||
const static int PIN_DP = 5; // Data parity
|
||||
const static int PIN_ATN = 22; // ATN
|
||||
const static int PIN_RST = 25; // RST
|
||||
const static int PIN_ACK = 10; // ACK
|
||||
const static int PIN_REQ = 7; // REQ
|
||||
const static int PIN_MSG = 9; // MSG
|
||||
const static int PIN_CD = 11; // CD
|
||||
const static int PIN_IO = 23; // IO
|
||||
const static int PIN_BSY = 24; // BSY
|
||||
const static int PIN_SEL = 8; // SEL
|
||||
|
||||
// Warning: The Allwinner/Banana Pi GPIO numbers DO NOT correspond to
|
||||
// the Raspberry Pi GPIO numbers.
|
||||
// For example, Pin 7 is GPIO4 on a Raspberry Pi. Its GPIO 6 on a Banana Pi
|
||||
// For Banana Pi, the pins are specified by physical pin number, NOT GPIO number
|
||||
// (The Macro's convert the pin number to logical BPi GPIO number)
|
||||
const static int BPI_PIN_ACT = BPI_M2P_07; // ACTIVE
|
||||
const static int BPI_PIN_ENB = BPI_M2P_11; // ENABLE
|
||||
const static int BPI_PIN_IND = BPI_M2P_13; // INITIATOR CTRL DIRECTION
|
||||
const static int BPI_PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int BPI_PIN_DTD = BPI_M2P_12; // DATA DIRECTION
|
||||
|
||||
const static int BPI_PIN_DT0 = BPI_M2P_31; // Data 0
|
||||
const static int BPI_PIN_DT1 = BPI_M2P_32; // Data 1
|
||||
const static int BPI_PIN_DT2 = BPI_M2P_33; // Data 2
|
||||
const static int BPI_PIN_DT3 = BPI_M2P_36; // Data 3
|
||||
const static int BPI_PIN_DT4 = BPI_M2P_35; // Data 4
|
||||
const static int BPI_PIN_DT5 = BPI_M2P_38; // Data 5
|
||||
const static int BPI_PIN_DT6 = BPI_M2P_37; // Data 6
|
||||
const static int BPI_PIN_DT7 = BPI_M2P_40; // Data 7
|
||||
const static int BPI_PIN_DP = BPI_M2P_29; // Data parity
|
||||
const static int BPI_PIN_ATN = BPI_M2P_15; // ATN
|
||||
const static int BPI_PIN_RST = BPI_M2P_22; // RST
|
||||
const static int BPI_PIN_ACK = BPI_M2P_19; // ACK
|
||||
const static int BPI_PIN_REQ = BPI_M2P_26; // REQ
|
||||
const static int BPI_PIN_MSG = BPI_M2P_21; // MSG
|
||||
const static int BPI_PIN_CD = BPI_M2P_23; // CD
|
||||
const static int BPI_PIN_IO = BPI_M2P_16; // IO
|
||||
const static int BPI_PIN_BSY = BPI_M2P_18; // BSY
|
||||
const static int BPI_PIN_SEL = BPI_M2P_24; // SEL
|
87
cpp/hal/connection_type/connection_fullspec.h
Normal file
87
cpp/hal/connection_type/connection_fullspec.h
Normal file
@ -0,0 +1,87 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/pi_defs/bpi-m2p.h"
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI standard (SCSI logic, standard pin assignment)
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "FULLSPEC"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 5; // ENABLE
|
||||
const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = 7; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 8; // DATA DIRECTION
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 10; // Data 0
|
||||
const static int PIN_DT1 = 11; // Data 1
|
||||
const static int PIN_DT2 = 12; // Data 2
|
||||
const static int PIN_DT3 = 13; // Data 3
|
||||
const static int PIN_DT4 = 14; // Data 4
|
||||
const static int PIN_DT5 = 15; // Data 5
|
||||
const static int PIN_DT6 = 16; // Data 6
|
||||
const static int PIN_DT7 = 17; // Data 7
|
||||
const static int PIN_DP = 18; // Data parity
|
||||
const static int PIN_ATN = 19; // ATN
|
||||
const static int PIN_RST = 20; // RST
|
||||
const static int PIN_ACK = 21; // ACK
|
||||
const static int PIN_REQ = 22; // REQ
|
||||
const static int PIN_MSG = 23; // MSG
|
||||
const static int PIN_CD = 24; // CD
|
||||
const static int PIN_IO = 25; // IO
|
||||
const static int PIN_BSY = 26; // BSY
|
||||
const static int PIN_SEL = 27; // SEL
|
||||
|
||||
// Warning: The Allwinner/Banana Pi GPIO numbers DO NOT correspond to
|
||||
// the Raspberry Pi GPIO numbers.
|
||||
// For example, Pin 7 is GPIO4 on a Raspberry Pi. Its GPIO 6 on a Banana Pi
|
||||
// For Banana Pi, the pins are specified by physical pin number, NOT GPIO number
|
||||
// (The Macro's convert the pin number to logical BPi GPIO number)
|
||||
const static int BPI_PIN_ACT = BPI_M2P_07; // ACTIVE
|
||||
const static int BPI_PIN_ENB = BPI_M2P_29; // ENABLE
|
||||
const static int BPI_PIN_IND = BPI_M2P_31; // INITIATOR CTRL DIRECTION
|
||||
const static int BPI_PIN_TAD = BPI_M2P_26; // TARGET CTRL DIRECTION
|
||||
const static int BPI_PIN_DTD = BPI_M2P_24; // DATA DIRECTION
|
||||
|
||||
const static int BPI_PIN_DT0 = BPI_M2P_19; // Data 0
|
||||
const static int BPI_PIN_DT1 = BPI_M2P_23; // Data 1
|
||||
const static int BPI_PIN_DT2 = BPI_M2P_32; // Data 2
|
||||
const static int BPI_PIN_DT3 = BPI_M2P_33; // Data 3
|
||||
const static int BPI_PIN_DT4 = BPI_M2P_08; // Data 4
|
||||
const static int BPI_PIN_DT5 = BPI_M2P_10; // Data 5
|
||||
const static int BPI_PIN_DT6 = BPI_M2P_36; // Data 6
|
||||
const static int BPI_PIN_DT7 = BPI_M2P_11; // Data 7
|
||||
const static int BPI_PIN_DP = BPI_M2P_12; // Data parity
|
||||
const static int BPI_PIN_ATN = BPI_M2P_35; // ATN
|
||||
const static int BPI_PIN_RST = BPI_M2P_38; // RST
|
||||
const static int BPI_PIN_ACK = BPI_M2P_40; // ACK
|
||||
const static int BPI_PIN_REQ = BPI_M2P_15; // REQ
|
||||
const static int BPI_PIN_MSG = BPI_M2P_16; // MSG
|
||||
const static int BPI_PIN_CD = BPI_M2P_18; // CD
|
||||
const static int BPI_PIN_IO = BPI_M2P_22; // IO
|
||||
const static int BPI_PIN_BSY = BPI_M2P_37; // BSY
|
||||
const static int BPI_PIN_SEL = BPI_M2P_13; // SEL
|
87
cpp/hal/connection_type/connection_gamernium.h
Normal file
87
cpp/hal/connection_type/connection_gamernium.h
Normal file
@ -0,0 +1,87 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/pi_defs/bpi-m2p.h"
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI Adapter GAMERnium.com version
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "GAMERnium.com version"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 14; // ACTIVE
|
||||
const static int PIN_ENB = 6; // ENABLE
|
||||
const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = 8; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 5; // DATA DIRECTION
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 21; // Data 0
|
||||
const static int PIN_DT1 = 26; // Data 1
|
||||
const static int PIN_DT2 = 20; // Data 2
|
||||
const static int PIN_DT3 = 19; // Data 3
|
||||
const static int PIN_DT4 = 16; // Data 4
|
||||
const static int PIN_DT5 = 13; // Data 5
|
||||
const static int PIN_DT6 = 12; // Data 6
|
||||
const static int PIN_DT7 = 11; // Data 7
|
||||
const static int PIN_DP = 25; // Data parity
|
||||
const static int PIN_ATN = 10; // ATN
|
||||
const static int PIN_RST = 22; // RST
|
||||
const static int PIN_ACK = 24; // ACK
|
||||
const static int PIN_REQ = 15; // REQ
|
||||
const static int PIN_MSG = 17; // MSG
|
||||
const static int PIN_CD = 18; // CD
|
||||
const static int PIN_IO = 4; // IO
|
||||
const static int PIN_BSY = 27; // BSY
|
||||
const static int PIN_SEL = 23; // SEL
|
||||
|
||||
// Warning: The Allwinner/Banana Pi GPIO numbers DO NOT correspond to
|
||||
// the Raspberry Pi GPIO numbers.
|
||||
// For example, Pin 7 is GPIO4 on a Raspberry Pi. Its GPIO 6 on a Banana Pi
|
||||
// For Banana Pi, the pins are specified by physical pin number, NOT GPIO number
|
||||
// (The Macro's convert the pin number to logical BPi GPIO number)
|
||||
const static int BPI_PIN_ACT = BPI_M2P_08; // ACTIVE
|
||||
const static int BPI_PIN_ENB = BPI_M2P_31; // ENABLE
|
||||
const static int BPI_PIN_IND = BPI_M2P_04; // INITIATOR CTRL DIRECTION
|
||||
const static int BPI_PIN_TAD = BPI_M2P_24; // TARGET CTRL DIRECTION
|
||||
const static int BPI_PIN_DTD = BPI_M2P_29; // DATA DIRECTION
|
||||
|
||||
const static int BPI_PIN_DT0 = BPI_M2P_40; // Data 0
|
||||
const static int BPI_PIN_DT1 = BPI_M2P_37; // Data 1
|
||||
const static int BPI_PIN_DT2 = BPI_M2P_38; // Data 2
|
||||
const static int BPI_PIN_DT3 = BPI_M2P_35; // Data 3
|
||||
const static int BPI_PIN_DT4 = BPI_M2P_36; // Data 4
|
||||
const static int BPI_PIN_DT5 = BPI_M2P_33; // Data 5
|
||||
const static int BPI_PIN_DT6 = BPI_M2P_32; // Data 6
|
||||
const static int BPI_PIN_DT7 = BPI_M2P_23; // Data 7
|
||||
const static int BPI_PIN_DP = BPI_M2P_22; // Data parity
|
||||
const static int BPI_PIN_ATN = BPI_M2P_19; // ATN
|
||||
const static int BPI_PIN_RST = BPI_M2P_15; // RST
|
||||
const static int BPI_PIN_ACK = BPI_M2P_18; // ACK
|
||||
const static int BPI_PIN_REQ = BPI_M2P_10; // REQ
|
||||
const static int BPI_PIN_MSG = BPI_M2P_11; // MSG
|
||||
const static int BPI_PIN_CD = BPI_M2P_12; // CD
|
||||
const static int BPI_PIN_IO = BPI_M2P_07; // IO
|
||||
const static int BPI_PIN_BSY = BPI_M2P_13; // BSY
|
||||
const static int BPI_PIN_SEL = BPI_M2P_16; // SEL
|
87
cpp/hal/connection_type/connection_standard.h
Normal file
87
cpp/hal/connection_type/connection_standard.h
Normal file
@ -0,0 +1,87 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/pi_defs/bpi-m2p.h"
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI standard (SCSI logic, standard pin assignment)
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "STANDARD"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 5; // ENABLE
|
||||
const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = -1; // DATA DIRECTION
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 10; // Data 0
|
||||
const static int PIN_DT1 = 11; // Data 1
|
||||
const static int PIN_DT2 = 12; // Data 2
|
||||
const static int PIN_DT3 = 13; // Data 3
|
||||
const static int PIN_DT4 = 14; // Data 4
|
||||
const static int PIN_DT5 = 15; // Data 5
|
||||
const static int PIN_DT6 = 16; // Data 6
|
||||
const static int PIN_DT7 = 17; // Data 7
|
||||
const static int PIN_DP = 18; // Data parity
|
||||
const static int PIN_ATN = 19; // ATN
|
||||
const static int PIN_RST = 20; // RST
|
||||
const static int PIN_ACK = 21; // ACK
|
||||
const static int PIN_REQ = 22; // REQ
|
||||
const static int PIN_MSG = 23; // MSG
|
||||
const static int PIN_CD = 24; // CD
|
||||
const static int PIN_IO = 25; // IO
|
||||
const static int PIN_BSY = 26; // BSY
|
||||
const static int PIN_SEL = 27; // SEL
|
||||
|
||||
// Warning: The Allwinner/Banana Pi GPIO numbers DO NOT correspond to
|
||||
// the Raspberry Pi GPIO numbers.
|
||||
// For example, Pin 7 is GPIO4 on a Raspberry Pi. Its GPIO 6 on a Banana Pi
|
||||
// For Banana Pi, the pins are specified by physical pin number, NOT GPIO number
|
||||
// (The Macro's convert the pin number to logical BPi GPIO number)
|
||||
const static int BPI_PIN_ACT = BPI_M2P_07; // ACTIVE
|
||||
const static int BPI_PIN_ENB = BPI_M2P_29; // ENABLE
|
||||
const static int BPI_PIN_IND = -1; // INITIATOR CTRL DIRECTION
|
||||
const static int BPI_PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int BPI_PIN_DTD = -1; // DATA DIRECTION
|
||||
|
||||
const static int BPI_PIN_DT0 = BPI_M2P_19; // Data 0
|
||||
const static int BPI_PIN_DT1 = BPI_M2P_23; // Data 1
|
||||
const static int BPI_PIN_DT2 = BPI_M2P_32; // Data 2
|
||||
const static int BPI_PIN_DT3 = BPI_M2P_33; // Data 3
|
||||
const static int BPI_PIN_DT4 = BPI_M2P_08; // Data 4
|
||||
const static int BPI_PIN_DT5 = BPI_M2P_10; // Data 5
|
||||
const static int BPI_PIN_DT6 = BPI_M2P_36; // Data 6
|
||||
const static int BPI_PIN_DT7 = BPI_M2P_11; // Data 7
|
||||
const static int BPI_PIN_DP = BPI_M2P_12; // Data parity
|
||||
const static int BPI_PIN_ATN = BPI_M2P_35; // ATN
|
||||
const static int BPI_PIN_RST = BPI_M2P_38; // RST
|
||||
const static int BPI_PIN_ACK = BPI_M2P_40; // ACK
|
||||
const static int BPI_PIN_REQ = BPI_M2P_15; // REQ
|
||||
const static int BPI_PIN_MSG = BPI_M2P_16; // MSG
|
||||
const static int BPI_PIN_CD = BPI_M2P_18; // CD
|
||||
const static int BPI_PIN_IO = BPI_M2P_22; // IO
|
||||
const static int BPI_PIN_BSY = BPI_M2P_37; // BSY
|
||||
const static int BPI_PIN_SEL = BPI_M2P_13; // SEL
|
40
cpp/hal/data_sample.cpp
Normal file
40
cpp/hal/data_sample.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/bus.h"
|
||||
#include "hal/data_sample.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string DataSample::GetPhaseStr() const
|
||||
{
|
||||
return BUS::GetPhaseStrRaw(GetPhase());
|
||||
}
|
||||
|
||||
phase_t DataSample::GetPhase() const
|
||||
{
|
||||
// Selection Phase
|
||||
if (GetSEL()) {
|
||||
return phase_t::selection;
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetBSY()) {
|
||||
return phase_t::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
uint32_t mci = GetMSG() ? 0x04 : 0x00;
|
||||
mci |= GetCD() ? 0x02 : 0x00;
|
||||
mci |= GetIO() ? 0x01 : 0x00;
|
||||
return BUS::GetPhase(mci);
|
||||
}
|
54
cpp/hal/data_sample.h
Normal file
54
cpp/hal/data_sample.h
Normal file
@ -0,0 +1,54 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Logical representation of a single data sample ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/scsi.h"
|
||||
#include <string>
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
class DataSample
|
||||
{
|
||||
public:
|
||||
virtual bool GetBSY() const = 0;
|
||||
virtual bool GetSEL() const = 0;
|
||||
virtual bool GetATN() const = 0;
|
||||
virtual bool GetACK() const = 0;
|
||||
virtual bool GetRST() const = 0;
|
||||
virtual bool GetMSG() const = 0;
|
||||
virtual bool GetCD() const = 0;
|
||||
virtual bool GetIO() const = 0;
|
||||
virtual bool GetREQ() const = 0;
|
||||
virtual bool GetACT() const = 0;
|
||||
virtual uint8_t GetDAT() const = 0;
|
||||
virtual bool GetDP() const = 0;
|
||||
|
||||
virtual uint32_t GetRawCapture() const = 0;
|
||||
|
||||
phase_t GetPhase() const;
|
||||
virtual bool GetSignal(int pin) const = 0;
|
||||
|
||||
uint64_t GetTimestamp() const
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
string GetPhaseStr() const;
|
||||
|
||||
virtual ~DataSample() = default;
|
||||
|
||||
explicit DataSample(uint64_t in_timestamp) : timestamp{in_timestamp} {}
|
||||
DataSample() = default;
|
||||
|
||||
private:
|
||||
uint64_t timestamp = 0;
|
||||
};
|
64
cpp/hal/data_sample_bananam2p.cpp
Normal file
64
cpp/hal/data_sample_bananam2p.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "data_sample_bananam2p.h"
|
||||
#include "hal/sunxi_utils.h"
|
||||
#include <cstdint>
|
||||
|
||||
uint8_t DataSample_BananaM2p::GetDAT() const
|
||||
{
|
||||
uint8_t ret_val = 0;
|
||||
ret_val |= GetSignal(BPI_PIN_DT0) ? 0x01 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT1) ? 0x02 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT2) ? 0x04 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT3) ? 0x08 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT4) ? 0x10 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT5) ? 0x20 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT6) ? 0x40 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
ret_val |= GetSignal(BPI_PIN_DT7) ? 0x80 : 0x00; // NOSONAR: GCC 10 doesn't fully support std::byte
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
bool DataSample_BananaM2p::GetSignal(int pin) const
|
||||
{
|
||||
int bank = SunXI::GPIO_BANK(pin);
|
||||
int num = SunXI::GPIO_NUM(pin);
|
||||
|
||||
return (bool)((data[bank] >> num) & 0x1);
|
||||
}
|
||||
|
||||
// This will return the Banana Pi data in the "Raspberry Pi" data format.
|
||||
uint32_t DataSample_BananaM2p::GetRawCapture() const
|
||||
{
|
||||
uint32_t rpi_data = 0;
|
||||
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_BSY)) << PIN_BSY;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_SEL)) << PIN_SEL;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_ATN)) << PIN_ATN;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_ACK)) << PIN_ACK;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_RST)) << PIN_RST;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_MSG)) << PIN_MSG;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_CD)) << PIN_CD;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_IO)) << PIN_IO;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_REQ)) << PIN_REQ;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_ACT)) << PIN_ACT;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DP)) << PIN_DP;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT0)) << PIN_DT0;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT1)) << PIN_DT1;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT2)) << PIN_DT2;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT3)) << PIN_DT3;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT4)) << PIN_DT4;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT5)) << PIN_DT5;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT6)) << PIN_DT6;
|
||||
rpi_data |= ((uint32_t)GetSignal(BPI_PIN_DT7)) << PIN_DT7;
|
||||
|
||||
return rpi_data;
|
||||
}
|
94
cpp/hal/data_sample_bananam2p.h
Normal file
94
cpp/hal/data_sample_bananam2p.h
Normal file
@ -0,0 +1,94 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Logical representation of a single data sample ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample.h"
|
||||
#include "shared/scsi.h"
|
||||
#include <array>
|
||||
|
||||
#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
|
||||
|
||||
class DataSample_BananaM2p final : public DataSample
|
||||
{
|
||||
public:
|
||||
bool GetSignal(int pin) const override;
|
||||
|
||||
bool GetBSY() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_BSY);
|
||||
}
|
||||
bool GetSEL() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_SEL);
|
||||
}
|
||||
bool GetATN() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_ATN);
|
||||
}
|
||||
bool GetACK() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_ACK);
|
||||
}
|
||||
bool GetRST() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_RST);
|
||||
}
|
||||
bool GetMSG() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_MSG);
|
||||
}
|
||||
bool GetCD() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_CD);
|
||||
}
|
||||
bool GetIO() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_IO);
|
||||
}
|
||||
bool GetREQ() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_REQ);
|
||||
}
|
||||
bool GetACT() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_ACT);
|
||||
}
|
||||
bool GetDP() const override
|
||||
{
|
||||
return GetSignal(BPI_PIN_DP);
|
||||
}
|
||||
|
||||
uint8_t GetDAT() const override;
|
||||
|
||||
uint32_t GetRawCapture() const override;
|
||||
|
||||
DataSample_BananaM2p(const array<uint32_t, 12> &in_data, uint64_t in_timestamp)
|
||||
: DataSample{in_timestamp}, data{in_data}
|
||||
{
|
||||
}
|
||||
DataSample_BananaM2p() = default;
|
||||
|
||||
~DataSample_BananaM2p() override = default;
|
||||
|
||||
private:
|
||||
array<uint32_t, 12> data = {0};
|
||||
};
|
14
cpp/hal/data_sample_raspberry.cpp
Normal file
14
cpp/hal/data_sample_raspberry.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "shared/scsi.h"
|
||||
#include "data_sample.h"
|
||||
|
109
cpp/hal/data_sample_raspberry.h
Normal file
109
cpp/hal/data_sample_raspberry.h
Normal file
@ -0,0 +1,109 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Logical representation of a single data sample ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample.h"
|
||||
#include "shared/scsi.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
|
||||
|
||||
class DataSample_Raspberry final : public DataSample
|
||||
{
|
||||
public:
|
||||
bool GetSignal(int pin) const override
|
||||
{
|
||||
return (bool)((data >> pin) & 1);
|
||||
};
|
||||
|
||||
bool GetBSY() const override
|
||||
{
|
||||
return GetSignal(PIN_BSY);
|
||||
}
|
||||
bool GetSEL() const override
|
||||
{
|
||||
return GetSignal(PIN_SEL);
|
||||
}
|
||||
bool GetATN() const override
|
||||
{
|
||||
return GetSignal(PIN_ATN);
|
||||
}
|
||||
bool GetACK() const override
|
||||
{
|
||||
return GetSignal(PIN_ACK);
|
||||
}
|
||||
bool GetRST() const override
|
||||
{
|
||||
return GetSignal(PIN_RST);
|
||||
}
|
||||
bool GetMSG() const override
|
||||
{
|
||||
return GetSignal(PIN_MSG);
|
||||
}
|
||||
bool GetCD() const override
|
||||
{
|
||||
return GetSignal(PIN_CD);
|
||||
}
|
||||
bool GetIO() const override
|
||||
{
|
||||
return GetSignal(PIN_IO);
|
||||
}
|
||||
bool GetREQ() const override
|
||||
{
|
||||
return GetSignal(PIN_REQ);
|
||||
}
|
||||
bool GetACT() const override
|
||||
{
|
||||
return GetSignal(PIN_ACT);
|
||||
}
|
||||
bool GetDP() const override
|
||||
{
|
||||
return GetSignal(PIN_DP);
|
||||
}
|
||||
uint8_t GetDAT() const override
|
||||
{
|
||||
uint8_t ret_val = 0;
|
||||
ret_val |= (data >> (PIN_DT0 - 0)) & 0x01; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT1 - 1)) & 0x02; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT2 - 2)) & 0x04; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT3 - 3)) & 0x08; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT4 - 4)) & 0x10; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT5 - 5)) & 0x20; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT6 - 6)) & 0x40; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
ret_val |= (data >> (PIN_DT7 - 7)) & 0x80; // NOSONAR: GCC 10 doesn't support shift operations on std::byte
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
uint32_t GetRawCapture() const override
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
DataSample_Raspberry(const uint32_t in_data, const uint64_t in_timestamp) : DataSample{in_timestamp}, data{in_data}
|
||||
{
|
||||
}
|
||||
DataSample_Raspberry() = default;
|
||||
|
||||
~DataSample_Raspberry() override = default;
|
||||
|
||||
private:
|
||||
uint32_t data = 0;
|
||||
};
|
1107
cpp/hal/gpiobus.cpp
1107
cpp/hal/gpiobus.cpp
File diff suppressed because it is too large
Load Diff
@ -11,10 +11,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/config.h"
|
||||
#include "hal/bus.h"
|
||||
#include "shared/scsi.h"
|
||||
#include "bus.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/gpio.h>
|
||||
@ -31,18 +32,25 @@
|
||||
//#define CONNECT_TYPE_GAMERNIUM // GAMERnium.com version (standard logic, unique pin assignment)
|
||||
|
||||
#if defined CONNECT_TYPE_STANDARD
|
||||
#include "hal/gpiobus_standard.h"
|
||||
#include "hal/connection_type/connection_standard.h"
|
||||
#elif defined CONNECT_TYPE_FULLSPEC
|
||||
#include "hal/gpiobus_fullspec.h"
|
||||
#include "hal/connection_type/connection_fullspec.h"
|
||||
#elif defined CONNECT_TYPE_AIBOM
|
||||
#include "hal/gpiobus_aibom.h"
|
||||
#include "hal/connection_type/connection_aibom.h"
|
||||
#elif defined CONNECT_TYPE_GAMERNIUM
|
||||
#include "hal/gpiobus_gamernium.h"
|
||||
#include "hal/connection_type/connection_gamernium.h"
|
||||
#else
|
||||
#error Invalid connection type or none specified
|
||||
#endif
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
// #define ENABLE_GPIO_TRACE
|
||||
#ifdef ENABLE_GPIO_TRACE
|
||||
#define GPIO_FUNCTION_TRACE LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define GPIO_FUNCTION_TRACE
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -118,136 +126,18 @@ using namespace std; //NOSONAR Not relevant for rascsi
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define ALL_SCSI_PINS \
|
||||
((1<<PIN_DT0)|\
|
||||
(1<<PIN_DT1)|\
|
||||
(1<<PIN_DT2)|\
|
||||
(1<<PIN_DT3)|\
|
||||
(1<<PIN_DT4)|\
|
||||
(1<<PIN_DT5)|\
|
||||
(1<<PIN_DT6)|\
|
||||
(1<<PIN_DT7)|\
|
||||
(1<<PIN_DP)|\
|
||||
(1<<PIN_ATN)|\
|
||||
(1<<PIN_RST)|\
|
||||
(1<<PIN_ACK)|\
|
||||
(1<<PIN_REQ)|\
|
||||
(1<<PIN_MSG)|\
|
||||
(1<<PIN_CD)|\
|
||||
(1<<PIN_IO)|\
|
||||
(1<<PIN_BSY)|\
|
||||
(1<<PIN_SEL))
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (GPIO)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const static uint32_t SYST_OFFSET = 0x00003000;
|
||||
const static uint32_t IRPT_OFFSET = 0x0000B200;
|
||||
const static uint32_t ARMT_OFFSET = 0x0000B400;
|
||||
const static uint32_t PADS_OFFSET = 0x00100000;
|
||||
const static uint32_t GPIO_OFFSET = 0x00200000;
|
||||
const static uint32_t QA7_OFFSET = 0x01000000;
|
||||
|
||||
const static int GPIO_INPUT = 0;
|
||||
const static int GPIO_OUTPUT = 1;
|
||||
const static int GPIO_IRQ_IN = 3;
|
||||
const static int GPIO_PULLNONE = 0;
|
||||
const static int GPIO_PULLDOWN = 1;
|
||||
const static int GPIO_PULLUP = 2;
|
||||
const static int GPIO_FSEL_0 = 0;
|
||||
const static int GPIO_FSEL_1 = 1;
|
||||
const static int GPIO_FSEL_2 = 2;
|
||||
const static int GPIO_FSEL_3 = 3;
|
||||
const static int GPIO_SET_0 = 7;
|
||||
const static int GPIO_CLR_0 = 10;
|
||||
const static int GPIO_LEV_0 = 13;
|
||||
const static int GPIO_EDS_0 = 16;
|
||||
const static int GPIO_REN_0 = 19;
|
||||
const static int GPIO_FEN_0 = 22;
|
||||
const static int GPIO_HEN_0 = 25;
|
||||
const static int GPIO_LEN_0 = 28;
|
||||
const static int GPIO_AREN_0 = 31;
|
||||
const static int GPIO_AFEN_0 = 34;
|
||||
const static int GPIO_PUD = 37;
|
||||
const static int GPIO_CLK_0 = 38;
|
||||
const static int GPIO_GPPINMUXSD = 52;
|
||||
const static int GPIO_PUPPDN0 = 57;
|
||||
const static int GPIO_PUPPDN1 = 58;
|
||||
const static int GPIO_PUPPDN3 = 59;
|
||||
const static int GPIO_PUPPDN4 = 60;
|
||||
const static int PAD_0_27 = 11;
|
||||
const static int SYST_CS = 0;
|
||||
const static int SYST_CLO = 1;
|
||||
const static int SYST_CHI = 2;
|
||||
const static int SYST_C0 = 3;
|
||||
const static int SYST_C1 = 4;
|
||||
const static int SYST_C2 = 5;
|
||||
const static int SYST_C3 = 6;
|
||||
const static int ARMT_LOAD = 0;
|
||||
const static int ARMT_VALUE = 1;
|
||||
const static int ARMT_CTRL = 2;
|
||||
const static int ARMT_CLRIRQ = 3;
|
||||
const static int ARMT_RAWIRQ = 4;
|
||||
const static int ARMT_MSKIRQ = 5;
|
||||
const static int ARMT_RELOAD = 6;
|
||||
const static int ARMT_PREDIV = 7;
|
||||
const static int ARMT_FREERUN = 8;
|
||||
const static int IRPT_PND_IRQ_B = 0;
|
||||
const static int IRPT_PND_IRQ_1 = 1;
|
||||
const static int IRPT_PND_IRQ_2 = 2;
|
||||
const static int IRPT_FIQ_CNTL = 3;
|
||||
const static int IRPT_ENB_IRQ_1 = 4;
|
||||
const static int IRPT_ENB_IRQ_2 = 5;
|
||||
const static int IRPT_ENB_IRQ_B = 6;
|
||||
const static int IRPT_DIS_IRQ_1 = 7;
|
||||
const static int IRPT_DIS_IRQ_2 = 8;
|
||||
const static int IRPT_DIS_IRQ_B = 9;
|
||||
const static int QA7_CORE0_TINTC = 16;
|
||||
const static int GPIO_IRQ = (32 + 20); // GPIO3
|
||||
|
||||
#define GPIO_INEDGE ((1 << PIN_BSY) | \
|
||||
(1 << PIN_SEL) | \
|
||||
(1 << PIN_ATN) | \
|
||||
(1 << PIN_ACK) | \
|
||||
(1 << PIN_RST))
|
||||
|
||||
#define GPIO_MCI ((1 << PIN_MSG) | \
|
||||
(1 << PIN_CD) | \
|
||||
(1 << PIN_IO))
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (GIC)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const static uint32_t ARM_GICD_BASE = 0xFF841000;
|
||||
const static uint32_t ARM_GICC_BASE = 0xFF842000;
|
||||
const static uint32_t ARM_GIC_END = 0xFF847FFF;
|
||||
const static int GICD_CTLR = 0x000;
|
||||
const static int GICD_IGROUPR0 = 0x020;
|
||||
const static int GICD_ISENABLER0 = 0x040;
|
||||
const static int GICD_ICENABLER0 = 0x060;
|
||||
const static int GICD_ISPENDR0 = 0x080;
|
||||
const static int GICD_ICPENDR0 = 0x0A0;
|
||||
const static int GICD_ISACTIVER0 = 0x0C0;
|
||||
const static int GICD_ICACTIVER0 = 0x0E0;
|
||||
const static int GICD_IPRIORITYR0 = 0x100;
|
||||
const static int GICD_ITARGETSR0 = 0x200;
|
||||
const static int GICD_ICFGR0 = 0x300;
|
||||
const static int GICD_SGIR = 0x3C0;
|
||||
const static int GICC_CTLR = 0x000;
|
||||
const static int GICC_PMR = 0x001;
|
||||
const static int GICC_IAR = 0x003;
|
||||
const static int GICC_EOIR = 0x004;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (GIC IRQ)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const static int GIC_IRQLOCAL0 = (16 + 14);
|
||||
const static int GIC_GPIO_IRQ = (32 + 116); // GPIO3
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -270,245 +160,61 @@ const static int GIC_GPIO_IRQ = (32 + 116); // GPIO3
|
||||
const static int ON = 1;
|
||||
const static int OFF = 0;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (bus control timing)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
// SCSI Bus timings taken from:
|
||||
// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html
|
||||
const static int SCSI_DELAY_ARBITRATION_DELAY_NS = 2400;
|
||||
const static int SCSI_DELAY_ASSERTION_PERIOD_NS = 90;
|
||||
const static int SCSI_DELAY_BUS_CLEAR_DELAY_NS = 800;
|
||||
const static int SCSI_DELAY_BUS_FREE_DELAY_NS = 800;
|
||||
const static int SCSI_DELAY_BUS_SET_DELAY_NS = 1800;
|
||||
const static int SCSI_DELAY_BUS_SETTLE_DELAY_NS = 400;
|
||||
const static int SCSI_DELAY_CABLE_SKEW_DELAY_NS = 10;
|
||||
const static int SCSI_DELAY_DATA_RELEASE_DELAY_NS = 400;
|
||||
const static int SCSI_DELAY_DESKEW_DELAY_NS = 45;
|
||||
const static int SCSI_DELAY_DISCONNECTION_DELAY_US = 200;
|
||||
const static int SCSI_DELAY_HOLD_TIME_NS = 45;
|
||||
const static int SCSI_DELAY_NEGATION_PERIOD_NS = 90;
|
||||
const static int SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S = 10; // (recommended)
|
||||
const static int SCSI_DELAY_RESET_TO_SELECTION_TIME_US = 250*1000; // (recommended)
|
||||
const static int SCSI_DELAY_RESET_HOLD_TIME_US = 25;
|
||||
const static int SCSI_DELAY_SELECTION_ABORT_TIME_US = 200;
|
||||
const static int SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS = 250*1000; // (recommended)
|
||||
const static int SCSI_DELAY_FAST_ASSERTION_PERIOD_NS = 30;
|
||||
const static int SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS = 5;
|
||||
const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20;
|
||||
const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10;
|
||||
const static int SCSI_DELAY_FAST_NEGATION_PERIOD_NS = 30;
|
||||
|
||||
// The DaynaPort SCSI Link do a short delay in the middle of transfering
|
||||
// a packet. This is the number of uS that will be delayed between the
|
||||
// header and the actual data.
|
||||
const static int SCSI_DELAY_SEND_DATA_DAYNAPORT_US = 100;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Class definition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
class GPIOBUS final : public BUS
|
||||
class GPIOBUS : public BUS
|
||||
{
|
||||
public:
|
||||
public:
|
||||
// Basic Functions
|
||||
GPIOBUS()= default;
|
||||
~GPIOBUS() override = default;
|
||||
GPIOBUS() = default;
|
||||
// Destructor
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
~GPIOBUS() override = default;
|
||||
// Initialization
|
||||
void Reset() override;
|
||||
// Reset
|
||||
void Cleanup() override;
|
||||
// Cleanup
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Bus signal acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
inline uint32_t Acquire() override
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
// Only used for development/debugging purposes. Isn't really applicable
|
||||
// to any real-world RaSCSI application
|
||||
return 0;
|
||||
#else
|
||||
signals = *level;
|
||||
|
||||
#if SIGNAL_CONTROL_MODE < 2
|
||||
// Invert if negative logic (internal processing is unified to positive logic)
|
||||
signals = ~signals;
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
|
||||
return signals;
|
||||
#endif // ifdef __x86_64__ || __X86__
|
||||
}
|
||||
|
||||
void SetENB(bool ast);
|
||||
// Set ENB signal
|
||||
|
||||
bool GetBSY() const override;
|
||||
// Get BSY signal
|
||||
void SetBSY(bool ast) override;
|
||||
// Set BSY signal
|
||||
|
||||
bool GetSEL() const override;
|
||||
// Get SEL signal
|
||||
void SetSEL(bool ast) override;
|
||||
// Set SEL signal
|
||||
|
||||
bool GetATN() const override;
|
||||
// Get ATN signal
|
||||
void SetATN(bool ast) override;
|
||||
// Set ATN signal
|
||||
|
||||
bool GetACK() const override;
|
||||
// Get ACK signal
|
||||
void SetACK(bool ast) override;
|
||||
// Set ACK signal
|
||||
|
||||
bool GetACT() const;
|
||||
// Get ACT signal
|
||||
void SetACT(bool ast);
|
||||
// Set ACT signal
|
||||
|
||||
bool GetRST() const override;
|
||||
// Get RST signal
|
||||
void SetRST(bool ast) override;
|
||||
// Set RST signal
|
||||
|
||||
bool GetMSG() const override;
|
||||
// Get MSG signal
|
||||
void SetMSG(bool ast) override;
|
||||
// Set MSG signal
|
||||
|
||||
bool GetCD() const override;
|
||||
// Get CD signal
|
||||
void SetCD(bool ast) override;
|
||||
// Set CD signal
|
||||
|
||||
bool GetIO() override;
|
||||
// Get IO signal
|
||||
void SetIO(bool ast) override;
|
||||
// Set IO signal
|
||||
|
||||
bool GetREQ() const override;
|
||||
// Get REQ signal
|
||||
void SetREQ(bool ast) override;
|
||||
// Set REQ signal
|
||||
|
||||
uint8_t GetDAT() override;
|
||||
// Get DAT signal
|
||||
void SetDAT(uint8_t dat) override;
|
||||
// Set DAT signal
|
||||
bool GetDP() const override;
|
||||
// Get Data parity signal
|
||||
int CommandHandShake(vector<uint8_t>&) override;
|
||||
// Command receive handshake
|
||||
int ReceiveHandShake(uint8_t *buf, int count) override;
|
||||
int CommandHandShake(vector<uint8_t> &) override;
|
||||
// Data receive handshake
|
||||
int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) override;
|
||||
int ReceiveHandShake(uint8_t *buf, int count) override;
|
||||
// Data transmission handshake
|
||||
int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) override;
|
||||
|
||||
static BUS::phase_t GetPhaseRaw(uint32_t raw_data);
|
||||
// Get the phase based on raw data
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal interrupt
|
||||
bool PollSelectEvent() override;
|
||||
// SEL signal event polling
|
||||
void ClearSelectEvent() override;
|
||||
bool PollSelectEvent() override;
|
||||
// Clear SEL signal event
|
||||
#endif
|
||||
void ClearSelectEvent() override;
|
||||
|
||||
protected:
|
||||
virtual void MakeTable() = 0;
|
||||
|
||||
bool GetSignal(int pin) const override = 0;
|
||||
void SetSignal(int pin, bool ast) override = 0;
|
||||
bool WaitSignal(int pin, bool ast);
|
||||
|
||||
private:
|
||||
// SCSI I/O signal control
|
||||
void MakeTable();
|
||||
// Create work data
|
||||
void SetControl(int pin, bool ast);
|
||||
// Set Control Signal
|
||||
void SetMode(int pin, int mode);
|
||||
// Set SCSI I/O mode
|
||||
bool GetSignal(int pin) const override;
|
||||
// Get SCSI input signal value
|
||||
void SetSignal(int pin, bool ast) override;
|
||||
// Set SCSI output signal value
|
||||
bool WaitSignal(int pin, int ast);
|
||||
// Wait for a signal to change
|
||||
virtual bool WaitREQ(bool ast) = 0;
|
||||
virtual bool WaitACK(bool ast) = 0;
|
||||
|
||||
// Interrupt control
|
||||
void DisableIRQ();
|
||||
// IRQ Disabled
|
||||
void EnableIRQ();
|
||||
// IRQ Enabled
|
||||
virtual void EnableIRQ() = 0;
|
||||
virtual void DisableIRQ() = 0;
|
||||
|
||||
// GPIO pin functionality settings
|
||||
void PinConfig(int pin, int mode);
|
||||
// GPIO pin direction setting
|
||||
void PullConfig(int pin, int mode);
|
||||
// GPIO pin pull up/down resistor setting
|
||||
void PinSetSignal(int pin, bool ast);
|
||||
// Set GPIO output signal
|
||||
void DrvConfig(uint32_t drive);
|
||||
virtual void PinSetSignal(int pin, bool ast) = 0;
|
||||
// Set GPIO drive strength
|
||||
virtual void DrvConfig(uint32_t drive) = 0;
|
||||
|
||||
// Operation mode
|
||||
mode_e actmode = mode_e::TARGET; // NOSONAR: This protected so derived classes can access it
|
||||
|
||||
mode_e actmode = mode_e::TARGET; // Operation mode
|
||||
#ifdef __linux__
|
||||
// SEL signal event request
|
||||
struct gpioevent_request selevreq = {}; // NOSONAR: This protected so derived classes can access it
|
||||
// epoll file descriptor
|
||||
int epfd; // NOSONAR: This protected so derived classes can access it
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
uint32_t baseaddr = 0; // Base address
|
||||
#endif
|
||||
|
||||
int rpitype = 0; // Type of Raspberry Pi
|
||||
|
||||
volatile uint32_t *gpio = nullptr; // GPIO register
|
||||
|
||||
volatile uint32_t *pads = nullptr; // PADS register
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
volatile uint32_t *level = nullptr; // GPIO input level
|
||||
#endif
|
||||
|
||||
volatile uint32_t *irpctl = nullptr; // Interrupt control register
|
||||
|
||||
volatile uint32_t irptenb; // Interrupt enabled state
|
||||
|
||||
volatile uint32_t *qa7regs = nullptr; // QA7 register
|
||||
|
||||
volatile int tintcore; // Interupt control target CPU.
|
||||
|
||||
volatile uint32_t tintctl; // Interupt control
|
||||
|
||||
volatile uint32_t giccpmr; // GICC priority setting
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register
|
||||
#endif
|
||||
|
||||
volatile uint32_t *gicc = nullptr; // GIC CPU interface register
|
||||
|
||||
array<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
|
||||
|
||||
uint32_t signals = 0; // All bus signals
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
struct gpioevent_request selevreq = {}; // SEL signal event request
|
||||
|
||||
int epfd; // epoll file descriptor
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
|
||||
|
||||
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
|
||||
#else
|
||||
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
|
||||
|
||||
array<uint32_t, 256> tblDatSet = {}; // Table setting table
|
||||
#endif
|
||||
|
||||
static const array<int, 19> SignalTable; // signal table
|
||||
};
|
||||
|
||||
|
@ -1,56 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI Adapter Aibom version
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "AIBOM PRODUCTS version"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 2; // SCSI positive logic specification
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN OFF // DATA SIGNAL INPUT
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 17; // ENABLE
|
||||
const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 18; // DATA DIRECTION
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 6; // Data 0
|
||||
const static int PIN_DT1 = 12; // Data 1
|
||||
const static int PIN_DT2 = 13; // Data 2
|
||||
const static int PIN_DT3 = 16; // Data 3
|
||||
const static int PIN_DT4 = 19; // Data 4
|
||||
const static int PIN_DT5 = 20; // Data 5
|
||||
const static int PIN_DT6 = 26; // Data 6
|
||||
const static int PIN_DT7 = 21; // Data 7
|
||||
const static int PIN_DP = 5; // Data parity
|
||||
const static int PIN_ATN = 22; // ATN
|
||||
const static int PIN_RST = 25; // RST
|
||||
const static int PIN_ACK = 10; // ACK
|
||||
const static int PIN_REQ = 7; // REQ
|
||||
const static int PIN_MSG = 9; // MSG
|
||||
const static int PIN_CD = 11; // CD
|
||||
const static int PIN_IO = 23; // IO
|
||||
const static int PIN_BSY = 24; // BSY
|
||||
const static int PIN_SEL = 8; // SEL
|
1105
cpp/hal/gpiobus_bananam2p.cpp
Normal file
1105
cpp/hal/gpiobus_bananam2p.cpp
Normal file
File diff suppressed because it is too large
Load Diff
221
cpp/hal/gpiobus_bananam2p.h
Normal file
221
cpp/hal/gpiobus_bananam2p.h
Normal file
@ -0,0 +1,221 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// [ GPIO-SCSI bus ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample_bananam2p.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/pi_defs/bpi-gpio.h"
|
||||
#include "hal/sbc_version.h"
|
||||
#include "hal/sunxi_utils.h"
|
||||
#include "shared/log.h"
|
||||
#include "shared/scsi.h"
|
||||
#include <map>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Class definition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
class GPIOBUS_BananaM2p : public GPIOBUS
|
||||
{
|
||||
public:
|
||||
// Basic Functions
|
||||
GPIOBUS_BananaM2p() = default;
|
||||
~GPIOBUS_BananaM2p() override = default;
|
||||
// Destructor
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
|
||||
void Cleanup() override;
|
||||
void Reset() override;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Bus signal acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t Acquire() override;
|
||||
|
||||
void SetENB(bool ast) override;
|
||||
// Set ENB signal
|
||||
|
||||
bool GetBSY() const override;
|
||||
// Get BSY signal
|
||||
void SetBSY(bool ast) override;
|
||||
// Set BSY signal
|
||||
|
||||
bool GetSEL() const override;
|
||||
// Get SEL signal
|
||||
void SetSEL(bool ast) override;
|
||||
// Set SEL signal
|
||||
|
||||
bool GetATN() const override;
|
||||
// Get ATN signal
|
||||
void SetATN(bool ast) override;
|
||||
// Set ATN signal
|
||||
|
||||
bool GetACK() const override;
|
||||
// Get ACK signal
|
||||
void SetACK(bool ast) override;
|
||||
// Set ACK signal
|
||||
|
||||
bool GetACT() const override;
|
||||
// Get ACT signal
|
||||
void SetACT(bool ast) override;
|
||||
// Set ACT signal
|
||||
|
||||
bool GetRST() const override;
|
||||
// Get RST signal
|
||||
void SetRST(bool ast) override;
|
||||
// Set RST signal
|
||||
|
||||
bool GetMSG() const override;
|
||||
// Get MSG signal
|
||||
void SetMSG(bool ast) override;
|
||||
// Set MSG signal
|
||||
|
||||
bool GetCD() const override;
|
||||
// Get CD signal
|
||||
void SetCD(bool ast) override;
|
||||
// Set CD signal
|
||||
|
||||
bool GetIO() override;
|
||||
// Get IO signal
|
||||
void SetIO(bool ast) override;
|
||||
// Set IO signal
|
||||
|
||||
bool GetREQ() const override;
|
||||
// Get REQ signal
|
||||
void SetREQ(bool ast) override;
|
||||
// Set REQ signal
|
||||
|
||||
bool GetDP() const override;
|
||||
|
||||
uint8_t GetDAT() override;
|
||||
// Get DAT signal
|
||||
void SetDAT(uint8_t dat) override;
|
||||
// Set DAT signal
|
||||
|
||||
bool WaitREQ(bool ast) override
|
||||
{
|
||||
return WaitSignal(BPI_PIN_REQ, ast);
|
||||
}
|
||||
bool WaitACK(bool ast) override
|
||||
{
|
||||
return WaitSignal(BPI_PIN_ACK, ast);
|
||||
}
|
||||
|
||||
// TODO: Restore these back to protected
|
||||
// protected:
|
||||
// SCSI I/O signal control
|
||||
void MakeTable() override;
|
||||
// Create work data
|
||||
void SetControl(int pin, bool ast) override;
|
||||
// Set Control Signal
|
||||
void SetMode(int pin, int mode) override;
|
||||
// Set SCSI I/O mode
|
||||
int GetMode(int pin) override;
|
||||
|
||||
bool GetSignal(int pin) const override;
|
||||
|
||||
// Set SCSI output signal value
|
||||
void SetSignal(int pin, bool ast) override;
|
||||
|
||||
// Interrupt control
|
||||
// IRQ Disabled
|
||||
void DisableIRQ() override;
|
||||
// IRQ Enabled
|
||||
void EnableIRQ() override;
|
||||
|
||||
// GPIO pin functionality settings
|
||||
void PinConfig(int pin, int mode) override;
|
||||
// GPIO pin direction setting
|
||||
void PullConfig(int pin, int mode) override;
|
||||
// GPIO pin pull up/down resistor setting
|
||||
void PinSetSignal(int pin, bool ast) override;
|
||||
// Set GPIO output signal
|
||||
void DrvConfig(uint32_t drive) override;
|
||||
// Set GPIO drive strength
|
||||
|
||||
unique_ptr<DataSample> GetSample(uint64_t timestamp) override
|
||||
{
|
||||
Acquire();
|
||||
return make_unique<DataSample_BananaM2p>(signals, timestamp);
|
||||
}
|
||||
|
||||
bool SetupSelEvent();
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
uint32_t baseaddr = 0; // Base address
|
||||
#endif
|
||||
|
||||
volatile uint32_t *gpio_map = nullptr;
|
||||
|
||||
// Timer control register
|
||||
volatile uint32_t *tmr_ctrl;
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register
|
||||
#endif
|
||||
|
||||
volatile uint32_t *gicc = nullptr; // GIC CPU interface register
|
||||
|
||||
array<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
|
||||
|
||||
array<uint32_t, 12> signals = {0}; // All bus signals
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
|
||||
|
||||
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
|
||||
#else
|
||||
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
|
||||
|
||||
array<uint32_t, 256> tblDatSet = {}; // Table setting table
|
||||
#endif
|
||||
|
||||
int sunxi_setup(void);
|
||||
|
||||
void sunxi_set_pullupdn(int gpio, int pud);
|
||||
void sunxi_setup_gpio(int gpio, int direction, int pud);
|
||||
|
||||
void sunxi_output_gpio(int gpio, int value);
|
||||
int sunxi_input_gpio(int gpio) const;
|
||||
|
||||
int bpi_found = -1;
|
||||
|
||||
volatile SunXI::sunxi_gpio_reg_t *pio_map;
|
||||
volatile SunXI::sunxi_gpio_reg_t *r_pio_map;
|
||||
|
||||
volatile uint32_t *r_gpio_map;
|
||||
|
||||
uint8_t *gpio_mmap_reg;
|
||||
uint32_t sunxi_capture_all_gpio();
|
||||
void set_pullupdn(int gpio, int pud);
|
||||
|
||||
// These definitions are from c_gpio.c and should be removed at some point!!
|
||||
const int SETUP_OK = 0;
|
||||
|
||||
SBC_Version::sbc_version_type sbc_version;
|
||||
|
||||
SunXI::sunxi_gpio_reg_t saved_gpio_config;
|
||||
|
||||
static const array<int, 19> SignalTable;
|
||||
|
||||
void InitializeGpio();
|
||||
std::vector<int> gpio_banks;
|
||||
|
||||
#if defined(__x86_64__) || defined(__X86__) || defined(__aarch64__)
|
||||
// The SEL_EVENT functions need to do something to prevent SonarCloud from
|
||||
// claiming they should be const
|
||||
int dummy_var = 0;
|
||||
#endif
|
||||
};
|
@ -4,11 +4,18 @@
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
// [ GPIO bus factory ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "hal/gpiobus_bananam2p.h"
|
||||
#include "hal/gpiobus_factory.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/gpiobus_raspberry.h"
|
||||
#include "hal/gpiobus_virtual.h"
|
||||
#include "hal/sbc_version.h"
|
||||
#include "shared/log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -17,11 +24,21 @@ unique_ptr<BUS> GPIOBUS_Factory::Create(BUS::mode_e mode)
|
||||
// TODO Make the factory a friend of GPIOBUS and make the GPIOBUS constructor private
|
||||
// so that clients cannot use it anymore but have to use the factory.
|
||||
// Also make Init() private.
|
||||
if (auto bus = make_unique<GPIOBUS>(); bus->Init(mode)) {
|
||||
bus->Reset();
|
||||
|
||||
return bus;
|
||||
unique_ptr<BUS> return_ptr;
|
||||
SBC_Version::Init();
|
||||
if (SBC_Version::IsBananaPi()) {
|
||||
LOGTRACE("Creating GPIOBUS_BananaM2p")
|
||||
return_ptr = make_unique<GPIOBUS_BananaM2p>();
|
||||
} else if (SBC_Version::IsRaspberryPi()) {
|
||||
LOGTRACE("Creating GPIOBUS_Raspberry")
|
||||
return_ptr = make_unique<GPIOBUS_Raspberry>();
|
||||
} else {
|
||||
LOGINFO("Creating Virtual GPIOBUS")
|
||||
return_ptr = make_unique<GPIOBUS_Virtual>();
|
||||
}
|
||||
|
||||
if (!return_ptr->Init(mode)) {
|
||||
return nullptr;
|
||||
}
|
||||
return_ptr->Reset();
|
||||
return return_ptr;
|
||||
}
|
||||
|
@ -9,14 +9,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bus.h"
|
||||
#include "hal/bus.h"
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class GPIOBUS_Factory
|
||||
{
|
||||
public:
|
||||
|
||||
static unique_ptr<BUS> Create(BUS::mode_e);
|
||||
static unique_ptr<BUS> Create(BUS::mode_e mode);
|
||||
};
|
||||
|
@ -1,56 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI standard (SCSI logic, standard pin assignment)
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "FULLSPEC"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 5; // ENABLE
|
||||
const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = 7; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 8; // DATA DIRECTION
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 10; // Data 0
|
||||
const static int PIN_DT1 = 11; // Data 1
|
||||
const static int PIN_DT2 = 12; // Data 2
|
||||
const static int PIN_DT3 = 13; // Data 3
|
||||
const static int PIN_DT4 = 14; // Data 4
|
||||
const static int PIN_DT5 = 15; // Data 5
|
||||
const static int PIN_DT6 = 16; // Data 6
|
||||
const static int PIN_DT7 = 17; // Data 7
|
||||
const static int PIN_DP = 18; // Data parity
|
||||
const static int PIN_ATN = 19; // ATN
|
||||
const static int PIN_RST = 20; // RST
|
||||
const static int PIN_ACK = 21; // ACK
|
||||
const static int PIN_REQ = 22; // REQ
|
||||
const static int PIN_MSG = 23; // MSG
|
||||
const static int PIN_CD = 24; // CD
|
||||
const static int PIN_IO = 25; // IO
|
||||
const static int PIN_BSY = 26; // BSY
|
||||
const static int PIN_SEL = 27; // SEL
|
@ -1,57 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI Adapter GAMERnium.com version
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "GAMERnium.com version"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 14; // ACTIVE
|
||||
const static int PIN_ENB = 6; // ENABLE
|
||||
const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = 8; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = 5; // DATA DIRECTION
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 21; // Data 0
|
||||
const static int PIN_DT1 = 26; // Data 1
|
||||
const static int PIN_DT2 = 20; // Data 2
|
||||
const static int PIN_DT3 = 19; // Data 3
|
||||
const static int PIN_DT4 = 16; // Data 4
|
||||
const static int PIN_DT5 = 13; // Data 5
|
||||
const static int PIN_DT6 = 12; // Data 6
|
||||
const static int PIN_DT7 = 11; // Data 7
|
||||
const static int PIN_DP = 25; // Data parity
|
||||
const static int PIN_ATN = 10; // ATN
|
||||
const static int PIN_RST = 22; // RST
|
||||
const static int PIN_ACK = 24; // ACK
|
||||
const static int PIN_REQ = 15; // REQ
|
||||
const static int PIN_MSG = 17; // MSG
|
||||
const static int PIN_CD = 18; // CD
|
||||
const static int PIN_IO = 4; // IO
|
||||
const static int PIN_BSY = 27; // BSY
|
||||
const static int PIN_SEL = 23; // SEL
|
||||
|
988
cpp/hal/gpiobus_raspberry.cpp
Normal file
988
cpp/hal/gpiobus_raspberry.cpp
Normal file
@ -0,0 +1,988 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
// [ GPIO-SCSI bus ]
|
||||
//
|
||||
// Raspberry Pi 4:
|
||||
// https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
|
||||
// Raspberry Pi Zero:
|
||||
// https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/gpiobus_raspberry.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "shared/log.h"
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// imported from bcm_host.c
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t GPIOBUS_Raspberry::get_dt_ranges(const char *filename, uint32_t offset)
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
uint32_t address = ~0;
|
||||
if (FILE *fp = fopen(filename, "rb"); fp) {
|
||||
fseek(fp, offset, SEEK_SET);
|
||||
if (array<uint8_t, 4> buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) {
|
||||
address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
uint32_t GPIOBUS_Raspberry::bcm_host_get_peripheral_address()
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
#ifdef __linux__
|
||||
uint32_t address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
|
||||
if (address == 0) {
|
||||
address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
|
||||
}
|
||||
address = (address == (uint32_t)~0) ? 0x20000000 : address;
|
||||
return address;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::Init(mode_e mode)
|
||||
{
|
||||
GPIOBUS::Init(mode);
|
||||
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
(void)baseaddr;
|
||||
level = new uint32_t();
|
||||
return true;
|
||||
#else
|
||||
int i;
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
epoll_event ev = {};
|
||||
#endif
|
||||
|
||||
// Get the base address
|
||||
baseaddr = (uint32_t)bcm_host_get_peripheral_address();
|
||||
|
||||
// Open /dev/mem
|
||||
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (fd == -1) {
|
||||
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?")
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map peripheral region memory
|
||||
void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
|
||||
if (map == MAP_FAILED) {
|
||||
LOGERROR("Error: Unable to map memory")
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine the type of raspberry pi from the base address
|
||||
if (baseaddr == 0xfe000000) {
|
||||
rpitype = 4;
|
||||
} else if (baseaddr == 0x3f000000) {
|
||||
rpitype = 2;
|
||||
} else {
|
||||
rpitype = 1;
|
||||
}
|
||||
|
||||
// GPIO
|
||||
gpio = (uint32_t *)map;
|
||||
gpio += GPIO_OFFSET / sizeof(uint32_t);
|
||||
level = &gpio[GPIO_LEV_0];
|
||||
|
||||
// PADS
|
||||
pads = (uint32_t *)map;
|
||||
pads += PADS_OFFSET / sizeof(uint32_t);
|
||||
|
||||
// System timer
|
||||
SysTimer::Init();
|
||||
|
||||
// Interrupt controller
|
||||
irpctl = (uint32_t *)map;
|
||||
irpctl += IRPT_OFFSET / sizeof(uint32_t);
|
||||
|
||||
// Quad-A7 control
|
||||
qa7regs = (uint32_t *)map;
|
||||
qa7regs += QA7_OFFSET / sizeof(uint32_t);
|
||||
|
||||
// Map GIC memory
|
||||
if (rpitype == 4) {
|
||||
map = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ARM_GICD_BASE);
|
||||
if (map == MAP_FAILED) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
gicd = (uint32_t *)map;
|
||||
gicc = (uint32_t *)map;
|
||||
gicc += (ARM_GICC_BASE - ARM_GICD_BASE) / sizeof(uint32_t);
|
||||
} else {
|
||||
gicd = NULL;
|
||||
gicc = NULL;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
// Set Drive Strength to 16mA
|
||||
DrvConfig(7);
|
||||
|
||||
// Set pull up/pull down
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
int pullmode = GPIO_PULLNONE;
|
||||
#elif SIGNAL_CONTROL_MODE == 1
|
||||
int pullmode = GPIO_PULLUP;
|
||||
#else
|
||||
int pullmode = GPIO_PULLDOWN;
|
||||
#endif
|
||||
|
||||
// Initialize all signals
|
||||
for (i = 0; SignalTable[i] >= 0; i++) {
|
||||
int j = SignalTable[i];
|
||||
PinSetSignal(j, OFF);
|
||||
PinConfig(j, GPIO_INPUT);
|
||||
PullConfig(j, pullmode);
|
||||
}
|
||||
|
||||
// Set control signals
|
||||
PinSetSignal(PIN_ACT, OFF);
|
||||
PinSetSignal(PIN_TAD, OFF);
|
||||
PinSetSignal(PIN_IND, OFF);
|
||||
PinSetSignal(PIN_DTD, OFF);
|
||||
PinConfig(PIN_ACT, GPIO_OUTPUT);
|
||||
PinConfig(PIN_TAD, GPIO_OUTPUT);
|
||||
PinConfig(PIN_IND, GPIO_OUTPUT);
|
||||
PinConfig(PIN_DTD, GPIO_OUTPUT);
|
||||
|
||||
// Set the ENABLE signal
|
||||
// This is used to show that the application is running
|
||||
PinSetSignal(PIN_ENB, ENB_OFF);
|
||||
PinConfig(PIN_ENB, GPIO_OUTPUT);
|
||||
|
||||
// GPIO Function Select (GPFSEL) registers backup
|
||||
gpfsel[0] = gpio[GPIO_FSEL_0];
|
||||
gpfsel[1] = gpio[GPIO_FSEL_1];
|
||||
gpfsel[2] = gpio[GPIO_FSEL_2];
|
||||
gpfsel[3] = gpio[GPIO_FSEL_3];
|
||||
|
||||
// Initialize SEL signal interrupt
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// GPIO chip open
|
||||
fd = open("/dev/gpiochip0", 0);
|
||||
if (fd == -1) {
|
||||
LOGERROR("Unable to open /dev/gpiochip0. Is RaSCSI already running?")
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event request setting
|
||||
strcpy(selevreq.consumer_label, "RaSCSI");
|
||||
selevreq.lineoffset = PIN_SEL;
|
||||
selevreq.handleflags = GPIOHANDLE_REQUEST_INPUT;
|
||||
#if SIGNAL_CONTROL_MODE < 2
|
||||
selevreq.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE;
|
||||
#else
|
||||
selevreq.eventflags = GPIOEVENT_REQUEST_RISING_EDGE;
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
|
||||
// Get event request
|
||||
if (ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) {
|
||||
LOGERROR("Unable to register event request. Is RaSCSI already running?")
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close GPIO chip file handle
|
||||
close(fd);
|
||||
|
||||
// epoll initialization
|
||||
epfd = epoll_create(1);
|
||||
ev.events = EPOLLIN | EPOLLPRI;
|
||||
ev.data.fd = selevreq.fd;
|
||||
epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev);
|
||||
#else
|
||||
// Edge detection setting
|
||||
#if SIGNAL_CONTROL_MODE == 2
|
||||
gpio[GPIO_AREN_0] = 1 << PIN_SEL;
|
||||
#else
|
||||
gpio[GPIO_AFEN_0] = 1 << PIN_SEL;
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
|
||||
// Clear event - GPIO Pin Event Detect Status
|
||||
gpio[GPIO_EDS_0] = 1 << PIN_SEL;
|
||||
|
||||
// Register interrupt handler
|
||||
setIrqFuncAddress(IrqHandler);
|
||||
|
||||
// GPIO interrupt setting
|
||||
if (rpitype == 4) {
|
||||
// GIC Invalid
|
||||
gicd[GICD_CTLR] = 0;
|
||||
|
||||
// Route all interupts to core 0
|
||||
for (i = 0; i < 8; i++) {
|
||||
gicd[GICD_ICENABLER0 + i] = 0xffffffff;
|
||||
gicd[GICD_ICPENDR0 + i] = 0xffffffff;
|
||||
gicd[GICD_ICACTIVER0 + i] = 0xffffffff;
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
gicd[GICD_IPRIORITYR0 + i] = 0xa0a0a0a0;
|
||||
gicd[GICD_ITARGETSR0 + i] = 0x01010101;
|
||||
}
|
||||
|
||||
// Set all interrupts as level triggers
|
||||
for (i = 0; i < 16; i++) {
|
||||
gicd[GICD_ICFGR0 + i] = 0;
|
||||
}
|
||||
|
||||
// GIC Invalid
|
||||
gicd[GICD_CTLR] = 1;
|
||||
|
||||
// Enable CPU interface for core 0
|
||||
gicc[GICC_PMR] = 0xf0;
|
||||
gicc[GICC_CTLR] = 1;
|
||||
|
||||
// Enable interrupts
|
||||
gicd[GICD_ISENABLER0 + (GIC_GPIO_IRQ / 32)] = 1 << (GIC_GPIO_IRQ % 32);
|
||||
} else {
|
||||
// Enable interrupts
|
||||
irpctl[IRPT_ENB_IRQ_2] = (1 << (GPIO_IRQ % 32));
|
||||
}
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Create work table
|
||||
MakeTable();
|
||||
|
||||
// Finally, enable ENABLE
|
||||
// Show the user that this app is running
|
||||
SetControl(PIN_ENB, ENB_ON);
|
||||
|
||||
return true;
|
||||
#endif // ifdef __x86_64__ || __X86__
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::Cleanup()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return;
|
||||
#else
|
||||
// Release SEL signal interrupt
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
close(selevreq.fd);
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Set control signals
|
||||
PinSetSignal(PIN_ENB, OFF);
|
||||
PinSetSignal(PIN_ACT, OFF);
|
||||
PinSetSignal(PIN_TAD, OFF);
|
||||
PinSetSignal(PIN_IND, OFF);
|
||||
PinSetSignal(PIN_DTD, OFF);
|
||||
PinConfig(PIN_ACT, GPIO_INPUT);
|
||||
PinConfig(PIN_TAD, GPIO_INPUT);
|
||||
PinConfig(PIN_IND, GPIO_INPUT);
|
||||
PinConfig(PIN_DTD, GPIO_INPUT);
|
||||
|
||||
// Initialize all signals
|
||||
for (int i = 0; SignalTable[i] >= 0; i++) {
|
||||
int pin = SignalTable[i];
|
||||
PinSetSignal(pin, OFF);
|
||||
PinConfig(pin, GPIO_INPUT);
|
||||
PullConfig(pin, GPIO_PULLNONE);
|
||||
}
|
||||
|
||||
// Set drive strength back to 8mA
|
||||
DrvConfig(3);
|
||||
#endif // ifdef __x86_64__ || __X86__
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::Reset()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return;
|
||||
#else
|
||||
int i;
|
||||
int j;
|
||||
|
||||
// Turn off active signal
|
||||
SetControl(PIN_ACT, ACT_OFF);
|
||||
|
||||
// Set all signals to off
|
||||
for (i = 0;; i++) {
|
||||
j = SignalTable[i];
|
||||
if (j < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
SetSignal(j, OFF);
|
||||
}
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Target mode
|
||||
|
||||
// Set target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
|
||||
// Set the initiator signal to input
|
||||
SetControl(PIN_IND, IND_IN);
|
||||
SetMode(PIN_SEL, IN);
|
||||
SetMode(PIN_ATN, IN);
|
||||
SetMode(PIN_ACK, IN);
|
||||
SetMode(PIN_RST, IN);
|
||||
|
||||
// Set data bus signals to input
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
} else {
|
||||
// Initiator mode
|
||||
|
||||
// Set target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
|
||||
// Set the initiator signal to output
|
||||
SetControl(PIN_IND, IND_OUT);
|
||||
SetMode(PIN_SEL, OUT);
|
||||
SetMode(PIN_ATN, OUT);
|
||||
SetMode(PIN_ACK, OUT);
|
||||
SetMode(PIN_RST, OUT);
|
||||
|
||||
// Set the data bus signals to output
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
}
|
||||
|
||||
// Initialize all signals
|
||||
signals = 0;
|
||||
#endif // ifdef __x86_64__ || __X86__
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetENB(bool ast)
|
||||
{
|
||||
PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetBSY() const
|
||||
{
|
||||
return GetSignal(PIN_BSY);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetBSY(bool ast)
|
||||
{
|
||||
// Set BSY signal
|
||||
SetSignal(PIN_BSY, ast);
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
if (ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
|
||||
// Set Target signal to output
|
||||
SetControl(PIN_TAD, TAD_OUT);
|
||||
|
||||
SetMode(PIN_BSY, OUT);
|
||||
SetMode(PIN_MSG, OUT);
|
||||
SetMode(PIN_CD, OUT);
|
||||
SetMode(PIN_REQ, OUT);
|
||||
SetMode(PIN_IO, OUT);
|
||||
} else {
|
||||
// Turn off the ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_OFF);
|
||||
|
||||
// Set the target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetSEL() const
|
||||
{
|
||||
return GetSignal(PIN_SEL);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetSEL(bool ast)
|
||||
{
|
||||
if (actmode == mode_e::INITIATOR && ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
}
|
||||
|
||||
// Set SEL signal
|
||||
SetSignal(PIN_SEL, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetATN() const
|
||||
{
|
||||
return GetSignal(PIN_ATN);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetATN(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ATN, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetACK() const
|
||||
{
|
||||
return GetSignal(PIN_ACK);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetACK(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ACK, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetACT() const
|
||||
{
|
||||
return GetSignal(PIN_ACT);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetACT(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ACT, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetRST() const
|
||||
{
|
||||
return GetSignal(PIN_RST);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetRST(bool ast)
|
||||
{
|
||||
SetSignal(PIN_RST, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetMSG() const
|
||||
{
|
||||
return GetSignal(PIN_MSG);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetMSG(bool ast)
|
||||
{
|
||||
SetSignal(PIN_MSG, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetCD() const
|
||||
{
|
||||
return GetSignal(PIN_CD);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetCD(bool ast)
|
||||
{
|
||||
SetSignal(PIN_CD, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetIO()
|
||||
{
|
||||
bool ast = GetSignal(PIN_IO);
|
||||
|
||||
if (actmode == mode_e::INITIATOR) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
} else {
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetIO(bool ast)
|
||||
{
|
||||
SetSignal(PIN_IO, ast);
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetDAT(0);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
} else {
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetREQ() const
|
||||
{
|
||||
return GetSignal(PIN_REQ);
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::SetREQ(bool ast)
|
||||
{
|
||||
SetSignal(PIN_REQ, ast);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get data signals
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint8_t GPIOBUS_Raspberry::GetDAT()
|
||||
{
|
||||
uint32_t data = Acquire();
|
||||
data = ((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));
|
||||
|
||||
return (uint8_t)data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set data signals
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::SetDAT(uint8_t dat)
|
||||
{
|
||||
// Write to port
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
uint32_t fsel = gpfsel[0];
|
||||
fsel &= tblDatMsk[0][dat];
|
||||
fsel |= tblDatSet[0][dat];
|
||||
if (fsel != gpfsel[0]) {
|
||||
gpfsel[0] = fsel;
|
||||
gpio[GPIO_FSEL_0] = fsel;
|
||||
}
|
||||
|
||||
fsel = gpfsel[1];
|
||||
fsel &= tblDatMsk[1][dat];
|
||||
fsel |= tblDatSet[1][dat];
|
||||
if (fsel != gpfsel[1]) {
|
||||
gpfsel[1] = fsel;
|
||||
gpio[GPIO_FSEL_1] = fsel;
|
||||
}
|
||||
|
||||
fsel = gpfsel[2];
|
||||
fsel &= tblDatMsk[2][dat];
|
||||
fsel |= tblDatSet[2][dat];
|
||||
if (fsel != gpfsel[2]) {
|
||||
gpfsel[2] = fsel;
|
||||
gpio[GPIO_FSEL_2] = fsel;
|
||||
}
|
||||
#else
|
||||
gpio[GPIO_CLR_0] = tblDatMsk[dat];
|
||||
gpio[GPIO_SET_0] = tblDatSet[dat];
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
}
|
||||
|
||||
bool GPIOBUS_Raspberry::GetDP() const
|
||||
{
|
||||
return GetSignal(PIN_DP);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Create work table
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Signal table
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const array<int, 19> GPIOBUS_Raspberry::SignalTable = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6,
|
||||
PIN_DT7, PIN_DP, PIN_SEL, PIN_ATN, PIN_RST, PIN_ACK, PIN_BSY,
|
||||
PIN_MSG, PIN_CD, PIN_IO, PIN_REQ, -1};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Create work table
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::MakeTable(void)
|
||||
{
|
||||
const array<int, 9> pintbl = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP};
|
||||
|
||||
array<bool, 256> tblParity;
|
||||
|
||||
// Create parity table
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
uint32_t bits = i;
|
||||
uint32_t parity = 0;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
parity ^= bits & 1;
|
||||
bits >>= 1;
|
||||
}
|
||||
parity = ~parity;
|
||||
tblParity[i] = parity & 1;
|
||||
}
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
// Mask and setting data generation
|
||||
for (auto &tbl : tblDatMsk) {
|
||||
tbl.fill(-1);
|
||||
}
|
||||
for (auto &tbl : tblDatSet) {
|
||||
tbl.fill(0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
// Bit string for inspection
|
||||
uint32_t bits = i;
|
||||
|
||||
// Get parity
|
||||
if (tblParity[i]) {
|
||||
bits |= (1 << 8);
|
||||
}
|
||||
|
||||
// Bit check
|
||||
for (int j = 0; j < 9; j++) {
|
||||
// Index and shift amount calculation
|
||||
int index = pintbl[j] / 10;
|
||||
int shift = (pintbl[j] % 10) * 3;
|
||||
|
||||
// Mask data
|
||||
tblDatMsk[index][i] &= ~(0x7 << shift);
|
||||
|
||||
// Setting data
|
||||
if (bits & 1) {
|
||||
tblDatSet[index][i] |= (1 << shift);
|
||||
}
|
||||
|
||||
bits >>= 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
// Bit string for inspection
|
||||
uint32_t bits = i;
|
||||
|
||||
// Get parity
|
||||
if (tblParity[i]) {
|
||||
bits |= (1 << 8);
|
||||
}
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 1
|
||||
// Negative logic is inverted
|
||||
bits = ~bits;
|
||||
#endif
|
||||
|
||||
// Create GPIO register information
|
||||
uint32_t gpclr = 0;
|
||||
uint32_t gpset = 0;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
if (bits & 1) {
|
||||
gpset |= (1 << pintbl[j]);
|
||||
} else {
|
||||
gpclr |= (1 << pintbl[j]);
|
||||
}
|
||||
bits >>= 1;
|
||||
}
|
||||
|
||||
tblDatMsk[i] = gpclr;
|
||||
tblDatSet[i] = gpset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Control signal setting
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::SetControl(int pin, bool ast)
|
||||
{
|
||||
PinSetSignal(pin, ast);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Input/output mode setting
|
||||
//
|
||||
// Set direction fo pin (IN / OUT)
|
||||
// Used with: TAD, BSY, MSG, CD, REQ, O, SEL, IND, ATN, ACK, RST, DT*
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::SetMode(int pin, int mode)
|
||||
{
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
if (mode == OUT) {
|
||||
return;
|
||||
}
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
|
||||
int index = pin / 10;
|
||||
int shift = (pin % 10) * 3;
|
||||
uint32_t data = gpfsel[index];
|
||||
data &= ~(0x7 << shift);
|
||||
if (mode == OUT) {
|
||||
data |= (1 << shift);
|
||||
}
|
||||
gpio[index] = data;
|
||||
gpfsel[index] = data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get input signal value
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool GPIOBUS_Raspberry::GetSignal(int pin) const
|
||||
{
|
||||
return (signals >> pin) & 1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set output signal value
|
||||
//
|
||||
// Sets the output value. Used with:
|
||||
// PIN_ENB, ACT, TAD, IND, DTD, BSY, SignalTable
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::SetSignal(int pin, bool ast)
|
||||
{
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
int index = pin / 10;
|
||||
int shift = (pin % 10) * 3;
|
||||
uint32_t data = gpfsel[index];
|
||||
if (ast) {
|
||||
data |= (1 << shift);
|
||||
} else {
|
||||
data &= ~(0x7 << shift);
|
||||
}
|
||||
gpio[index] = data;
|
||||
gpfsel[index] = data;
|
||||
#elif SIGNAL_CONTROL_MODE == 1
|
||||
if (ast) {
|
||||
gpio[GPIO_CLR_0] = 0x1 << pin;
|
||||
} else {
|
||||
gpio[GPIO_SET_0] = 0x1 << pin;
|
||||
}
|
||||
#elif SIGNAL_CONTROL_MODE == 2
|
||||
if (ast) {
|
||||
gpio[GPIO_SET_0] = 0x1 << pin;
|
||||
} else {
|
||||
gpio[GPIO_CLR_0] = 0x1 << pin;
|
||||
}
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::DisableIRQ()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (rpitype == 4) {
|
||||
// RPI4 is disabled by GICC
|
||||
giccpmr = gicc[GICC_PMR];
|
||||
gicc[GICC_PMR] = 0;
|
||||
} else if (rpitype == 2) {
|
||||
// RPI2,3 disable core timer IRQ
|
||||
tintcore = sched_getcpu() + QA7_CORE0_TINTC;
|
||||
tintctl = qa7regs[tintcore];
|
||||
qa7regs[tintcore] = 0;
|
||||
} else {
|
||||
// Stop system timer interrupt with interrupt controller
|
||||
irptenb = irpctl[IRPT_ENB_IRQ_1];
|
||||
irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf;
|
||||
}
|
||||
#else
|
||||
(void)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPIOBUS_Raspberry::EnableIRQ()
|
||||
{
|
||||
if (rpitype == 4) {
|
||||
// RPI4 enables interrupts via the GICC
|
||||
gicc[GICC_PMR] = giccpmr;
|
||||
} else if (rpitype == 2) {
|
||||
// RPI2,3 re-enable core timer IRQ
|
||||
qa7regs[tintcore] = tintctl;
|
||||
} else {
|
||||
// Restart the system timer interrupt with the interrupt controller
|
||||
irpctl[IRPT_ENB_IRQ_1] = irptenb & 0xf;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Pin direction setting (input/output)
|
||||
//
|
||||
// Used in Init() for ACT, TAD, IND, DTD, ENB to set direction (GPIO_OUTPUT vs GPIO_INPUT)
|
||||
// Also used on SignalTable
|
||||
// Only used in Init and Cleanup. Reset uses SetMode
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::PinConfig(int pin, int mode)
|
||||
{
|
||||
// Check for invalid pin
|
||||
if (pin < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = pin / 10;
|
||||
uint32_t mask = ~(0x7 << ((pin % 10) * 3));
|
||||
gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Pin pull-up/pull-down setting
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::PullConfig(int pin, int mode)
|
||||
{
|
||||
uint32_t pull;
|
||||
|
||||
// Check for invalid pin
|
||||
if (pin < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpitype == 4) {
|
||||
switch (mode) {
|
||||
case GPIO_PULLNONE:
|
||||
pull = 0;
|
||||
break;
|
||||
case GPIO_PULLUP:
|
||||
pull = 1;
|
||||
break;
|
||||
case GPIO_PULLDOWN:
|
||||
pull = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
pin &= 0x1f;
|
||||
int shift = (pin & 0xf) << 1;
|
||||
uint32_t bits = gpio[GPIO_PUPPDN0 + (pin >> 4)];
|
||||
bits &= ~(3 << shift);
|
||||
bits |= (pull << shift);
|
||||
gpio[GPIO_PUPPDN0 + (pin >> 4)] = bits;
|
||||
} else {
|
||||
pin &= 0x1f;
|
||||
gpio[GPIO_PUD] = mode & 0x3;
|
||||
SysTimer::SleepUsec(2);
|
||||
gpio[GPIO_CLK_0] = 0x1 << pin;
|
||||
SysTimer::SleepUsec(2);
|
||||
gpio[GPIO_PUD] = 0;
|
||||
gpio[GPIO_CLK_0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set output pin
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::PinSetSignal(int pin, bool ast)
|
||||
{
|
||||
// Check for invalid pin
|
||||
if (pin < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ast) {
|
||||
gpio[GPIO_SET_0] = 0x1 << pin;
|
||||
} else {
|
||||
gpio[GPIO_CLR_0] = 0x1 << pin;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set the signal drive strength
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Raspberry::DrvConfig(uint32_t drive)
|
||||
{
|
||||
uint32_t data = pads[PAD_0_27];
|
||||
pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Bus signal acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t GPIOBUS_Raspberry::Acquire()
|
||||
{
|
||||
signals = *level;
|
||||
|
||||
#if SIGNAL_CONTROL_MODE < 2
|
||||
// Invert if negative logic (internal processing is unified to positive logic)
|
||||
signals = ~signals;
|
||||
#endif // SIGNAL_CONTROL_MODE
|
||||
|
||||
return signals;
|
||||
}
|
295
cpp/hal/gpiobus_raspberry.h
Normal file
295
cpp/hal/gpiobus_raspberry.h
Normal file
@ -0,0 +1,295 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// [ GPIO-SCSI bus ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample_raspberry.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "shared/log.h"
|
||||
#include "shared/scsi.h"
|
||||
#include <map>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI signal pin assignment setting
|
||||
// GPIO pin mapping table for SCSI signals.
|
||||
// PIN_DT0~PIN_SEL
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define ALL_SCSI_PINS \
|
||||
((1 << PIN_DT0) | (1 << PIN_DT1) | (1 << PIN_DT2) | (1 << PIN_DT3) | (1 << PIN_DT4) | (1 << PIN_DT5) | \
|
||||
(1 << PIN_DT6) | (1 << PIN_DT7) | (1 << PIN_DP) | (1 << PIN_ATN) | (1 << PIN_RST) | (1 << PIN_ACK) | \
|
||||
(1 << PIN_REQ) | (1 << PIN_MSG) | (1 << PIN_CD) | (1 << PIN_IO) | (1 << PIN_BSY) | (1 << PIN_SEL))
|
||||
|
||||
#define GPIO_INEDGE ((1 << PIN_BSY) | (1 << PIN_SEL) | (1 << PIN_ATN) | (1 << PIN_ACK) | (1 << PIN_RST))
|
||||
|
||||
#define GPIO_MCI ((1 << PIN_MSG) | (1 << PIN_CD) | (1 << PIN_IO))
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (GIC)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const static uint32_t ARM_GICD_BASE = 0xFF841000;
|
||||
const static uint32_t ARM_GICC_BASE = 0xFF842000;
|
||||
const static uint32_t ARM_GIC_END = 0xFF847FFF;
|
||||
const static int GICD_CTLR = 0x000;
|
||||
const static int GICD_IGROUPR0 = 0x020;
|
||||
const static int GICD_ISENABLER0 = 0x040;
|
||||
const static int GICD_ICENABLER0 = 0x060;
|
||||
const static int GICD_ISPENDR0 = 0x080;
|
||||
const static int GICD_ICPENDR0 = 0x0A0;
|
||||
const static int GICD_ISACTIVER0 = 0x0C0;
|
||||
const static int GICD_ICACTIVER0 = 0x0E0;
|
||||
const static int GICD_IPRIORITYR0 = 0x100;
|
||||
const static int GICD_ITARGETSR0 = 0x200;
|
||||
const static int GICD_ICFGR0 = 0x300;
|
||||
const static int GICD_SGIR = 0x3C0;
|
||||
const static int GICC_CTLR = 0x000;
|
||||
const static int GICC_PMR = 0x001;
|
||||
const static int GICC_IAR = 0x003;
|
||||
const static int GICC_EOIR = 0x004;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations (GIC IRQ)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const static int GIC_IRQLOCAL0 = (16 + 14);
|
||||
const static int GIC_GPIO_IRQ = (32 + 116); // GPIO3
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Class definition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
class GPIOBUS_Raspberry : public GPIOBUS
|
||||
{
|
||||
public:
|
||||
GPIOBUS_Raspberry() = default;
|
||||
~GPIOBUS_Raspberry() override = default;
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
|
||||
void Reset() override;
|
||||
void Cleanup() override;
|
||||
|
||||
// Bus signal acquisition
|
||||
uint32_t Acquire() override;
|
||||
|
||||
// Set ENB signal
|
||||
void SetENB(bool ast) override;
|
||||
|
||||
// Get BSY signal
|
||||
bool GetBSY() const override;
|
||||
// Set BSY signal
|
||||
void SetBSY(bool ast) override;
|
||||
|
||||
// Get SEL signal
|
||||
bool GetSEL() const override;
|
||||
// Set SEL signal
|
||||
void SetSEL(bool ast) override;
|
||||
|
||||
// Get ATN signal
|
||||
bool GetATN() const override;
|
||||
// Set ATN signal
|
||||
void SetATN(bool ast) override;
|
||||
|
||||
// Get ACK signal
|
||||
bool GetACK() const override;
|
||||
// Set ACK signal
|
||||
void SetACK(bool ast) override;
|
||||
|
||||
// Get ACT signal
|
||||
bool GetACT() const override;
|
||||
// Set ACT signal
|
||||
void SetACT(bool ast) override;
|
||||
|
||||
// Get RST signal
|
||||
bool GetRST() const override;
|
||||
// Set RST signal
|
||||
void SetRST(bool ast) override;
|
||||
|
||||
// Get MSG signal
|
||||
bool GetMSG() const override;
|
||||
// Set MSG signal
|
||||
void SetMSG(bool ast) override;
|
||||
|
||||
// Get CD signal
|
||||
bool GetCD() const override;
|
||||
// Set CD signal
|
||||
void SetCD(bool ast) override;
|
||||
|
||||
// Get IO signal
|
||||
bool GetIO() override;
|
||||
// Set IO signal
|
||||
void SetIO(bool ast) override;
|
||||
|
||||
// Get REQ signal
|
||||
bool GetREQ() const override;
|
||||
// Set REQ signal
|
||||
void SetREQ(bool ast) override;
|
||||
|
||||
bool GetDP() const override;
|
||||
|
||||
// Get DAT signal
|
||||
uint8_t GetDAT() override;
|
||||
// Set DAT signal
|
||||
void SetDAT(uint8_t dat) override;
|
||||
|
||||
bool WaitREQ(bool ast) override
|
||||
{
|
||||
return WaitSignal(PIN_REQ, ast);
|
||||
}
|
||||
bool WaitACK(bool ast) override
|
||||
{
|
||||
return WaitSignal(PIN_ACK, ast);
|
||||
}
|
||||
static uint32_t bcm_host_get_peripheral_address();
|
||||
|
||||
unique_ptr<DataSample> GetSample(uint64_t timestamp) override
|
||||
{
|
||||
Acquire();
|
||||
return make_unique<DataSample_Raspberry>(signals, timestamp);
|
||||
}
|
||||
|
||||
protected:
|
||||
// All bus signals
|
||||
uint32_t signals = 0; // NOSONAR: Must be protected (not private) for testability
|
||||
// GPIO input level
|
||||
volatile uint32_t *level = nullptr; // NOSONAR: Must be protected (not private) for testability
|
||||
|
||||
private:
|
||||
// SCSI I/O signal control
|
||||
void MakeTable() override;
|
||||
// Create work data
|
||||
void SetControl(int pin, bool ast) override;
|
||||
// Set Control Signal
|
||||
void SetMode(int pin, int mode) override;
|
||||
// Set SCSI I/O mode
|
||||
int GetMode(int pin) override
|
||||
{
|
||||
// Not implemented (or needed for thist gpio bus type)
|
||||
(void)pin;
|
||||
return -1;
|
||||
}
|
||||
bool GetSignal(int pin) const override;
|
||||
// Get SCSI input signal value
|
||||
void SetSignal(int pin, bool ast) override;
|
||||
// Set SCSI output signal value
|
||||
|
||||
// Interrupt control
|
||||
void DisableIRQ() override;
|
||||
// IRQ Disabled
|
||||
void EnableIRQ() override;
|
||||
// IRQ Enabled
|
||||
|
||||
// GPIO pin functionality settings
|
||||
void PinConfig(int pin, int mode) override;
|
||||
// GPIO pin direction setting
|
||||
void PullConfig(int pin, int mode) override;
|
||||
// GPIO pin pull up/down resistor setting
|
||||
void PinSetSignal(int pin, bool ast) override;
|
||||
// Set GPIO output signal
|
||||
void DrvConfig(uint32_t drive) override;
|
||||
// Set GPIO drive strength
|
||||
|
||||
static uint32_t get_dt_ranges(const char *filename, uint32_t offset);
|
||||
|
||||
uint32_t baseaddr = 0; // Base address
|
||||
|
||||
int rpitype = 0; // Type of Raspberry Pi
|
||||
|
||||
// GPIO register
|
||||
volatile uint32_t *gpio = nullptr; // NOSONAR: volatile needed for register access
|
||||
// PADS register
|
||||
volatile uint32_t *pads = nullptr; // NOSONAR: volatile needed for register access
|
||||
|
||||
// Interrupt control register
|
||||
volatile uint32_t *irpctl = nullptr;
|
||||
|
||||
// Interrupt enabled state
|
||||
volatile uint32_t irptenb; // NOSONAR: volatile needed for register access
|
||||
|
||||
// QA7 register
|
||||
volatile uint32_t *qa7regs = nullptr;
|
||||
// Interupt control target CPU.
|
||||
volatile int tintcore; // NOSONAR: volatile needed for register access
|
||||
|
||||
// Interupt control
|
||||
volatile uint32_t tintctl; // NOSONAR: volatile needed for register access
|
||||
// GICC priority setting
|
||||
volatile uint32_t giccpmr; // NOSONAR: volatile needed for register access
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
// GIC Interrupt distributor register
|
||||
volatile uint32_t *gicd = nullptr;
|
||||
#endif
|
||||
// GIC CPU interface register
|
||||
volatile uint32_t *gicc = nullptr;
|
||||
|
||||
// RAM copy of GPFSEL0-4 values (GPIO Function Select)
|
||||
array<uint32_t, 4> gpfsel;
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
// Data mask table
|
||||
array<array<uint32_t, 256>, 3> tblDatMsk;
|
||||
// Data setting table
|
||||
array<array<uint32_t, 256>, 3> tblDatSet;
|
||||
#else
|
||||
// Data mask table
|
||||
array<uint32_t, 256> tblDatMsk = {};
|
||||
// Table setting table
|
||||
array<uint32_t, 256> tblDatSet = {};
|
||||
#endif
|
||||
|
||||
static const array<int, 19> SignalTable;
|
||||
|
||||
const static int GPIO_FSEL_0 = 0;
|
||||
const static int GPIO_FSEL_1 = 1;
|
||||
const static int GPIO_FSEL_2 = 2;
|
||||
const static int GPIO_FSEL_3 = 3;
|
||||
const static int GPIO_SET_0 = 7;
|
||||
const static int GPIO_CLR_0 = 10;
|
||||
const static int GPIO_LEV_0 = 13;
|
||||
const static int GPIO_EDS_0 = 16;
|
||||
const static int GPIO_REN_0 = 19;
|
||||
const static int GPIO_FEN_0 = 22;
|
||||
const static int GPIO_HEN_0 = 25;
|
||||
const static int GPIO_LEN_0 = 28;
|
||||
const static int GPIO_AREN_0 = 31;
|
||||
const static int GPIO_AFEN_0 = 34;
|
||||
const static int GPIO_PUD = 37;
|
||||
const static int GPIO_CLK_0 = 38;
|
||||
const static int GPIO_GPPINMUXSD = 52;
|
||||
const static int GPIO_PUPPDN0 = 57;
|
||||
const static int GPIO_PUPPDN1 = 58;
|
||||
const static int GPIO_PUPPDN3 = 59;
|
||||
const static int GPIO_PUPPDN4 = 60;
|
||||
const static int PAD_0_27 = 11;
|
||||
const static int IRPT_PND_IRQ_B = 0;
|
||||
const static int IRPT_PND_IRQ_1 = 1;
|
||||
const static int IRPT_PND_IRQ_2 = 2;
|
||||
const static int IRPT_FIQ_CNTL = 3;
|
||||
const static int IRPT_ENB_IRQ_1 = 4;
|
||||
const static int IRPT_ENB_IRQ_2 = 5;
|
||||
const static int IRPT_ENB_IRQ_B = 6;
|
||||
const static int IRPT_DIS_IRQ_1 = 7;
|
||||
const static int IRPT_DIS_IRQ_2 = 8;
|
||||
const static int IRPT_DIS_IRQ_B = 9;
|
||||
const static int QA7_CORE0_TINTC = 16;
|
||||
const static int GPIO_IRQ = (32 + 20); // GPIO3
|
||||
|
||||
const static uint32_t IRPT_OFFSET = 0x0000B200;
|
||||
const static uint32_t PADS_OFFSET = 0x00100000;
|
||||
const static uint32_t GPIO_OFFSET = 0x00200000;
|
||||
const static uint32_t QA7_OFFSET = 0x01000000;
|
||||
};
|
@ -1,56 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// RaSCSI standard (SCSI logic, standard pin assignment)
|
||||
//
|
||||
|
||||
const std::string CONNECT_DESC = "STANDARD"; // Startup message
|
||||
|
||||
// Select signal control mode
|
||||
const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification
|
||||
|
||||
// Control signal pin assignment (-1 means no control)
|
||||
const static int PIN_ACT = 4; // ACTIVE
|
||||
const static int PIN_ENB = 5; // ENABLE
|
||||
const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION
|
||||
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
|
||||
const static int PIN_DTD = -1; // DATA DIRECTION
|
||||
|
||||
// Control signal output logic
|
||||
#define ACT_ON ON // ACTIVE SIGNAL ON
|
||||
#define ENB_ON ON // ENABLE SIGNAL ON
|
||||
#define IND_IN OFF // INITIATOR SIGNAL INPUT
|
||||
#define TAD_IN OFF // TARGET SIGNAL INPUT
|
||||
#define DTD_IN ON // DATA SIGNAL INPUT
|
||||
|
||||
// SCSI signal pin assignment
|
||||
const static int PIN_DT0 = 10; // Data 0
|
||||
const static int PIN_DT1 = 11; // Data 1
|
||||
const static int PIN_DT2 = 12; // Data 2
|
||||
const static int PIN_DT3 = 13; // Data 3
|
||||
const static int PIN_DT4 = 14; // Data 4
|
||||
const static int PIN_DT5 = 15; // Data 5
|
||||
const static int PIN_DT6 = 16; // Data 6
|
||||
const static int PIN_DT7 = 17; // Data 7
|
||||
const static int PIN_DP = 18; // Data parity
|
||||
const static int PIN_ATN = 19; // ATN
|
||||
const static int PIN_RST = 20; // RST
|
||||
const static int PIN_ACK = 21; // ACK
|
||||
const static int PIN_REQ = 22; // REQ
|
||||
const static int PIN_MSG = 23; // MSG
|
||||
const static int PIN_CD = 24; // CD
|
||||
const static int PIN_IO = 25; // IO
|
||||
const static int PIN_BSY = 26; // BSY
|
||||
const static int PIN_SEL = 27; // SEL
|
564
cpp/hal/gpiobus_virtual.cpp
Normal file
564
cpp/hal/gpiobus_virtual.cpp
Normal file
@ -0,0 +1,564 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
// [ GPIO-SCSI bus ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/gpiobus_virtual.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "shared/log.h"
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool GPIOBUS_Virtual::Init(mode_e mode)
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
GPIOBUS::Init(mode);
|
||||
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
// Create a shared memory region that can be accessed as a virtual "SCSI bus"
|
||||
// mutual exclusion semaphore, mutex_sem with an initial value 0.
|
||||
if ((mutex_sem = sem_open(SHARED_MEM_MUTEX_NAME.c_str(), O_CREAT, 0660, 0)) == SEM_FAILED) {
|
||||
LOGERROR("Unable to open shared memory semaphore %s. Are you running as root?", SHARED_MEM_MUTEX_NAME.c_str());
|
||||
}
|
||||
// Get shared memory
|
||||
if ((fd_shm = shm_open(SHARED_MEM_NAME.c_str(), O_RDWR | O_CREAT | O_EXCL, 0660)) == -1) {
|
||||
LOGERROR("Unable to open shared memory %s. Are you running as root?", SHARED_MEM_NAME.c_str());
|
||||
sem_close(mutex_sem);
|
||||
}
|
||||
if (ftruncate(fd_shm, sizeof(uint32_t)) == -1) {
|
||||
LOGERROR("Unable to read shared memory");
|
||||
sem_close(mutex_sem);
|
||||
shm_unlink(SHARED_MEM_NAME.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
signals = static_cast<uint32_t *>(mmap(NULL, sizeof(uint32_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0));
|
||||
if (static_cast<void *>(signals) == MAP_FAILED) {
|
||||
LOGERROR("Unabled to map shared memory");
|
||||
sem_close(mutex_sem);
|
||||
shm_unlink(SHARED_MEM_NAME.c_str());
|
||||
}
|
||||
#else
|
||||
signals = make_shared<uint32_t>(0);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::Cleanup()
|
||||
{
|
||||
// Set control signals
|
||||
PinSetSignal(PIN_ENB, OFF);
|
||||
PinSetSignal(PIN_ACT, OFF);
|
||||
PinSetSignal(PIN_TAD, OFF);
|
||||
PinSetSignal(PIN_IND, OFF);
|
||||
PinSetSignal(PIN_DTD, OFF);
|
||||
PinConfig(PIN_ACT, GPIO_INPUT);
|
||||
PinConfig(PIN_TAD, GPIO_INPUT);
|
||||
PinConfig(PIN_IND, GPIO_INPUT);
|
||||
PinConfig(PIN_DTD, GPIO_INPUT);
|
||||
|
||||
// Initialize all signals
|
||||
for (int i = 0; SignalTable[i] >= 0; i++) {
|
||||
int pin = SignalTable[i];
|
||||
PinSetSignal(pin, OFF);
|
||||
PinConfig(pin, GPIO_INPUT);
|
||||
PullConfig(pin, GPIO_PULLNONE);
|
||||
}
|
||||
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
munmap(static_cast<void *>(signals), sizeof(uint32_t));
|
||||
shm_unlink(SHARED_MEM_NAME.c_str());
|
||||
sem_close(mutex_sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::Reset()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
return;
|
||||
#else
|
||||
int i;
|
||||
int j;
|
||||
|
||||
// Turn off active signal
|
||||
SetControl(PIN_ACT, ACT_OFF);
|
||||
|
||||
// Set all signals to off
|
||||
for (i = 0;; i++) {
|
||||
j = SignalTable[i];
|
||||
if (j < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
SetSignal(j, OFF);
|
||||
}
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Target mode
|
||||
|
||||
// Set target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
|
||||
// Set the initiator signal to input
|
||||
SetControl(PIN_IND, IND_IN);
|
||||
SetMode(PIN_SEL, IN);
|
||||
SetMode(PIN_ATN, IN);
|
||||
SetMode(PIN_ACK, IN);
|
||||
SetMode(PIN_RST, IN);
|
||||
|
||||
// Set data bus signals to input
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
} else {
|
||||
// Initiator mode
|
||||
|
||||
// Set target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
|
||||
// Set the initiator signal to output
|
||||
SetControl(PIN_IND, IND_OUT);
|
||||
SetMode(PIN_SEL, OUT);
|
||||
SetMode(PIN_ATN, OUT);
|
||||
SetMode(PIN_ACK, OUT);
|
||||
SetMode(PIN_RST, OUT);
|
||||
|
||||
// Set the data bus signals to output
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
}
|
||||
|
||||
// Initialize all signals
|
||||
signals = 0;
|
||||
#endif // ifdef __x86_64__ || __X86__
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetENB(bool ast)
|
||||
{
|
||||
PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetBSY() const
|
||||
{
|
||||
return GetSignal(PIN_BSY);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetBSY(bool ast)
|
||||
{
|
||||
// Set BSY signal
|
||||
SetSignal(PIN_BSY, ast);
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
if (ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
|
||||
// Set Target signal to output
|
||||
SetControl(PIN_TAD, TAD_OUT);
|
||||
|
||||
SetMode(PIN_BSY, OUT);
|
||||
SetMode(PIN_MSG, OUT);
|
||||
SetMode(PIN_CD, OUT);
|
||||
SetMode(PIN_REQ, OUT);
|
||||
SetMode(PIN_IO, OUT);
|
||||
} else {
|
||||
// Turn off the ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_OFF);
|
||||
|
||||
// Set the target signal to input
|
||||
SetControl(PIN_TAD, TAD_IN);
|
||||
|
||||
SetMode(PIN_BSY, IN);
|
||||
SetMode(PIN_MSG, IN);
|
||||
SetMode(PIN_CD, IN);
|
||||
SetMode(PIN_REQ, IN);
|
||||
SetMode(PIN_IO, IN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetSEL() const
|
||||
{
|
||||
return GetSignal(PIN_SEL);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetSEL(bool ast)
|
||||
{
|
||||
if (actmode == mode_e::INITIATOR && ast) {
|
||||
// Turn on ACTIVE signal
|
||||
SetControl(PIN_ACT, ACT_ON);
|
||||
}
|
||||
|
||||
// Set SEL signal
|
||||
SetSignal(PIN_SEL, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetATN() const
|
||||
{
|
||||
return GetSignal(PIN_ATN);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetATN(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ATN, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetACK() const
|
||||
{
|
||||
return GetSignal(PIN_ACK);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetACK(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ACK, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetACT() const
|
||||
{
|
||||
return GetSignal(PIN_ACT);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetACT(bool ast)
|
||||
{
|
||||
SetSignal(PIN_ACT, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetRST() const
|
||||
{
|
||||
return GetSignal(PIN_RST);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetRST(bool ast)
|
||||
{
|
||||
SetSignal(PIN_RST, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetMSG() const
|
||||
{
|
||||
return GetSignal(PIN_MSG);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetMSG(bool ast)
|
||||
{
|
||||
SetSignal(PIN_MSG, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetCD() const
|
||||
{
|
||||
return GetSignal(PIN_CD);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetCD(bool ast)
|
||||
{
|
||||
SetSignal(PIN_CD, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetIO()
|
||||
{
|
||||
bool ast = GetSignal(PIN_IO);
|
||||
|
||||
if (actmode == mode_e::INITIATOR) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
} else {
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetIO(bool ast)
|
||||
{
|
||||
SetSignal(PIN_IO, ast);
|
||||
|
||||
if (actmode == mode_e::TARGET) {
|
||||
// Change the data input/output direction by IO signal
|
||||
if (ast) {
|
||||
SetControl(PIN_DTD, DTD_OUT);
|
||||
SetDAT(0);
|
||||
SetMode(PIN_DT0, OUT);
|
||||
SetMode(PIN_DT1, OUT);
|
||||
SetMode(PIN_DT2, OUT);
|
||||
SetMode(PIN_DT3, OUT);
|
||||
SetMode(PIN_DT4, OUT);
|
||||
SetMode(PIN_DT5, OUT);
|
||||
SetMode(PIN_DT6, OUT);
|
||||
SetMode(PIN_DT7, OUT);
|
||||
SetMode(PIN_DP, OUT);
|
||||
} else {
|
||||
SetControl(PIN_DTD, DTD_IN);
|
||||
SetMode(PIN_DT0, IN);
|
||||
SetMode(PIN_DT1, IN);
|
||||
SetMode(PIN_DT2, IN);
|
||||
SetMode(PIN_DT3, IN);
|
||||
SetMode(PIN_DT4, IN);
|
||||
SetMode(PIN_DT5, IN);
|
||||
SetMode(PIN_DT6, IN);
|
||||
SetMode(PIN_DT7, IN);
|
||||
SetMode(PIN_DP, IN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetREQ() const
|
||||
{
|
||||
return GetSignal(PIN_REQ);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::SetREQ(bool ast)
|
||||
{
|
||||
SetSignal(PIN_REQ, ast);
|
||||
}
|
||||
|
||||
bool GPIOBUS_Virtual::GetDP() const
|
||||
{
|
||||
return GetSignal(PIN_DP);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get data signals
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint8_t GPIOBUS_Virtual::GetDAT()
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
uint32_t data = Acquire();
|
||||
data = ((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));
|
||||
return (uint8_t)data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set data signals
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::SetDAT(uint8_t dat)
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
|
||||
auto new_dat = static_cast<byte>(dat);
|
||||
|
||||
PinSetSignal(PIN_DT0, (new_dat & ((byte)1 << 0)) != (byte)0);
|
||||
PinSetSignal(PIN_DT1, (new_dat & ((byte)1 << 1)) != (byte)0);
|
||||
PinSetSignal(PIN_DT2, (new_dat & ((byte)1 << 2)) != (byte)0);
|
||||
PinSetSignal(PIN_DT3, (new_dat & ((byte)1 << 3)) != (byte)0);
|
||||
PinSetSignal(PIN_DT4, (new_dat & ((byte)1 << 4)) != (byte)0);
|
||||
PinSetSignal(PIN_DT5, (new_dat & ((byte)1 << 5)) != (byte)0);
|
||||
PinSetSignal(PIN_DT6, (new_dat & ((byte)1 << 6)) != (byte)0);
|
||||
PinSetSignal(PIN_DT7, (new_dat & ((byte)1 << 7)) != (byte)0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Create work table
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::MakeTable(void)
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Control signal setting
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::SetControl(int pin, bool ast)
|
||||
{
|
||||
LOGTRACE("%s hwpin: %d", __PRETTY_FUNCTION__, (int)pin)
|
||||
PinSetSignal(pin, ast);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Input/output mode setting
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::SetMode(int hw_pin, int mode)
|
||||
{
|
||||
// Doesn't do anything for virtual gpio bus
|
||||
(void)hw_pin;
|
||||
(void)mode;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get input signal value
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool GPIOBUS_Virtual::GetSignal(int hw_pin) const
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
|
||||
uint32_t signal_value = 0;
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_wait(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to lock the shared memory")
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
signal_value = *signals;
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_post(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to release the shared memory")
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return (signal_value >> hw_pin) & 1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set output signal value
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::SetSignal(int hw_pin, bool ast)
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
PinSetSignal(hw_pin, ast);
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::DisableIRQ()
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
// Nothing to do for virtual gpio bus
|
||||
}
|
||||
|
||||
void GPIOBUS_Virtual::EnableIRQ()
|
||||
{
|
||||
GPIO_FUNCTION_TRACE
|
||||
// Nothing to do for virtual gpio bus
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set output pin
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::PinSetSignal(int hw_pin, bool ast)
|
||||
{
|
||||
LOGTRACE("%s hwpin: %d", __PRETTY_FUNCTION__, (int)hw_pin)
|
||||
|
||||
// Check for invalid pin
|
||||
if (hw_pin < 0) {
|
||||
return;
|
||||
}
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_wait(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to lock the shared memory")
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (ast) {
|
||||
// Set the "gpio" bit
|
||||
*signals |= 0x1 << hw_pin;
|
||||
} else {
|
||||
// Clear the "gpio" bit
|
||||
*signals ^= ~(0x1 << hw_pin);
|
||||
}
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_post(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to release the shared memory")
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Set the signal drive strength
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS_Virtual::DrvConfig(uint32_t drive)
|
||||
{
|
||||
(void)drive;
|
||||
// Nothing to do for virtual GPIO
|
||||
}
|
||||
|
||||
uint32_t GPIOBUS_Virtual::Acquire()
|
||||
{
|
||||
GPIO_FUNCTION_TRACE;
|
||||
|
||||
uint32_t signal_value = 0;
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_wait(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to lock the shared memory")
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
signal_value = *signals;
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
if (sem_post(mutex_sem) == -1) {
|
||||
LOGERROR("Unable to release the shared memory")
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return signal_value;
|
||||
}
|
||||
|
174
cpp/hal/gpiobus_virtual.h
Normal file
174
cpp/hal/gpiobus_virtual.h
Normal file
@ -0,0 +1,174 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// [ GPIO-SCSI bus ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/data_sample_raspberry.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "shared/log.h"
|
||||
#include "shared/scsi.h"
|
||||
|
||||
#include <map>
|
||||
#include <semaphore.h>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Class definition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
class GPIOBUS_Virtual final : public GPIOBUS
|
||||
{
|
||||
public:
|
||||
// Basic Functions
|
||||
GPIOBUS_Virtual() = default;
|
||||
~GPIOBUS_Virtual() override = default;
|
||||
// Destructor
|
||||
bool Init(mode_e mode = mode_e::TARGET) override;
|
||||
|
||||
// // Initialization
|
||||
void Reset() override;
|
||||
// Reset
|
||||
void Cleanup() override;
|
||||
// Cleanup
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Bus signal acquisition
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t Acquire() override;
|
||||
|
||||
void SetENB(bool ast) override;
|
||||
// Set ENB signal
|
||||
|
||||
bool GetBSY() const override;
|
||||
// Get BSY signal
|
||||
void SetBSY(bool ast) override;
|
||||
// Set BSY signal
|
||||
|
||||
bool GetSEL() const override;
|
||||
// Get SEL signal
|
||||
void SetSEL(bool ast) override;
|
||||
// Set SEL signal
|
||||
|
||||
bool GetATN() const override;
|
||||
// Get ATN signal
|
||||
void SetATN(bool ast) override;
|
||||
// Set ATN signal
|
||||
|
||||
bool GetACK() const override;
|
||||
// Get ACK signal
|
||||
void SetACK(bool ast) override;
|
||||
// Set ACK signal
|
||||
|
||||
bool GetACT() const override;
|
||||
// Get ACT signal
|
||||
void SetACT(bool ast) override;
|
||||
// Set ACT signal
|
||||
|
||||
bool GetRST() const override;
|
||||
// Get RST signal
|
||||
void SetRST(bool ast) override;
|
||||
// Set RST signal
|
||||
|
||||
bool GetMSG() const override;
|
||||
// Get MSG signal
|
||||
void SetMSG(bool ast) override;
|
||||
// Set MSG signal
|
||||
|
||||
bool GetCD() const override;
|
||||
// Get CD signal
|
||||
void SetCD(bool ast) override;
|
||||
// Set CD signal
|
||||
|
||||
bool GetIO() override;
|
||||
// Get IO signal
|
||||
void SetIO(bool ast) override;
|
||||
// Set IO signal
|
||||
|
||||
bool GetREQ() const override;
|
||||
// Get REQ signal
|
||||
void SetREQ(bool ast) override;
|
||||
// Set REQ signal
|
||||
|
||||
bool GetDP() const override;
|
||||
|
||||
bool WaitREQ(bool ast) override
|
||||
{
|
||||
return WaitSignal(PIN_REQ, ast);
|
||||
}
|
||||
bool WaitACK(bool ast) override
|
||||
{
|
||||
return WaitSignal(PIN_ACK, ast);
|
||||
}
|
||||
|
||||
uint8_t GetDAT() override;
|
||||
// Get DAT signal
|
||||
void SetDAT(uint8_t dat) override;
|
||||
// Set DAT signal
|
||||
private:
|
||||
// SCSI I/O signal control
|
||||
void MakeTable() override;
|
||||
// Create work data
|
||||
void SetControl(int pin, bool ast) override;
|
||||
// Set Control Signal
|
||||
void SetMode(int pin, int mode) override;
|
||||
// Set SCSI I/O mode
|
||||
int GetMode(int pin) override
|
||||
{
|
||||
// Not implemented (or needed for thist gpio bus type)
|
||||
(void)pin;
|
||||
return -1;
|
||||
}
|
||||
bool GetSignal(int pin) const override;
|
||||
// Get SCSI input signal value
|
||||
void SetSignal(int pin, bool ast) override;
|
||||
// Wait for a signal to change
|
||||
// Interrupt control
|
||||
void DisableIRQ() override;
|
||||
// IRQ Disabled
|
||||
void EnableIRQ() override;
|
||||
// IRQ Enabled
|
||||
|
||||
// GPIO pin functionality settings
|
||||
void PinConfig(int pin, int mode) override
|
||||
{
|
||||
(void)pin;
|
||||
(void)mode;
|
||||
}
|
||||
// GPIO pin direction setting
|
||||
void PullConfig(int pin, int mode) override
|
||||
{
|
||||
(void)mode; // Put these in opposite order so Sonar doesn't complain
|
||||
(void)pin; // That PinConfig and PullConfig are identical
|
||||
}
|
||||
// GPIO pin pull up/down resistor setting
|
||||
void PinSetSignal(int pin, bool ast) override;
|
||||
// Set GPIO output signal
|
||||
void DrvConfig(uint32_t drive) override;
|
||||
// Set GPIO drive strength
|
||||
|
||||
array<int, 19> SignalTable;
|
||||
shared_ptr<uint32_t> signals; // All bus signals
|
||||
|
||||
unique_ptr<DataSample> GetSample(uint64_t timestamp) override
|
||||
{
|
||||
return make_unique<DataSample_Raspberry>(*signals, timestamp);
|
||||
}
|
||||
|
||||
#ifdef SHARED_MEMORY_GPIO
|
||||
inline static const string SHARED_MEM_MUTEX_NAME = "/sem-mutex";
|
||||
inline static const string SHARED_MEM_NAME = "/posix-shared-mem-example";
|
||||
|
||||
sem_t *mutex_sem, *buffer_count_sem, *spool_signal_sem;
|
||||
int fd_shm, fd_log;
|
||||
#endif
|
||||
};
|
356
cpp/hal/pi_defs/bpi-gpio.h
Normal file
356
cpp/hal/pi_defs/bpi-gpio.h
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
Copyright (c) 2014-2017 Banana Pi
|
||||
Updates Copyright (C) 2022 akuker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
const int GPIO_NOT_USED = -1;
|
||||
|
||||
const int GPIO_PA00 = 0;
|
||||
const int GPIO_PA01 = 1;
|
||||
const int GPIO_PA02 = 2;
|
||||
const int GPIO_PA03 = 3;
|
||||
const int GPIO_PA04 = 4;
|
||||
const int GPIO_PA05 = 5;
|
||||
const int GPIO_PA06 = 6;
|
||||
const int GPIO_PA07 = 7;
|
||||
const int GPIO_PA08 = 8;
|
||||
const int GPIO_PA09 = 9;
|
||||
const int GPIO_PA10 = 10;
|
||||
const int GPIO_PA11 = 11;
|
||||
const int GPIO_PA12 = 12;
|
||||
const int GPIO_PA13 = 13;
|
||||
const int GPIO_PA14 = 14;
|
||||
const int GPIO_PA15 = 15;
|
||||
const int GPIO_PA16 = 16;
|
||||
const int GPIO_PA17 = 17;
|
||||
const int GPIO_PA18 = 18;
|
||||
const int GPIO_PA19 = 19;
|
||||
const int GPIO_PA20 = 20;
|
||||
const int GPIO_PA21 = 21;
|
||||
const int GPIO_PA22 = 22;
|
||||
const int GPIO_PA23 = 23;
|
||||
const int GPIO_PA24 = 24;
|
||||
const int GPIO_PA25 = 25;
|
||||
const int GPIO_PA26 = 26;
|
||||
const int GPIO_PA27 = 27;
|
||||
const int GPIO_PA28 = 28;
|
||||
const int GPIO_PA29 = 29;
|
||||
const int GPIO_PA30 = 30;
|
||||
const int GPIO_PA31 = 31;
|
||||
|
||||
const int GPIO_PB00 = 32;
|
||||
const int GPIO_PB01 = 1 + GPIO_PB00;
|
||||
const int GPIO_PB02 = 2 + GPIO_PB00;
|
||||
const int GPIO_PB03 = 3 + GPIO_PB00;
|
||||
const int GPIO_PB04 = 4 + GPIO_PB00;
|
||||
const int GPIO_PB05 = 5 + GPIO_PB00;
|
||||
const int GPIO_PB06 = 6 + GPIO_PB00;
|
||||
const int GPIO_PB07 = 7 + GPIO_PB00;
|
||||
const int GPIO_PB08 = 8 + GPIO_PB00;
|
||||
const int GPIO_PB09 = 9 + GPIO_PB00;
|
||||
const int GPIO_PB10 = 10 + GPIO_PB00;
|
||||
const int GPIO_PB11 = 11 + GPIO_PB00;
|
||||
const int GPIO_PB12 = 12 + GPIO_PB00;
|
||||
const int GPIO_PB13 = 13 + GPIO_PB00;
|
||||
const int GPIO_PB14 = 14 + GPIO_PB00;
|
||||
const int GPIO_PB15 = 15 + GPIO_PB00;
|
||||
const int GPIO_PB16 = 16 + GPIO_PB00;
|
||||
const int GPIO_PB17 = 17 + GPIO_PB00;
|
||||
const int GPIO_PB18 = 18 + GPIO_PB00;
|
||||
const int GPIO_PB19 = 19 + GPIO_PB00;
|
||||
const int GPIO_PB20 = 20 + GPIO_PB00;
|
||||
const int GPIO_PB21 = 21 + GPIO_PB00;
|
||||
const int GPIO_PB22 = 22 + GPIO_PB00;
|
||||
const int GPIO_PB23 = 23 + GPIO_PB00;
|
||||
const int GPIO_PB24 = 24 + GPIO_PB00;
|
||||
const int GPIO_PB25 = 25 + GPIO_PB00;
|
||||
const int GPIO_PB26 = 26 + GPIO_PB00;
|
||||
const int GPIO_PB27 = 27 + GPIO_PB00;
|
||||
const int GPIO_PB28 = 28 + GPIO_PB00;
|
||||
const int GPIO_PB29 = 29 + GPIO_PB00;
|
||||
const int GPIO_PB30 = 30 + GPIO_PB00;
|
||||
const int GPIO_PB31 = 31 + GPIO_PB00;
|
||||
|
||||
const int GPIO_PC00 = 64;
|
||||
const int GPIO_PC01 = 1 + GPIO_PC00;
|
||||
const int GPIO_PC02 = 2 + GPIO_PC00;
|
||||
const int GPIO_PC03 = 3 + GPIO_PC00;
|
||||
const int GPIO_PC04 = 4 + GPIO_PC00;
|
||||
const int GPIO_PC05 = 5 + GPIO_PC00;
|
||||
const int GPIO_PC06 = 6 + GPIO_PC00;
|
||||
const int GPIO_PC07 = 7 + GPIO_PC00;
|
||||
const int GPIO_PC08 = 8 + GPIO_PC00;
|
||||
const int GPIO_PC09 = 9 + GPIO_PC00;
|
||||
const int GPIO_PC10 = 10 + GPIO_PC00;
|
||||
const int GPIO_PC11 = 11 + GPIO_PC00;
|
||||
const int GPIO_PC12 = 12 + GPIO_PC00;
|
||||
const int GPIO_PC13 = 13 + GPIO_PC00;
|
||||
const int GPIO_PC14 = 14 + GPIO_PC00;
|
||||
const int GPIO_PC15 = 15 + GPIO_PC00;
|
||||
const int GPIO_PC16 = 16 + GPIO_PC00;
|
||||
const int GPIO_PC17 = 17 + GPIO_PC00;
|
||||
const int GPIO_PC18 = 18 + GPIO_PC00;
|
||||
const int GPIO_PC19 = 19 + GPIO_PC00;
|
||||
const int GPIO_PC20 = 20 + GPIO_PC00;
|
||||
const int GPIO_PC21 = 21 + GPIO_PC00;
|
||||
const int GPIO_PC22 = 22 + GPIO_PC00;
|
||||
const int GPIO_PC23 = 23 + GPIO_PC00;
|
||||
const int GPIO_PC24 = 24 + GPIO_PC00;
|
||||
const int GPIO_PC25 = 25 + GPIO_PC00;
|
||||
const int GPIO_PC26 = 26 + GPIO_PC00;
|
||||
const int GPIO_PC27 = 27 + GPIO_PC00;
|
||||
const int GPIO_PC28 = 28 + GPIO_PC00;
|
||||
const int GPIO_PC29 = 29 + GPIO_PC00;
|
||||
const int GPIO_PC30 = 30 + GPIO_PC00;
|
||||
const int GPIO_PC31 = 31 + GPIO_PC00;
|
||||
|
||||
const int GPIO_PD00 = 96;
|
||||
const int GPIO_PD01 = 1 + GPIO_PD00;
|
||||
const int GPIO_PD02 = 2 + GPIO_PD00;
|
||||
const int GPIO_PD03 = 3 + GPIO_PD00;
|
||||
const int GPIO_PD04 = 4 + GPIO_PD00;
|
||||
const int GPIO_PD05 = 5 + GPIO_PD00;
|
||||
const int GPIO_PD06 = 6 + GPIO_PD00;
|
||||
const int GPIO_PD07 = 7 + GPIO_PD00;
|
||||
const int GPIO_PD08 = 8 + GPIO_PD00;
|
||||
const int GPIO_PD09 = 9 + GPIO_PD00;
|
||||
const int GPIO_PD10 = 10 + GPIO_PD00;
|
||||
const int GPIO_PD11 = 11 + GPIO_PD00;
|
||||
const int GPIO_PD12 = 12 + GPIO_PD00;
|
||||
const int GPIO_PD13 = 13 + GPIO_PD00;
|
||||
const int GPIO_PD14 = 14 + GPIO_PD00;
|
||||
const int GPIO_PD15 = 15 + GPIO_PD00;
|
||||
const int GPIO_PD16 = 16 + GPIO_PD00;
|
||||
const int GPIO_PD17 = 17 + GPIO_PD00;
|
||||
const int GPIO_PD18 = 18 + GPIO_PD00;
|
||||
const int GPIO_PD19 = 19 + GPIO_PD00;
|
||||
const int GPIO_PD20 = 20 + GPIO_PD00;
|
||||
const int GPIO_PD21 = 21 + GPIO_PD00;
|
||||
const int GPIO_PD22 = 22 + GPIO_PD00;
|
||||
const int GPIO_PD23 = 23 + GPIO_PD00;
|
||||
const int GPIO_PD24 = 24 + GPIO_PD00;
|
||||
const int GPIO_PD25 = 25 + GPIO_PD00;
|
||||
const int GPIO_PD26 = 26 + GPIO_PD00;
|
||||
const int GPIO_PD27 = 27 + GPIO_PD00;
|
||||
const int GPIO_PD28 = 28 + GPIO_PD00;
|
||||
const int GPIO_PD29 = 29 + GPIO_PD00;
|
||||
const int GPIO_PD30 = 30 + GPIO_PD00;
|
||||
const int GPIO_PD31 = 31 + GPIO_PD00;
|
||||
|
||||
const int GPIO_PE00 = 128;
|
||||
const int GPIO_PE01 = 1 + GPIO_PE00;
|
||||
const int GPIO_PE02 = 2 + GPIO_PE00;
|
||||
const int GPIO_PE03 = 3 + GPIO_PE00;
|
||||
const int GPIO_PE04 = 4 + GPIO_PE00;
|
||||
const int GPIO_PE05 = 5 + GPIO_PE00;
|
||||
const int GPIO_PE06 = 6 + GPIO_PE00;
|
||||
const int GPIO_PE07 = 7 + GPIO_PE00;
|
||||
const int GPIO_PE08 = 8 + GPIO_PE00;
|
||||
const int GPIO_PE09 = 9 + GPIO_PE00;
|
||||
const int GPIO_PE10 = 10 + GPIO_PE00;
|
||||
const int GPIO_PE11 = 11 + GPIO_PE00;
|
||||
const int GPIO_PE12 = 12 + GPIO_PE00;
|
||||
const int GPIO_PE13 = 13 + GPIO_PE00;
|
||||
const int GPIO_PE14 = 14 + GPIO_PE00;
|
||||
const int GPIO_PE15 = 15 + GPIO_PE00;
|
||||
const int GPIO_PE16 = 16 + GPIO_PE00;
|
||||
const int GPIO_PE17 = 17 + GPIO_PE00;
|
||||
const int GPIO_PE18 = 18 + GPIO_PE00;
|
||||
const int GPIO_PE19 = 19 + GPIO_PE00;
|
||||
const int GPIO_PE20 = 20 + GPIO_PE00;
|
||||
const int GPIO_PE21 = 21 + GPIO_PE00;
|
||||
const int GPIO_PE22 = 22 + GPIO_PE00;
|
||||
const int GPIO_PE23 = 23 + GPIO_PE00;
|
||||
const int GPIO_PE24 = 24 + GPIO_PE00;
|
||||
const int GPIO_PE25 = 25 + GPIO_PE00;
|
||||
const int GPIO_PE26 = 26 + GPIO_PE00;
|
||||
const int GPIO_PE27 = 27 + GPIO_PE00;
|
||||
const int GPIO_PE28 = 28 + GPIO_PE00;
|
||||
const int GPIO_PE29 = 29 + GPIO_PE00;
|
||||
const int GPIO_PE30 = 30 + GPIO_PE00;
|
||||
const int GPIO_PE31 = 31 + GPIO_PE00;
|
||||
|
||||
const int GPIO_PG00 = 192;
|
||||
const int GPIO_PG01 = 1 + GPIO_PG00;
|
||||
const int GPIO_PG02 = 2 + GPIO_PG00;
|
||||
const int GPIO_PG03 = 3 + GPIO_PG00;
|
||||
const int GPIO_PG04 = 4 + GPIO_PG00;
|
||||
const int GPIO_PG05 = 5 + GPIO_PG00;
|
||||
const int GPIO_PG06 = 6 + GPIO_PG00;
|
||||
const int GPIO_PG07 = 7 + GPIO_PG00;
|
||||
const int GPIO_PG08 = 8 + GPIO_PG00;
|
||||
const int GPIO_PG09 = 9 + GPIO_PG00;
|
||||
const int GPIO_PG10 = 10 + GPIO_PG00;
|
||||
const int GPIO_PG11 = 11 + GPIO_PG00;
|
||||
const int GPIO_PG12 = 12 + GPIO_PG00;
|
||||
const int GPIO_PG13 = 13 + GPIO_PG00;
|
||||
const int GPIO_PG14 = 14 + GPIO_PG00;
|
||||
const int GPIO_PG15 = 15 + GPIO_PG00;
|
||||
const int GPIO_PG16 = 16 + GPIO_PG00;
|
||||
const int GPIO_PG17 = 17 + GPIO_PG00;
|
||||
const int GPIO_PG18 = 18 + GPIO_PG00;
|
||||
const int GPIO_PG19 = 19 + GPIO_PG00;
|
||||
const int GPIO_PG20 = 20 + GPIO_PG00;
|
||||
const int GPIO_PG21 = 21 + GPIO_PG00;
|
||||
const int GPIO_PG22 = 22 + GPIO_PG00;
|
||||
const int GPIO_PG23 = 23 + GPIO_PG00;
|
||||
const int GPIO_PG24 = 24 + GPIO_PG00;
|
||||
const int GPIO_PG25 = 25 + GPIO_PG00;
|
||||
const int GPIO_PG26 = 26 + GPIO_PG00;
|
||||
const int GPIO_PG27 = 27 + GPIO_PG00;
|
||||
const int GPIO_PG28 = 28 + GPIO_PG00;
|
||||
const int GPIO_PG29 = 29 + GPIO_PG00;
|
||||
const int GPIO_PG30 = 30 + GPIO_PG00;
|
||||
const int GPIO_PG31 = 31 + GPIO_PG00;
|
||||
|
||||
const int GPIO_PH00 = 224;
|
||||
const int GPIO_PH01 = 1 + GPIO_PH00;
|
||||
const int GPIO_PH02 = 2 + GPIO_PH00;
|
||||
const int GPIO_PH03 = 3 + GPIO_PH00;
|
||||
const int GPIO_PH04 = 4 + GPIO_PH00;
|
||||
const int GPIO_PH05 = 5 + GPIO_PH00;
|
||||
const int GPIO_PH06 = 6 + GPIO_PH00;
|
||||
const int GPIO_PH07 = 7 + GPIO_PH00;
|
||||
const int GPIO_PH08 = 8 + GPIO_PH00;
|
||||
const int GPIO_PH09 = 9 + GPIO_PH00;
|
||||
const int GPIO_PH10 = 10 + GPIO_PH00;
|
||||
const int GPIO_PH11 = 11 + GPIO_PH00;
|
||||
const int GPIO_PH12 = 12 + GPIO_PH00;
|
||||
const int GPIO_PH13 = 13 + GPIO_PH00;
|
||||
const int GPIO_PH14 = 14 + GPIO_PH00;
|
||||
const int GPIO_PH15 = 15 + GPIO_PH00;
|
||||
const int GPIO_PH16 = 16 + GPIO_PH00;
|
||||
const int GPIO_PH17 = 17 + GPIO_PH00;
|
||||
const int GPIO_PH18 = 18 + GPIO_PH00;
|
||||
const int GPIO_PH19 = 19 + GPIO_PH00;
|
||||
const int GPIO_PH20 = 20 + GPIO_PH00;
|
||||
const int GPIO_PH21 = 21 + GPIO_PH00;
|
||||
const int GPIO_PH22 = 22 + GPIO_PH00;
|
||||
const int GPIO_PH23 = 23 + GPIO_PH00;
|
||||
const int GPIO_PH24 = 24 + GPIO_PH00;
|
||||
const int GPIO_PH25 = 25 + GPIO_PH00;
|
||||
const int GPIO_PH26 = 26 + GPIO_PH00;
|
||||
const int GPIO_PH27 = 27 + GPIO_PH00;
|
||||
const int GPIO_PH28 = 28 + GPIO_PH00;
|
||||
const int GPIO_PH29 = 29 + GPIO_PH00;
|
||||
const int GPIO_PH30 = 30 + GPIO_PH00;
|
||||
const int GPIO_PH31 = 31 + GPIO_PH00;
|
||||
|
||||
const int GPIO_PI00 = 256;
|
||||
const int GPIO_PI01 = 1 + GPIO_PI00;
|
||||
const int GPIO_PI02 = 2 + GPIO_PI00;
|
||||
const int GPIO_PI03 = 3 + GPIO_PI00;
|
||||
const int GPIO_PI04 = 4 + GPIO_PI00;
|
||||
const int GPIO_PI05 = 5 + GPIO_PI00;
|
||||
const int GPIO_PI06 = 6 + GPIO_PI00;
|
||||
const int GPIO_PI07 = 7 + GPIO_PI00;
|
||||
const int GPIO_PI08 = 8 + GPIO_PI00;
|
||||
const int GPIO_PI09 = 9 + GPIO_PI00;
|
||||
const int GPIO_PI10 = 10 + GPIO_PI00;
|
||||
const int GPIO_PI11 = 11 + GPIO_PI00;
|
||||
const int GPIO_PI12 = 12 + GPIO_PI00;
|
||||
const int GPIO_PI13 = 13 + GPIO_PI00;
|
||||
const int GPIO_PI14 = 14 + GPIO_PI00;
|
||||
const int GPIO_PI15 = 15 + GPIO_PI00;
|
||||
const int GPIO_PI16 = 16 + GPIO_PI00;
|
||||
const int GPIO_PI17 = 17 + GPIO_PI00;
|
||||
const int GPIO_PI18 = 18 + GPIO_PI00;
|
||||
const int GPIO_PI19 = 19 + GPIO_PI00;
|
||||
const int GPIO_PI20 = 20 + GPIO_PI00;
|
||||
const int GPIO_PI21 = 21 + GPIO_PI00;
|
||||
const int GPIO_PI22 = 22 + GPIO_PI00;
|
||||
const int GPIO_PI23 = 23 + GPIO_PI00;
|
||||
const int GPIO_PI24 = 24 + GPIO_PI00;
|
||||
const int GPIO_PI25 = 25 + GPIO_PI00;
|
||||
const int GPIO_PI26 = 26 + GPIO_PI00;
|
||||
const int GPIO_PI27 = 27 + GPIO_PI00;
|
||||
const int GPIO_PI28 = 28 + GPIO_PI00;
|
||||
const int GPIO_PI29 = 29 + GPIO_PI00;
|
||||
const int GPIO_PI30 = 30 + GPIO_PI00;
|
||||
const int GPIO_PI31 = 31 + GPIO_PI00;
|
||||
|
||||
const int GPIO_PL00 = 352;
|
||||
const int GPIO_PL01 = 1 + GPIO_PL00;
|
||||
const int GPIO_PL02 = 2 + GPIO_PL00;
|
||||
const int GPIO_PL03 = 3 + GPIO_PL00;
|
||||
const int GPIO_PL04 = 4 + GPIO_PL00;
|
||||
const int GPIO_PL05 = 5 + GPIO_PL00;
|
||||
const int GPIO_PL06 = 6 + GPIO_PL00;
|
||||
const int GPIO_PL07 = 7 + GPIO_PL00;
|
||||
const int GPIO_PL08 = 8 + GPIO_PL00;
|
||||
const int GPIO_PL09 = 9 + GPIO_PL00;
|
||||
const int GPIO_PL10 = 10 + GPIO_PL00;
|
||||
const int GPIO_PL11 = 11 + GPIO_PL00;
|
||||
const int GPIO_PL12 = 12 + GPIO_PL00;
|
||||
const int GPIO_PL13 = 13 + GPIO_PL00;
|
||||
const int GPIO_PL14 = 14 + GPIO_PL00;
|
||||
const int GPIO_PL15 = 15 + GPIO_PL00;
|
||||
const int GPIO_PL16 = 16 + GPIO_PL00;
|
||||
const int GPIO_PL17 = 17 + GPIO_PL00;
|
||||
const int GPIO_PL18 = 18 + GPIO_PL00;
|
||||
const int GPIO_PL19 = 19 + GPIO_PL00;
|
||||
const int GPIO_PL20 = 20 + GPIO_PL00;
|
||||
const int GPIO_PL21 = 21 + GPIO_PL00;
|
||||
const int GPIO_PL22 = 22 + GPIO_PL00;
|
||||
const int GPIO_PL23 = 23 + GPIO_PL00;
|
||||
const int GPIO_PL24 = 24 + GPIO_PL00;
|
||||
const int GPIO_PL25 = 25 + GPIO_PL00;
|
||||
const int GPIO_PL26 = 26 + GPIO_PL00;
|
||||
const int GPIO_PL27 = 27 + GPIO_PL00;
|
||||
const int GPIO_PL28 = 28 + GPIO_PL00;
|
||||
const int GPIO_PL29 = 29 + GPIO_PL00;
|
||||
const int GPIO_PL30 = 30 + GPIO_PL00;
|
||||
const int GPIO_PL31 = 31 + GPIO_PL00;
|
||||
|
||||
const int GPIO_PM00 = 384;
|
||||
const int GPIO_PM01 = 1 + GPIO_PM00;
|
||||
const int GPIO_PM02 = 2 + GPIO_PM00;
|
||||
const int GPIO_PM03 = 3 + GPIO_PM00;
|
||||
const int GPIO_PM04 = 4 + GPIO_PM00;
|
||||
const int GPIO_PM05 = 5 + GPIO_PM00;
|
||||
const int GPIO_PM06 = 6 + GPIO_PM00;
|
||||
const int GPIO_PM07 = 7 + GPIO_PM00;
|
||||
const int GPIO_PM08 = 8 + GPIO_PM00;
|
||||
const int GPIO_PM09 = 9 + GPIO_PM00;
|
||||
const int GPIO_PM10 = 10 + GPIO_PM00;
|
||||
const int GPIO_PM11 = 11 + GPIO_PM00;
|
||||
const int GPIO_PM12 = 12 + GPIO_PM00;
|
||||
const int GPIO_PM13 = 13 + GPIO_PM00;
|
||||
const int GPIO_PM14 = 14 + GPIO_PM00;
|
||||
const int GPIO_PM15 = 15 + GPIO_PM00;
|
||||
const int GPIO_PM16 = 16 + GPIO_PM00;
|
||||
const int GPIO_PM17 = 17 + GPIO_PM00;
|
||||
const int GPIO_PM18 = 18 + GPIO_PM00;
|
||||
const int GPIO_PM19 = 19 + GPIO_PM00;
|
||||
const int GPIO_PM20 = 20 + GPIO_PM00;
|
||||
const int GPIO_PM21 = 21 + GPIO_PM00;
|
||||
const int GPIO_PM22 = 22 + GPIO_PM00;
|
||||
const int GPIO_PM23 = 23 + GPIO_PM00;
|
||||
const int GPIO_PM24 = 24 + GPIO_PM00;
|
||||
const int GPIO_PM25 = 25 + GPIO_PM00;
|
||||
const int GPIO_PM26 = 26 + GPIO_PM00;
|
||||
const int GPIO_PM27 = 27 + GPIO_PM00;
|
||||
const int GPIO_PM28 = 28 + GPIO_PM00;
|
||||
const int GPIO_PM29 = 29 + GPIO_PM00;
|
||||
const int GPIO_PM30 = 30 + GPIO_PM00;
|
||||
const int GPIO_PM31 = 31 + GPIO_PM00;
|
71
cpp/hal/pi_defs/bpi-m2p.h
Executable file
71
cpp/hal/pi_defs/bpi-m2p.h
Executable file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (c) 2014-2017 Banana Pi
|
||||
Updates Copyright (C) 2022 akuker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/pi_defs/bpi-gpio.h"
|
||||
|
||||
/* The following define the mapping of the Banana Pi CPU pins to the logical
|
||||
* GPIO numbers. The GPIO numbers are used by the software to set/configure
|
||||
* the CPU registers. */
|
||||
const int BPI_M2P_01 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_03 = GPIO_PA12;
|
||||
const int BPI_M2P_05 = GPIO_PA11;
|
||||
const int BPI_M2P_07 = GPIO_PA06;
|
||||
const int BPI_M2P_09 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_11 = GPIO_PA01;
|
||||
const int BPI_M2P_13 = GPIO_PA00;
|
||||
const int BPI_M2P_15 = GPIO_PA03;
|
||||
const int BPI_M2P_17 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_19 = GPIO_PC00;
|
||||
const int BPI_M2P_21 = GPIO_PC01;
|
||||
const int BPI_M2P_23 = GPIO_PC02;
|
||||
const int BPI_M2P_25 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_27 = GPIO_PA19;
|
||||
const int BPI_M2P_29 = GPIO_PA07;
|
||||
const int BPI_M2P_31 = GPIO_PA08;
|
||||
const int BPI_M2P_33 = GPIO_PA09;
|
||||
const int BPI_M2P_35 = GPIO_PA10;
|
||||
const int BPI_M2P_37 = GPIO_PA17;
|
||||
const int BPI_M2P_39 = GPIO_NOT_USED;
|
||||
|
||||
const int BPI_M2P_02 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_04 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_06 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_08 = GPIO_PA13;
|
||||
const int BPI_M2P_10 = GPIO_PA14;
|
||||
const int BPI_M2P_12 = GPIO_PA16;
|
||||
const int BPI_M2P_14 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_16 = GPIO_PA15;
|
||||
const int BPI_M2P_18 = GPIO_PC04;
|
||||
const int BPI_M2P_20 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_22 = GPIO_PA02;
|
||||
const int BPI_M2P_24 = GPIO_PC03;
|
||||
const int BPI_M2P_26 = GPIO_PC07;
|
||||
const int BPI_M2P_28 = GPIO_PA18;
|
||||
const int BPI_M2P_30 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_32 = GPIO_PL02;
|
||||
const int BPI_M2P_34 = GPIO_NOT_USED;
|
||||
const int BPI_M2P_36 = GPIO_PL04;
|
||||
const int BPI_M2P_38 = GPIO_PA21;
|
||||
const int BPI_M2P_40 = GPIO_PA20;
|
68
cpp/hal/pin_control.h
Normal file
68
cpp/hal/pin_control.h
Normal file
@ -0,0 +1,68 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#pragma once
|
||||
|
||||
// Virtual functions that must be implemented by the derived gpiobus classes
|
||||
// to control the GPIO pins
|
||||
class PinControl
|
||||
{
|
||||
public:
|
||||
virtual bool GetBSY() const = 0;
|
||||
virtual void SetBSY(bool ast) = 0;
|
||||
|
||||
virtual bool GetSEL() const = 0;
|
||||
virtual void SetSEL(bool ast) = 0;
|
||||
|
||||
virtual bool GetATN() const = 0;
|
||||
virtual void SetATN(bool ast) = 0;
|
||||
|
||||
virtual bool GetACK() const = 0;
|
||||
virtual void SetACK(bool ast) = 0;
|
||||
|
||||
virtual bool GetRST() const = 0;
|
||||
virtual void SetRST(bool ast) = 0;
|
||||
|
||||
virtual bool GetMSG() const = 0;
|
||||
virtual void SetMSG(bool ast) = 0;
|
||||
|
||||
virtual bool GetCD() const = 0;
|
||||
virtual void SetCD(bool ast) = 0;
|
||||
|
||||
virtual bool GetIO() = 0;
|
||||
virtual void SetIO(bool ast) = 0;
|
||||
|
||||
virtual bool GetREQ() const = 0;
|
||||
virtual void SetREQ(bool ast) = 0;
|
||||
|
||||
virtual bool GetACT() const = 0;
|
||||
virtual void SetACT(bool ast) = 0;
|
||||
|
||||
virtual uint8_t GetDAT() = 0;
|
||||
virtual void SetDAT(uint8_t dat) = 0;
|
||||
|
||||
// Set ENB signal
|
||||
virtual void SetENB(bool ast) = 0;
|
||||
|
||||
// Get parity signal
|
||||
virtual bool GetDP() const = 0;
|
||||
|
||||
// GPIO pin direction setting
|
||||
virtual void PinConfig(int pin, int mode) = 0;
|
||||
// GPIO pin pull up/down resistor setting
|
||||
virtual void PullConfig(int pin, int mode) = 0;
|
||||
|
||||
virtual void SetControl(int pin, bool ast) = 0;
|
||||
virtual void SetMode(int pin, int mode) = 0;
|
||||
|
||||
PinControl() = default;
|
||||
virtual ~PinControl() = default;
|
||||
};
|
226
cpp/hal/sbc_version.cpp
Normal file
226
cpp/hal/sbc_version.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Hardware version detection routines ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "sbc_version.h"
|
||||
#include "shared/log.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
SBC_Version::sbc_version_type SBC_Version::m_sbc_version = sbc_version_type::sbc_unknown;
|
||||
|
||||
// TODO: THESE NEED TO BE VALIDATED!!!!
|
||||
const std::string SBC_Version::m_str_raspberry_pi_1 = "Raspberry Pi 1";
|
||||
const std::string SBC_Version::m_str_raspberry_pi_2_3 = "Raspberry Pi 2/3";
|
||||
const std::string SBC_Version::m_str_raspberry_pi_4 = "Raspberry Pi 4";
|
||||
const std::string SBC_Version::m_str_bananapi_m1_plus = "Banana Pi M1 Plus";
|
||||
const std::string SBC_Version::m_str_bananapi_m2_berry = "Banana Pi M2 Berry/Ultra";
|
||||
const std::string SBC_Version::m_str_bananapi_m2_zero = "Banana Pi M2 Zero";
|
||||
const std::string SBC_Version::m_str_bananapi_m2_plus = "Banana Pi BPI-M2-Plus H3";
|
||||
const std::string SBC_Version::m_str_bananapi_m3 = "Banana Pi M3";
|
||||
const std::string SBC_Version::m_str_bananapi_m4 = "Banana Pi M4";
|
||||
const std::string SBC_Version::m_str_bananapi_m5 = "Banana Pi M5";
|
||||
const std::string SBC_Version::m_str_bananapi_m64 = "Banana Pi M64";
|
||||
const std::string SBC_Version::m_str_unknown_sbc = "Unknown SBC";
|
||||
|
||||
// The strings in this table should align with the 'model' embedded
|
||||
// in the device tree. This can be aquired by running:
|
||||
// cat /proc/device-tree/model
|
||||
// Only the first part of the string is checked. Anything following
|
||||
// will be ignored. For example:
|
||||
// "Raspberry Pi 4 Model B" will match with both of the following:
|
||||
// - Raspberry Pi 4 Model B Rev 1.4
|
||||
// - Raspberry Pi 4 Model B Rev 1.3
|
||||
const std::map<std::string, SBC_Version::sbc_version_type, std::less<>> SBC_Version::m_proc_device_tree_mapping = {
|
||||
{"Raspberry Pi 1 Model ", sbc_version_type::sbc_raspberry_pi_1},
|
||||
{"Raspberry Pi 2 Model ", sbc_version_type::sbc_raspberry_pi_2_3},
|
||||
{"Raspberry Pi 3 Model ", sbc_version_type::sbc_raspberry_pi_2_3},
|
||||
{"Raspberry Pi 4 Model ", sbc_version_type::sbc_raspberry_pi_4},
|
||||
{"Raspberry Pi 400 ", sbc_version_type::sbc_raspberry_pi_4},
|
||||
{"Raspberry Pi Zero W", sbc_version_type::sbc_raspberry_pi_1},
|
||||
{"Raspberry Pi Zero", sbc_version_type::sbc_raspberry_pi_1},
|
||||
{"Banana Pi BPI-M2-Zero ", sbc_version_type::sbc_bananapi_m2_zero},
|
||||
{"Banana Pi BPI-M2-Ultra ", sbc_version_type::sbc_bananapi_m2_berry},
|
||||
{"Banana Pi BPI-M2-Plus H3", sbc_version_type::sbc_bananapi_m2_plus},
|
||||
{"Banana Pi M2 Berry ", sbc_version_type::sbc_bananapi_m2_berry},
|
||||
// sbc_bananapi_m3, TBD....
|
||||
// sbc_bananapi_m4,
|
||||
};
|
||||
|
||||
const std::string SBC_Version::m_device_tree_model_path = "/proc/device-tree/model";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Convert the SBC Version to a printable string
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const std::string *SBC_Version::GetString()
|
||||
{
|
||||
switch (m_sbc_version) {
|
||||
case sbc_version_type::sbc_raspberry_pi_1:
|
||||
return &m_str_raspberry_pi_1;
|
||||
case sbc_version_type::sbc_raspberry_pi_2_3:
|
||||
return &m_str_raspberry_pi_2_3;
|
||||
case sbc_version_type::sbc_raspberry_pi_4:
|
||||
return &m_str_raspberry_pi_4;
|
||||
case sbc_version_type::sbc_bananapi_m2_berry:
|
||||
return &m_str_bananapi_m2_berry;
|
||||
case sbc_version_type::sbc_bananapi_m2_zero:
|
||||
return &m_str_bananapi_m2_zero;
|
||||
case sbc_version_type::sbc_bananapi_m2_plus:
|
||||
return &m_str_bananapi_m2_plus;
|
||||
case sbc_version_type::sbc_bananapi_m3:
|
||||
return &m_str_bananapi_m3;
|
||||
case sbc_version_type::sbc_bananapi_m4:
|
||||
return &m_str_bananapi_m4;
|
||||
default:
|
||||
LOGERROR("Unknown type of sbc detected: %d", static_cast<int>(m_sbc_version))
|
||||
return &m_str_unknown_sbc;
|
||||
}
|
||||
}
|
||||
|
||||
SBC_Version::sbc_version_type SBC_Version::GetSbcVersion()
|
||||
{
|
||||
return m_sbc_version;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Determine which version of single board computer (Pi) is being used
|
||||
// based upon the device tree model string.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SBC_Version::Init()
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
std::string device_tree_model;
|
||||
|
||||
const std::ifstream input_stream(SBC_Version::m_device_tree_model_path);
|
||||
|
||||
if (input_stream.fail()) {
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
// We expect this to fail on x86
|
||||
LOGINFO("Detected device %s", GetString()->c_str())
|
||||
m_sbc_version = sbc_version_type::sbc_unknown;
|
||||
return;
|
||||
#else
|
||||
LOGERROR("Failed to open %s. Are you running as root?", SBC_Version::m_device_tree_model_path.c_str())
|
||||
throw std::invalid_argument("Failed to open /proc/device-tree/model");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::stringstream str_buffer;
|
||||
str_buffer << input_stream.rdbuf();
|
||||
device_tree_model = str_buffer.str();
|
||||
|
||||
for (const auto &[key, value] : m_proc_device_tree_mapping) {
|
||||
if (device_tree_model.rfind(key, 0) == 0) {
|
||||
m_sbc_version = value;
|
||||
LOGINFO("Detected device %s", GetString()->c_str())
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOGERROR("%s Unable to determine single board computer type. Defaulting to Raspberry Pi 4", __PRETTY_FUNCTION__)
|
||||
m_sbc_version = sbc_version_type::sbc_raspberry_pi_4;
|
||||
}
|
||||
|
||||
bool SBC_Version::IsRaspberryPi()
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
switch (m_sbc_version) {
|
||||
case sbc_version_type::sbc_raspberry_pi_1:
|
||||
case sbc_version_type::sbc_raspberry_pi_2_3:
|
||||
case sbc_version_type::sbc_raspberry_pi_4:
|
||||
return true;
|
||||
case sbc_version_type::sbc_bananapi_m2_berry:
|
||||
case sbc_version_type::sbc_bananapi_m2_zero:
|
||||
case sbc_version_type::sbc_bananapi_m2_plus:
|
||||
case sbc_version_type::sbc_bananapi_m3:
|
||||
case sbc_version_type::sbc_bananapi_m4:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SBC_Version::IsBananaPi()
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
switch (m_sbc_version) {
|
||||
case sbc_version_type::sbc_raspberry_pi_1:
|
||||
case sbc_version_type::sbc_raspberry_pi_2_3:
|
||||
case sbc_version_type::sbc_raspberry_pi_4:
|
||||
return false;
|
||||
case sbc_version_type::sbc_bananapi_m2_berry:
|
||||
case sbc_version_type::sbc_bananapi_m2_zero:
|
||||
case sbc_version_type::sbc_bananapi_m2_plus:
|
||||
case sbc_version_type::sbc_bananapi_m3:
|
||||
case sbc_version_type::sbc_bananapi_m4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The following functions are only used on the Raspberry Pi
|
||||
// (imported from bcm_host.c)
|
||||
uint32_t SBC_Version::GetDeviceTreeRanges(const char *filename, uint32_t offset)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
uint32_t address = ~0;
|
||||
if (FILE *fp = fopen(filename, "rb"); fp) {
|
||||
fseek(fp, offset, SEEK_SET);
|
||||
if (std::array<uint8_t, 4> buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) {
|
||||
address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
#if defined __linux__
|
||||
uint32_t SBC_Version::GetPeripheralAddress(void)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
uint32_t address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 4);
|
||||
if (address == 0) {
|
||||
address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 8);
|
||||
}
|
||||
address = (address == (uint32_t)~0) ? 0x20000000 : address;
|
||||
|
||||
LOGDEBUG("Peripheral address : 0x%8x\n", address)
|
||||
|
||||
return address;
|
||||
}
|
||||
#elif defined __NetBSD__
|
||||
uint32_t SBC_Version::GetPeripheralAddress(void)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t len = sizeof(buf);
|
||||
uint32_t address;
|
||||
|
||||
if (sysctlbyname("hw.model", buf, &len, NULL, 0) || strstr(buf, "ARM1176JZ-S") != buf) {
|
||||
// Failed to get CPU model || Not BCM2835
|
||||
// use the address of BCM283[67]
|
||||
address = 0x3f000000;
|
||||
} else {
|
||||
// Use BCM2835 address
|
||||
address = 0x20000000;
|
||||
}
|
||||
LOGDEBUG("Peripheral address : 0x%lx\n", address);
|
||||
return address;
|
||||
}
|
||||
#else
|
||||
uint32_t SBC_Version::GetPeripheralAddress(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
78
cpp/hal/sbc_version.h
Normal file
78
cpp/hal/sbc_version.h
Normal file
@ -0,0 +1,78 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Hardware version detection routines ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Single Board Computer Versions
|
||||
//
|
||||
//===========================================================================
|
||||
class SBC_Version
|
||||
{
|
||||
public:
|
||||
// Type of Single Board Computer
|
||||
enum class sbc_version_type : uint8_t {
|
||||
sbc_unknown = 0,
|
||||
sbc_raspberry_pi_1,
|
||||
sbc_raspberry_pi_2_3,
|
||||
sbc_raspberry_pi_4,
|
||||
sbc_bananapi_m1_plus,
|
||||
sbc_bananapi_m2_ultra,
|
||||
sbc_bananapi_m2_berry,
|
||||
sbc_bananapi_m2_zero,
|
||||
sbc_bananapi_m2_plus,
|
||||
sbc_bananapi_m3,
|
||||
sbc_bananapi_m4,
|
||||
sbc_bananapi_m5,
|
||||
sbc_bananapi_m64,
|
||||
};
|
||||
|
||||
SBC_Version() = delete;
|
||||
~SBC_Version() = delete;
|
||||
|
||||
static void Init();
|
||||
|
||||
static sbc_version_type GetSbcVersion();
|
||||
|
||||
static bool IsRaspberryPi();
|
||||
static bool IsBananaPi();
|
||||
|
||||
static const std::string *GetString();
|
||||
|
||||
static uint32_t GetPeripheralAddress();
|
||||
|
||||
private:
|
||||
static sbc_version_type m_sbc_version;
|
||||
|
||||
static const std::string m_str_raspberry_pi_1;
|
||||
static const std::string m_str_raspberry_pi_2_3;
|
||||
static const std::string m_str_raspberry_pi_4;
|
||||
static const std::string m_str_bananapi_m1_plus;
|
||||
static const std::string m_str_bananapi_m2_ultra;
|
||||
static const std::string m_str_bananapi_m2_berry;
|
||||
static const std::string m_str_bananapi_m2_zero;
|
||||
static const std::string m_str_bananapi_m2_plus;
|
||||
static const std::string m_str_bananapi_m3;
|
||||
static const std::string m_str_bananapi_m4;
|
||||
static const std::string m_str_bananapi_m5;
|
||||
static const std::string m_str_bananapi_m64;
|
||||
static const std::string m_str_unknown_sbc;
|
||||
|
||||
static const std::map<std::string, sbc_version_type, std::less<>> m_proc_device_tree_mapping;
|
||||
|
||||
static const std::string m_device_tree_model_path;
|
||||
|
||||
static uint32_t GetDeviceTreeRanges(const char *filename, uint32_t offset);
|
||||
};
|
65
cpp/hal/sunxi_utils.cpp
Normal file
65
cpp/hal/sunxi_utils.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Utility functions for working with Allwinner CPUs ]
|
||||
//
|
||||
// This should include generic functions that can be applicable to
|
||||
// different variants of the SunXI (Allwinner) SoCs
|
||||
//
|
||||
// Large portions of this functionality were derived from c_gpio.c, which
|
||||
// is part of the RPI.GPIO library available here:
|
||||
// https://github.com/BPI-SINOVOIP/RPi.GPIO/blob/master/source/c_gpio.c
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/sunxi_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const string BLACK = "\033[30m"; /* Black */
|
||||
static const string RED = "\033[31m"; /* Red */
|
||||
static const string GREEN = "\033[32m"; /* Green */
|
||||
static const string YELLOW = "\033[33m"; /* Yellow */
|
||||
static const string BLUE = "\033[34m"; /* Blue */
|
||||
static const string MAGENTA = "\033[35m"; /* Magenta */
|
||||
static const string CYAN = "\033[36m"; /* Cyan */
|
||||
static const string WHITE = "\033[37m"; /* White */
|
||||
|
||||
// TODO: this is only a debug function that will be removed at a later date.....
|
||||
void dump_gpio_registers(const SunXI::sunxi_gpio_reg_t *regs)
|
||||
{
|
||||
printf("%s--- GPIO BANK 0 CFG: %08X %08X %08X %08X\n", CYAN.c_str(), regs->gpio_bank[0].CFG[0],
|
||||
regs->gpio_bank[0].CFG[1], regs->gpio_bank[0].CFG[2], regs->gpio_bank[0].CFG[3]);
|
||||
|
||||
printf("--- Dat: (%08X) DRV: %08X %08X\n", regs->gpio_bank[0].DAT, regs->gpio_bank[0].DRV[0],
|
||||
regs->gpio_bank[0].DRV[1]);
|
||||
printf("--- Pull: %08X %08x\n", regs->gpio_bank[0].PULL[0], regs->gpio_bank[0].PULL[1]);
|
||||
|
||||
printf("--- GPIO INT CFG: %08X %08X %08X\n", regs->gpio_int.CFG[0], regs->gpio_int.CFG[1], regs->gpio_int.CFG[2]);
|
||||
printf("--- CTL: (%08X) STA: %08X DEB: %08X\n %s", regs->gpio_int.CTL, regs->gpio_int.STA, regs->gpio_int.DEB,
|
||||
WHITE.c_str());
|
||||
}
|
189
cpp/hal/sunxi_utils.h
Normal file
189
cpp/hal/sunxi_utils.h
Normal file
@ -0,0 +1,189 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Utility functions for working with Allwinner CPUs ]
|
||||
//
|
||||
// This should include generic functions that can be applicable to
|
||||
// different variants of the SunXI (Allwinner) SoCs
|
||||
//
|
||||
// Large portions of this functionality were derived from c_gpio.c, which
|
||||
// is part of the RPI.GPIO library available here:
|
||||
// https://github.com/BPI-SINOVOIP/RPi.GPIO/blob/master/source/c_gpio.c
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#ifndef __arm__
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
class SunXI
|
||||
{
|
||||
public:
|
||||
static inline int GPIO_BANK(int pin)
|
||||
{
|
||||
return (pin >> 5);
|
||||
}
|
||||
static inline int GPIO_NUM(int pin)
|
||||
{
|
||||
return (pin & 0x1F);
|
||||
}
|
||||
static inline int GPIO_CFG_INDEX(int pin)
|
||||
{
|
||||
return ((pin & 0x1F) >> 3);
|
||||
}
|
||||
static inline int GPIO_CFG_OFFSET(int pin)
|
||||
{
|
||||
return (((pin & 0x1F) & 0x7) << 2);
|
||||
}
|
||||
static inline int GPIO_PUL_INDEX(int pin)
|
||||
{
|
||||
return ((pin & 0x1F) >> 4);
|
||||
}
|
||||
static inline int GPIO_PUL_OFFSET(int pin)
|
||||
{
|
||||
return ((pin & 0x0F) << 1);
|
||||
}
|
||||
static inline int GPIO_DRV_INDEX(int pin)
|
||||
{
|
||||
return ((pin & 0x1F) >> 4);
|
||||
}
|
||||
static inline int GPIO_DRV_OFFSET(int pin)
|
||||
{
|
||||
return ((pin & 0x0F) << 1);
|
||||
}
|
||||
|
||||
static inline void short_wait(void)
|
||||
{
|
||||
for (int i = 0; i < 150; i++) {
|
||||
#ifndef __arm__
|
||||
// Timing doesn't really matter if we're not on ARM.
|
||||
// The SunXI SoCs are all ARM-based.
|
||||
const timespec ts = {.tv_sec = 0, .tv_nsec = 1};
|
||||
nanosleep(&ts, nullptr);
|
||||
#else
|
||||
// wait 150 cycles
|
||||
asm volatile("nop");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
enum class gpio_configure_values_e : uint8_t {
|
||||
gpio_input = 0b000,
|
||||
gpio_output = 0b001,
|
||||
gpio_alt_func_1 = 0b010,
|
||||
gpio_alt_func_2 = 0b011,
|
||||
gpio_reserved_1 = 0b100,
|
||||
gpio_reserved_2 = 0b101,
|
||||
gpio_interupt = 0b110,
|
||||
gpio_disable = 0b111
|
||||
};
|
||||
|
||||
struct sunxi_gpio {
|
||||
unsigned int CFG[4]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
unsigned int DAT;
|
||||
unsigned int DRV[2]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
unsigned int PULL[2]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
};
|
||||
using sunxi_gpio_t = struct sunxi_gpio;
|
||||
|
||||
/* gpio interrupt control */
|
||||
struct sunxi_gpio_int {
|
||||
unsigned int CFG[3]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
unsigned int CTL;
|
||||
unsigned int STA;
|
||||
unsigned int DEB;
|
||||
};
|
||||
using sunxi_gpio_int_t = struct sunxi_gpio_int;
|
||||
|
||||
struct sunxi_gpio_reg {
|
||||
struct sunxi_gpio gpio_bank[9]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
unsigned char res[0xbc]; // NOSONAR: Intentionally using C style arrays for low level register access
|
||||
struct sunxi_gpio_int gpio_int;
|
||||
};
|
||||
using sunxi_gpio_reg_t = struct sunxi_gpio_reg;
|
||||
|
||||
static const uint32_t PAGE_SIZE = (4 * 1024);
|
||||
static const uint32_t BLOCK_SIZE = (4 * 1024);
|
||||
|
||||
static const int SETUP_DEVMEM_FAIL = 1;
|
||||
static const int SETUP_MALLOC_FAIL = 2;
|
||||
static const int SETUP_MMAP_FAIL = 3;
|
||||
static const int SETUP_CPUINFO_FAIL = 4;
|
||||
static const int SETUP_NOT_RPI_FAIL = 5;
|
||||
static const int INPUT = 1;
|
||||
static const int OUTPUT = 0;
|
||||
static const int ALT0 = 4;
|
||||
static const int HIGH = 1;
|
||||
static const int LOW = 0;
|
||||
static const int PUD_OFF = 0;
|
||||
static const int PUD_DOWN = 1;
|
||||
static const int PUD_UP = 2;
|
||||
|
||||
static const uint32_t SUNXI_R_GPIO_BASE = 0x01F02000;
|
||||
static const uint32_t SUNXI_R_GPIO_REG_OFFSET = 0xC00;
|
||||
static const uint32_t SUNXI_GPIO_BASE = 0x01C20000;
|
||||
static const uint32_t SUNXI_GPIO_REG_OFFSET = 0x800;
|
||||
static const uint32_t SUNXI_CFG_OFFSET = 0x00;
|
||||
static const uint32_t SUNXI_DATA_OFFSET = 0x10;
|
||||
static const uint32_t SUNXI_PUD_OFFSET = 0x1C;
|
||||
static const uint32_t SUNXI_BANK_SIZE = 0x24;
|
||||
|
||||
static const uint32_t MAP_SIZE = (4096 * 2);
|
||||
static const uint32_t MAP_MASK = (MAP_SIZE - 1);
|
||||
|
||||
static const int FSEL_OFFSET = 0; // 0x0000
|
||||
static const int SET_OFFSET = 7; // 0x001c / 4
|
||||
static const int CLR_OFFSET = 10; // 0x0028 / 4
|
||||
static const int PINLEVEL_OFFSET = 13; // 0x0034 / 4
|
||||
static const int EVENT_DETECT_OFFSET = 16; // 0x0040 / 4
|
||||
static const int RISING_ED_OFFSET = 19; // 0x004c / 4
|
||||
static const int FALLING_ED_OFFSET = 22; // 0x0058 / 4
|
||||
static const int HIGH_DETECT_OFFSET = 25; // 0x0064 / 4
|
||||
static const int LOW_DETECT_OFFSET = 28; // 0x0070 / 4
|
||||
static const int PULLUPDN_OFFSET = 37; // 0x0094 / 4
|
||||
static const int PULLUPDNCLK_OFFSET = 38; // 0x0098 / 4
|
||||
|
||||
static const uint32_t TMR_REGISTER_BASE = 0x01C20C00;
|
||||
static const uint32_t TMR_IRQ_EN_REG = 0x0; // T imer IRQ Enable Register
|
||||
static const uint32_t TMR_IRQ_STA_REG = 0x4; // Timer Status Register
|
||||
static const uint32_t TMR0_CTRL_REG = 0x10; // Timer 0 Control Register
|
||||
static const uint32_t TMR0_INTV_VALUE_REG = 0x14; // Timer 0 Interval Value Register
|
||||
static const uint32_t TMR0_CUR_VALUE_REG = 0x18; // Timer 0 Current Value Register
|
||||
static const uint32_t TMR1_CTRL_REG = 0x20; // Timer 1 Control Register
|
||||
static const uint32_t TMR1_INTV_VALUE_REG = 0x24; // Timer 1 Interval Value Register
|
||||
static const uint32_t TMR1_CUR_VALUE_REG = 0x28; // Timer 1 Current Value Register
|
||||
static const uint32_t AVS_CNT_CTL_REG = 0x80; // AVS Control Register
|
||||
static const uint32_t AVS_CNT0_REG = 0x84; // AVS Counter 0 Register
|
||||
static const uint32_t AVS_CNT1_REG = 0x88; // AVS Counter 1 Register
|
||||
static const uint32_t AVS_CNT_DIV_REG = 0x8C; // AVS Divisor Register
|
||||
static const uint32_t WDOG0_IRQ_EN_REG = 0xA0; // Watchdog 0 IRQ Enable Register
|
||||
static const uint32_t WDOG0_IRQ_STA_REG = 0xA4; // Watchdog 0 Status Register
|
||||
static const uint32_t WDOG0_CTRL_REG = 0xB0; // Watchdog 0 Control Register
|
||||
static const uint32_t WDOG0_CFG_REG = 0xB4; // Watchdog 0 Configuration Register
|
||||
static const uint32_t WDOG0_MODE_REG = 0xB8; // Watchdog 0 Mode Register
|
||||
};
|
@ -12,129 +12,55 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/systimer.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "shared/config.h"
|
||||
#include "hal/systimer_allwinner.h"
|
||||
#include "hal/systimer_raspberry.h"
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// System timer address
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
volatile uint32_t* SysTimer::systaddr;
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/sbc_version.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ARM timer address
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
volatile uint32_t* SysTimer::armtaddr;
|
||||
#include "shared/log.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Core frequency
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
volatile uint32_t SysTimer::corefreq;
|
||||
bool SysTimer::initialized = false;
|
||||
bool SysTimer::is_allwinnner = false;
|
||||
bool SysTimer::is_raspberry = false;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Initialize the system timer
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer::Init(uint32_t *syst, uint32_t *armt)
|
||||
std::unique_ptr<PlatformSpecificTimer> SysTimer::systimer_ptr;
|
||||
|
||||
void SysTimer::Init()
|
||||
{
|
||||
// RPI Mailbox property interface
|
||||
// Get max clock rate
|
||||
// Tag: 0x00030004
|
||||
//
|
||||
// Request: Length: 4
|
||||
// Value: u32: clock id
|
||||
// Response: Length: 8
|
||||
// Value: u32: clock id, u32: rate (in Hz)
|
||||
//
|
||||
// Clock id
|
||||
// 0x000000004: CORE
|
||||
array<uint32_t, 32> maxclock = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
// Save the base address
|
||||
systaddr = syst;
|
||||
armtaddr = armt;
|
||||
|
||||
// Change the ARM timer to free run mode
|
||||
armtaddr[ARMT_CTRL] = 0x00000282;
|
||||
|
||||
// Get the core frequency
|
||||
corefreq = 0;
|
||||
int fd = open("/dev/vcio", O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
ioctl(fd, _IOWR(100, 0, char *), maxclock);
|
||||
corefreq = maxclock[6] / 1000000;
|
||||
if (!initialized) {
|
||||
if (SBC_Version::IsRaspberryPi()) {
|
||||
systimer_ptr = make_unique<SysTimer_Raspberry>();
|
||||
is_raspberry = true;
|
||||
} else if (SBC_Version::IsBananaPi()) {
|
||||
systimer_ptr = make_unique<SysTimer_AllWinner>();
|
||||
is_allwinnner = true;
|
||||
}
|
||||
systimer_ptr->Init();
|
||||
initialized = true;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get system timer low byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t SysTimer::GetTimerLow() {
|
||||
return systaddr[SYST_CLO];
|
||||
uint32_t SysTimer::GetTimerLow()
|
||||
{
|
||||
return systimer_ptr->GetTimerLow();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get system timer high byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t SysTimer::GetTimerHigh() {
|
||||
return systaddr[SYST_CHI];
|
||||
uint32_t SysTimer::GetTimerHigh()
|
||||
{
|
||||
return systimer_ptr->GetTimerHigh();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in nanoseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
// Sleep for N nanoseconds
|
||||
void SysTimer::SleepNsec(uint32_t nsec)
|
||||
{
|
||||
// If time is 0, don't do anything
|
||||
if (nsec == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the timer difference
|
||||
uint32_t diff = corefreq * nsec / 1000;
|
||||
|
||||
// Return if the difference in time is too small
|
||||
if (diff == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start
|
||||
uint32_t start = armtaddr[ARMT_FREERUN];
|
||||
|
||||
// Loop until timer has elapsed
|
||||
while ((armtaddr[ARMT_FREERUN] - start) < diff);
|
||||
systimer_ptr->SleepNsec(nsec);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in microseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
// Sleep for N microseconds
|
||||
void SysTimer::SleepUsec(uint32_t usec)
|
||||
{
|
||||
// If time is 0, don't do anything
|
||||
if (usec == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t now = GetTimerLow();
|
||||
while ((GetTimerLow() - now) < usec);
|
||||
systimer_ptr->SleepUsec(usec);
|
||||
}
|
||||
|
@ -13,11 +13,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "shared/config.h"
|
||||
#include "shared/scsi.h"
|
||||
|
||||
class PlatformSpecificTimer
|
||||
{
|
||||
public:
|
||||
// Default constructor
|
||||
PlatformSpecificTimer() = default;
|
||||
// Default destructor
|
||||
virtual ~PlatformSpecificTimer() = default;
|
||||
// Initialization
|
||||
virtual void Init() = 0;
|
||||
// Get system timer low byte
|
||||
virtual uint32_t GetTimerLow() = 0;
|
||||
// Get system timer high byte
|
||||
virtual uint32_t GetTimerHigh() = 0;
|
||||
// Sleep for N nanoseconds
|
||||
virtual void SleepNsec(uint32_t nsec) = 0;
|
||||
// Sleep for N microseconds
|
||||
virtual void SleepUsec(uint32_t usec) = 0;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// System timer
|
||||
@ -25,23 +44,21 @@
|
||||
//===========================================================================
|
||||
class SysTimer
|
||||
{
|
||||
public:
|
||||
static void Init(uint32_t *syst, uint32_t *armt);
|
||||
// Initialization
|
||||
static uint32_t GetTimerLow();
|
||||
public:
|
||||
static void Init();
|
||||
// Get system timer low byte
|
||||
static uint32_t GetTimerHigh();
|
||||
static uint32_t GetTimerLow();
|
||||
// Get system timer high byte
|
||||
static void SleepNsec(uint32_t nsec);
|
||||
static uint32_t GetTimerHigh();
|
||||
// Sleep for N nanoseconds
|
||||
static void SleepUsec(uint32_t usec);
|
||||
static void SleepNsec(uint32_t nsec);
|
||||
// Sleep for N microseconds
|
||||
static void SleepUsec(uint32_t usec);
|
||||
|
||||
private:
|
||||
static volatile uint32_t *systaddr;
|
||||
// System timer address
|
||||
static volatile uint32_t *armtaddr;
|
||||
// ARM timer address
|
||||
static volatile uint32_t corefreq;
|
||||
// Core frequency
|
||||
private:
|
||||
static bool initialized;
|
||||
static bool is_allwinnner;
|
||||
static bool is_raspberry;
|
||||
|
||||
static std::unique_ptr<PlatformSpecificTimer> systimer_ptr;
|
||||
};
|
||||
|
155
cpp/hal/systimer_allwinner.cpp
Normal file
155
cpp/hal/systimer_allwinner.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ High resolution timer for the Allwinner series of SoC's]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/systimer_allwinner.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "hal/gpiobus.h"
|
||||
|
||||
#include "shared/log.h"
|
||||
|
||||
const std::string SysTimer_AllWinner::dev_mem_filename = "/dev/mem";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Initialize the system timer
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_AllWinner::Init()
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
int fd;
|
||||
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
|
||||
LOGERROR("I can't open /dev/mem. Are you running as root?")
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
hsitimer_regs =
|
||||
(sun8i_hsitimer_registers *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, hs_timer_base_address);
|
||||
|
||||
if (hsitimer_regs == MAP_FAILED) {
|
||||
LOGERROR("Unable to map high speed timer registers. Are you running as root?")
|
||||
}
|
||||
|
||||
sysbus_regs = (struct sun8i_sysbus_registers *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||
system_bus_base_address);
|
||||
|
||||
if (sysbus_regs == MAP_FAILED) {
|
||||
LOGERROR("Unable to map system bus registers. Are you running as root?")
|
||||
}
|
||||
|
||||
enable_hs_timer();
|
||||
}
|
||||
|
||||
void SysTimer_AllWinner::enable_hs_timer()
|
||||
{
|
||||
// By default, the HSTimer clock gating is masked. When it is necessary to use
|
||||
// the HSTimer, its clock gating should be opened in BUS Clock Gating Register 0
|
||||
// and then de-assert the software reset in BUS Software Reset Register 0 on the
|
||||
// CCU module. If it is not needed to use the HSTimer, both the gating bit and
|
||||
// the software reset bit should be set 0.
|
||||
|
||||
LOGTRACE("%s [Before Enable] CLK GATE: %08X SOFT RST: %08X", __PRETTY_FUNCTION__, sysbus_regs->bus_clk_gating_reg0,
|
||||
sysbus_regs->bus_soft_rst_reg0)
|
||||
|
||||
sysbus_regs->bus_clk_gating_reg0 = sysbus_regs->bus_clk_gating_reg0 | (1 << BUS_CLK_GATING_REG0_HSTMR);
|
||||
sysbus_regs->bus_soft_rst_reg0 = sysbus_regs->bus_soft_rst_reg0 | (1 << BUS_SOFT_RST_REG0_HSTMR);
|
||||
LOGTRACE("%s [After Enable] CLK GATE: %08X SOFT RST: %08X", __PRETTY_FUNCTION__, sysbus_regs->bus_clk_gating_reg0,
|
||||
sysbus_regs->bus_soft_rst_reg0)
|
||||
|
||||
// Set interval value to the maximum value. (its a 52 bit register)
|
||||
hsitimer_regs->hs_tmr_intv_hi_reg = (1 << 20) - 1; //(0xFFFFF)
|
||||
hsitimer_regs->hs_tmr_intv_lo_reg = UINT32_MAX;
|
||||
|
||||
// Select prescale value of 1, continuouse mode
|
||||
hsitimer_regs->hs_tmr_ctrl_reg = HS_TMR_CLK_PRE_SCALE_1;
|
||||
|
||||
// Set reload bit
|
||||
hsitimer_regs->hs_tmr_ctrl_reg |= HS_TMR_RELOAD;
|
||||
|
||||
// Enable HSTimer
|
||||
hsitimer_regs->hs_tmr_ctrl_reg |= HS_TMR_EN;
|
||||
}
|
||||
|
||||
// TODO: According to the data sheet, we should turn off the HS timer when we're done with it. But, its just going to
|
||||
// eat up a little extra power if we leave it running.
|
||||
void SysTimer_AllWinner::disable_hs_timer()
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
LOGINFO("[Before Disable] CLK GATE: %08X SOFT RST: %08X", sysbus_regs->bus_clk_gating_reg0,
|
||||
sysbus_regs->bus_soft_rst_reg0)
|
||||
|
||||
sysbus_regs->bus_clk_gating_reg0 = sysbus_regs->bus_clk_gating_reg0 & ~(1 << BUS_CLK_GATING_REG0_HSTMR);
|
||||
sysbus_regs->bus_soft_rst_reg0 = sysbus_regs->bus_soft_rst_reg0 & ~(1 << BUS_SOFT_RST_REG0_HSTMR);
|
||||
|
||||
LOGINFO("[After Disable] CLK GATE: %08X SOFT RST: %08X", sysbus_regs->bus_clk_gating_reg0,
|
||||
sysbus_regs->bus_soft_rst_reg0)
|
||||
}
|
||||
|
||||
uint32_t SysTimer_AllWinner::GetTimerLow()
|
||||
{
|
||||
// RaSCSI expects the timer to count UP, but the Allwinner HS timer counts
|
||||
// down. So, we subtract the current timer value from UINT32_MAX
|
||||
return UINT32_MAX - (hsitimer_regs->hs_tmr_curnt_lo_reg / 200);
|
||||
}
|
||||
|
||||
uint32_t SysTimer_AllWinner::GetTimerHigh()
|
||||
{
|
||||
return (uint32_t)0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in nanoseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_AllWinner::SleepNsec(uint32_t nsec)
|
||||
{
|
||||
// If time is less than one HS timer clock tick, don't do anything
|
||||
if (nsec < 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The HS timer receives a 200MHz clock input, which equates to
|
||||
// one clock tick every 5 ns.
|
||||
auto clockticks = (uint32_t)std::ceil(nsec / 5);
|
||||
|
||||
uint32_t enter_time = hsitimer_regs->hs_tmr_curnt_lo_reg;
|
||||
|
||||
// TODO: NEED TO HANDLE COUNTER OVERFLOW
|
||||
LOGTRACE("%s entertime: %08X ns: %d clockticks: %d", __PRETTY_FUNCTION__, enter_time, nsec, clockticks)
|
||||
while ((enter_time - hsitimer_regs->hs_tmr_curnt_lo_reg) < clockticks)
|
||||
;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in microseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_AllWinner::SleepUsec(uint32_t usec)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
// If time is 0, don't do anything
|
||||
if (usec == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t enter_time = GetTimerLow();
|
||||
while ((GetTimerLow() - enter_time) < usec)
|
||||
;
|
||||
}
|
106
cpp/hal/systimer_allwinner.h
Normal file
106
cpp/hal/systimer_allwinner.h
Normal file
@ -0,0 +1,106 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ High resolution timer ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "systimer.h"
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// System timer
|
||||
//
|
||||
//===========================================================================
|
||||
class SysTimer_AllWinner : public PlatformSpecificTimer
|
||||
{
|
||||
public:
|
||||
// Default constructor
|
||||
SysTimer_AllWinner() = default;
|
||||
// Default destructor
|
||||
~SysTimer_AllWinner() override = default;
|
||||
// Initialization
|
||||
void Init() override;
|
||||
// Get system timer low byte
|
||||
uint32_t GetTimerLow() override;
|
||||
// Get system timer high byte
|
||||
uint32_t GetTimerHigh() override;
|
||||
// Sleep for N nanoseconds
|
||||
void SleepNsec(uint32_t nsec) override;
|
||||
// Sleep for N microseconds
|
||||
void SleepUsec(uint32_t usec) override;
|
||||
|
||||
private:
|
||||
void enable_hs_timer();
|
||||
void disable_hs_timer();
|
||||
|
||||
static const std::string dev_mem_filename;
|
||||
|
||||
/* Reference: Allwinner H3 Datasheet, section 4.9.3 */
|
||||
static const uint32_t hs_timer_base_address = 0x01C60000;
|
||||
/* Note: Currently the high speed timer is NOT in the armbian
|
||||
* device tree. If it is ever added, this should be pulled
|
||||
* from there */
|
||||
|
||||
using sun8i_hsitimer_registers = struct {
|
||||
/* 0x00 HS Timer IRQ Enabled Register */
|
||||
uint32_t hs_tmr_irq_en_reg;
|
||||
/* 0x04 HS Timer Status Register */
|
||||
uint32_t hs_tmr_irq_stat_reg;
|
||||
/* 0x08 Unused */
|
||||
uint32_t unused_08;
|
||||
/* 0x0C Unused */
|
||||
uint32_t unused_0C;
|
||||
/* 0x10 HS Timer Control Register */
|
||||
uint32_t hs_tmr_ctrl_reg;
|
||||
/* 0x14 HS Timer Interval Value Low Reg */
|
||||
uint32_t hs_tmr_intv_lo_reg;
|
||||
/* 0x18 HS Timer Interval Value High Register */
|
||||
uint32_t hs_tmr_intv_hi_reg;
|
||||
/* 0x1C HS Timer Current Value Low Register */
|
||||
uint32_t hs_tmr_curnt_lo_reg;
|
||||
/* 0x20 HS Timer Current Value High Register */
|
||||
uint32_t hs_tmr_curnt_hi_reg;
|
||||
};
|
||||
|
||||
/* Constants for the HS Timer IRQ enable Register (section 4.9.4.1) */
|
||||
static const uint32_t HS_TMR_INTERUPT_ENB = (1 << 0);
|
||||
|
||||
/* Constants for the HS Timer Control Register (section 4.9.4.3) */
|
||||
static const uint32_t HS_TMR_EN = (1 << 0);
|
||||
static const uint32_t HS_TMR_RELOAD = (1 << 1);
|
||||
static const uint32_t HS_TMR_CLK_PRE_SCALE_1 = (0 << 4);
|
||||
static const uint32_t HS_TMR_CLK_PRE_SCALE_2 = (1 << 4);
|
||||
static const uint32_t HS_TMR_CLK_PRE_SCALE_4 = (2 << 4);
|
||||
static const uint32_t HS_TMR_CLK_PRE_SCALE_8 = (3 << 4);
|
||||
static const uint32_t HS_TMR_CLK_PRE_SCALE_16 = (4 << 4); // NOSONAR This matches the datasheet
|
||||
static const uint32_t HS_TMR_MODE_SINGLE = (1 << 7);
|
||||
static const uint32_t HS_TMR_TEST_MODE = (1 << 31);
|
||||
|
||||
volatile sun8i_hsitimer_registers *hsitimer_regs;
|
||||
|
||||
/* Reference: Allwinner H3 Datasheet, section 4.3.4 */
|
||||
static const uint32_t system_bus_base_address = 0x01C20000;
|
||||
|
||||
struct sun8i_sysbus_registers {
|
||||
uint32_t pad_00_5C[(0x60 / sizeof(uint32_t))]; // NOSONAR c-style array used for padding
|
||||
/* 0x0060 Bus Clock Gating Register 0 */
|
||||
uint32_t bus_clk_gating_reg0;
|
||||
uint32_t pad_64_2C0[((0x2C0 - 0x64) / sizeof(uint32_t))]; // NOSONAR c-style array used for padding
|
||||
/* 0x2C0 Bus Software Reset Register 0 */
|
||||
uint32_t bus_soft_rst_reg0;
|
||||
};
|
||||
|
||||
/* Bit associated with the HS Timer */
|
||||
static const uint32_t BUS_CLK_GATING_REG0_HSTMR = 19;
|
||||
static const uint32_t BUS_SOFT_RST_REG0_HSTMR = 19;
|
||||
|
||||
struct sun8i_sysbus_registers *sysbus_regs;
|
||||
};
|
147
cpp/hal/systimer_raspberry.cpp
Normal file
147
cpp/hal/systimer_raspberry.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ High resolution timer ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/systimer_raspberry.h"
|
||||
#include <memory>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/sbc_version.h"
|
||||
|
||||
#include "shared/log.h"
|
||||
|
||||
// System timer address
|
||||
volatile uint32_t *SysTimer_Raspberry::systaddr = nullptr;
|
||||
// ARM timer address
|
||||
volatile uint32_t *SysTimer_Raspberry::armtaddr = nullptr;
|
||||
volatile uint32_t SysTimer_Raspberry::corefreq = 0;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Initialize the system timer
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_Raspberry::Init()
|
||||
{
|
||||
// Get the base address
|
||||
auto baseaddr = SBC_Version::GetPeripheralAddress();
|
||||
|
||||
// Open /dev/mem
|
||||
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (mem_fd == -1) {
|
||||
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?")
|
||||
return;
|
||||
}
|
||||
|
||||
// Map peripheral region memory
|
||||
void *map = mmap(nullptr, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, baseaddr);
|
||||
if (map == MAP_FAILED) {
|
||||
LOGERROR("Error: Unable to map memory")
|
||||
close(mem_fd);
|
||||
return;
|
||||
}
|
||||
close(mem_fd);
|
||||
|
||||
// RPI Mailbox property interface
|
||||
// Get max clock rate
|
||||
// Tag: 0x00030004
|
||||
//
|
||||
// Request: Length: 4
|
||||
// Value: u32: clock id
|
||||
// Response: Length: 8
|
||||
// Value: u32: clock id, u32: rate (in Hz)
|
||||
//
|
||||
// Clock id
|
||||
// 0x000000004: CORE
|
||||
std::array<uint32_t, 32> maxclock = {32, 0, 0x00030004, 8, 0, 4, 0, 0};
|
||||
|
||||
// Save the base address
|
||||
systaddr = (uint32_t *)map + SYST_OFFSET / sizeof(uint32_t);
|
||||
armtaddr = (uint32_t *)map + ARMT_OFFSET / sizeof(uint32_t);
|
||||
|
||||
// Change the ARM timer to free run mode
|
||||
armtaddr[ARMT_CTRL] = 0x00000282;
|
||||
|
||||
// Get the core frequency
|
||||
if (int vcio_fd = open("/dev/vcio", O_RDONLY); vcio_fd >= 0) {
|
||||
ioctl(vcio_fd, _IOWR(100, 0, char *), maxclock.data());
|
||||
corefreq = maxclock[6] / 1000000;
|
||||
close(vcio_fd);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get system timer low byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t SysTimer_Raspberry::GetTimerLow()
|
||||
{
|
||||
return systaddr[SYST_CLO];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get system timer high byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t SysTimer_Raspberry::GetTimerHigh()
|
||||
{
|
||||
return systaddr[SYST_CHI];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in nanoseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_Raspberry::SleepNsec(uint32_t nsec)
|
||||
{
|
||||
// If time is 0, don't do anything
|
||||
if (nsec == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the timer difference
|
||||
uint32_t diff = corefreq * nsec / 1000;
|
||||
|
||||
// Return if the difference in time is too small
|
||||
if (diff == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start
|
||||
uint32_t start = armtaddr[ARMT_FREERUN];
|
||||
|
||||
// Loop until timer has elapsed
|
||||
while ((armtaddr[ARMT_FREERUN] - start) < diff)
|
||||
;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Sleep in microseconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SysTimer_Raspberry::SleepUsec(uint32_t usec)
|
||||
{
|
||||
// If time is 0, don't do anything
|
||||
if (usec == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t now = GetTimerLow();
|
||||
while ((GetTimerLow() - now) < usec)
|
||||
;
|
||||
}
|
70
cpp/hal/systimer_raspberry.h
Normal file
70
cpp/hal/systimer_raspberry.h
Normal file
@ -0,0 +1,70 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ High resolution timer ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "systimer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// System timer
|
||||
//
|
||||
//===========================================================================
|
||||
class SysTimer_Raspberry : public PlatformSpecificTimer
|
||||
{
|
||||
public:
|
||||
// Default constructor
|
||||
SysTimer_Raspberry() = default;
|
||||
// Default destructor
|
||||
~SysTimer_Raspberry() override = default;
|
||||
// Initialization
|
||||
void Init() override;
|
||||
// Get system timer low byte
|
||||
uint32_t GetTimerLow() override;
|
||||
// Get system timer high byte
|
||||
uint32_t GetTimerHigh() override;
|
||||
// Sleep for N nanoseconds
|
||||
void SleepNsec(uint32_t nsec) override;
|
||||
// Sleep for N microseconds
|
||||
void SleepUsec(uint32_t usec) override;
|
||||
|
||||
private:
|
||||
// System timer address
|
||||
static volatile uint32_t *systaddr;
|
||||
// ARM timer address
|
||||
static volatile uint32_t *armtaddr;
|
||||
// Core frequency
|
||||
static volatile uint32_t corefreq;
|
||||
|
||||
const static int ARMT_LOAD = 0;
|
||||
const static int ARMT_VALUE = 1;
|
||||
const static int ARMT_CTRL = 2;
|
||||
const static int ARMT_CLRIRQ = 3;
|
||||
const static int ARMT_RAWIRQ = 4;
|
||||
const static int ARMT_MSKIRQ = 5;
|
||||
const static int ARMT_RELOAD = 6;
|
||||
const static int ARMT_PREDIV = 7;
|
||||
const static int ARMT_FREERUN = 8;
|
||||
|
||||
const static int SYST_CS = 0;
|
||||
const static int SYST_CLO = 1;
|
||||
const static int SYST_CHI = 2;
|
||||
const static int SYST_C0 = 3;
|
||||
const static int SYST_C1 = 4;
|
||||
const static int SYST_C2 = 5;
|
||||
const static int SYST_C3 = 6;
|
||||
|
||||
const static uint32_t SYST_OFFSET = 0x00003000;
|
||||
const static uint32_t ARMT_OFFSET = 0x0000B400;
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "shared/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::phase_t::selection;
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetBsy(sample))
|
||||
{
|
||||
return BUS::phase_t::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
uint32_t mci = GetMsg(sample) ? 0x04 : 0x00;
|
||||
mci |= GetCd(sample) ? 0x02 : 0x00;
|
||||
mci |= GetIo(sample) ? 0x01 : 0x00;
|
||||
return BUS::GetPhase(mci);
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/scsi.h"
|
||||
#include "hal/gpiobus.h"
|
||||
|
||||
using data_capture_t = struct data_capture
|
||||
{
|
||||
uint32_t data;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
#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 uint8_t GetData(const data_capture *sample)
|
||||
{
|
||||
uint32_t data = sample->data;
|
||||
return (uint8_t)((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);
|
@ -5,23 +5,24 @@
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2021-2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "shared/log.h"
|
||||
#include "shared/rasutil.h"
|
||||
#include "shared/rascsi_version.h"
|
||||
#include "hal/gpiobus_factory.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "monitor/sm_reports.h"
|
||||
#include "monitor/sm_core.h"
|
||||
#include "monitor/data_sample.h"
|
||||
#include <sys/time.h>
|
||||
#include "hal/data_sample.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/gpiobus_factory.h"
|
||||
#include "monitor/sm_reports.h"
|
||||
#include "shared/log.h"
|
||||
#include "shared/rascsi_version.h"
|
||||
#include "shared/rasutil.h"
|
||||
#include <climits>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace ras_util;
|
||||
@ -31,7 +32,7 @@ void ScsiMon::KillHandler(int)
|
||||
running = false;
|
||||
}
|
||||
|
||||
void ScsiMon::ParseArguments(const vector<char *>& args)
|
||||
void ScsiMon::ParseArguments(const vector<char *> &args)
|
||||
{
|
||||
int opt;
|
||||
|
||||
@ -60,8 +61,10 @@ void ScsiMon::ParseArguments(const vector<char *>& args)
|
||||
|
||||
/* Process any remaining command line arguments (not options). */
|
||||
if (optind < static_cast<int>(args.size())) {
|
||||
while (optind < static_cast<int>(args.size()))
|
||||
file_base_name = args[optind++];
|
||||
while (optind < static_cast<int>(args.size())) {
|
||||
file_base_name = args[optind];
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
|
||||
vcd_file_name = file_base_name;
|
||||
@ -72,7 +75,7 @@ void ScsiMon::ParseArguments(const vector<char *>& args)
|
||||
html_file_name += ".html";
|
||||
}
|
||||
|
||||
void ScsiMon::PrintHelpText(const vector<char *>& args) const
|
||||
void ScsiMon::PrintHelpText(const vector<char *> &args) const
|
||||
{
|
||||
LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0])
|
||||
LOGINFO(" -i [input file json] - scsimon will parse the json file instead of capturing new data")
|
||||
@ -86,8 +89,7 @@ void ScsiMon::Banner() const
|
||||
{
|
||||
if (import_data) {
|
||||
LOGINFO("Reading input file: %s", input_file_name.c_str())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOGINFO("Reading live data from the GPIO pins")
|
||||
LOGINFO(" Connection type : %s", CONNECT_DESC.c_str())
|
||||
}
|
||||
@ -130,11 +132,11 @@ void ScsiMon::Cleanup() const
|
||||
}
|
||||
LOGINFO(" ")
|
||||
LOGINFO("Generating %s...", vcd_file_name.c_str())
|
||||
scsimon_generate_value_change_dump(vcd_file_name.c_str(), data_buffer, data_idx);
|
||||
scsimon_generate_value_change_dump(vcd_file_name, data_buffer);
|
||||
LOGINFO("Generating %s...", json_file_name.c_str())
|
||||
scsimon_generate_json(json_file_name.c_str(), data_buffer, data_idx);
|
||||
scsimon_generate_json(json_file_name, data_buffer);
|
||||
LOGINFO("Generating %s...", html_file_name.c_str())
|
||||
scsimon_generate_html(html_file_name.c_str(), data_buffer, data_idx);
|
||||
scsimon_generate_html(html_file_name, data_buffer);
|
||||
|
||||
bus->Cleanup();
|
||||
}
|
||||
@ -144,12 +146,7 @@ void ScsiMon::Reset() const
|
||||
bus->Reset();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static uint32_t high_bits = 0x0;
|
||||
static uint32_t low_bits = 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
int ScsiMon::run(const vector<char *>& args)
|
||||
int ScsiMon::run(const vector<char *> &args)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
@ -162,12 +159,8 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
|
||||
ParseArguments(args);
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t prev_high = high_bits;
|
||||
uint32_t prev_low = low_bits;
|
||||
#endif
|
||||
uint32_t prev_sample = 0xFFFFFFFF;
|
||||
uint32_t this_sample = 0;
|
||||
shared_ptr<DataSample> prev_sample = nullptr;
|
||||
shared_ptr<DataSample> this_sample = nullptr;
|
||||
timeval start_time;
|
||||
timeval stop_time;
|
||||
uint64_t loop_count = 0;
|
||||
@ -181,12 +174,11 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
|
||||
Banner();
|
||||
|
||||
data_buffer = (data_capture *)calloc(buff_size, sizeof(data_capture_t));
|
||||
data_buffer.reserve(buff_size);
|
||||
|
||||
if (import_data) {
|
||||
data_idx = scsimon_read_json(input_file_name.c_str(), data_buffer, buff_size);
|
||||
if (data_idx > 0)
|
||||
{
|
||||
data_idx = scsimon_read_json(input_file_name, data_buffer);
|
||||
if (data_idx > 0) {
|
||||
LOGDEBUG("Read %d samples from %s", data_idx, input_file_name.c_str())
|
||||
Cleanup();
|
||||
}
|
||||
@ -223,12 +215,8 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
|
||||
(void)gettimeofday(&start_time, nullptr);
|
||||
|
||||
LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS)
|
||||
|
||||
// Main Loop
|
||||
while (running) {
|
||||
// Work initialization
|
||||
this_sample = (bus->Acquire() & ALL_SCSI_PINS);
|
||||
loop_count++;
|
||||
if (loop_count > LLONG_MAX - 1) {
|
||||
LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating.")
|
||||
@ -240,23 +228,9 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
running = false;
|
||||
}
|
||||
|
||||
if (this_sample != prev_sample) {
|
||||
#ifdef DEBUG
|
||||
// This is intended to be a debug check to see if every pin is set
|
||||
// high and low at some point.
|
||||
high_bits |= this_sample;
|
||||
low_bits &= this_sample;
|
||||
if ((high_bits != prev_high) || (low_bits != prev_low)) {
|
||||
LOGDEBUG(" %08X %08X\n", high_bits, low_bits)
|
||||
}
|
||||
prev_high = high_bits;
|
||||
prev_low = low_bits;
|
||||
if ((data_idx % 1000) == 0) {
|
||||
LOGDEBUG("%s", ("Collected " + to_string(data_idx) + " samples...").c_str())
|
||||
}
|
||||
#endif
|
||||
data_buffer[data_idx].data = this_sample;
|
||||
data_buffer[data_idx].timestamp = loop_count;
|
||||
this_sample = bus->GetSample(loop_count);
|
||||
if ((prev_sample == nullptr) || (this_sample->GetRawCapture() != prev_sample->GetRawCapture())) {
|
||||
data_buffer.push_back(this_sample);
|
||||
data_idx++;
|
||||
prev_sample = this_sample;
|
||||
}
|
||||
@ -266,8 +240,7 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
|
||||
// Collect one last sample, otherwise it looks like the end of the data was cut off
|
||||
if (data_idx < buff_size) {
|
||||
data_buffer[data_idx].data = this_sample;
|
||||
data_buffer[data_idx].timestamp = loop_count;
|
||||
data_buffer.push_back(bus->GetSample(loop_count));
|
||||
data_idx++;
|
||||
}
|
||||
|
||||
@ -276,13 +249,15 @@ int ScsiMon::run(const vector<char *>& args)
|
||||
timersub(&stop_time, &start_time, &time_diff);
|
||||
|
||||
elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec);
|
||||
LOGINFO("%s", ("Elapsed time: " + to_string(elapsed_us) + " microseconds (" + to_string(elapsed_us / 1000000)
|
||||
+ " seconds").c_str())
|
||||
LOGINFO("%s", ("Elapsed time: " + to_string(elapsed_us) + " microseconds (" + to_string(elapsed_us / 1000000) +
|
||||
" seconds")
|
||||
.c_str())
|
||||
LOGINFO("%s", ("Collected " + to_string(data_idx) + " changes").c_str())
|
||||
|
||||
ns_per_loop = (double)(elapsed_us * 1000) / (double)loop_count;
|
||||
LOGINFO("%s", ("Read the SCSI bus " + to_string(loop_count) + " times with an average of "
|
||||
+ to_string(ns_per_loop) + " ns for each read").c_str())
|
||||
LOGINFO("%s", ("Read the SCSI bus " + to_string(loop_count) + " times with an average of " +
|
||||
to_string(ns_per_loop) + " ns for each read")
|
||||
.c_str())
|
||||
|
||||
Cleanup();
|
||||
|
||||
|
@ -10,28 +10,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "hal/bus.h"
|
||||
#include "monitor/data_sample.h"
|
||||
#include <vector>
|
||||
#include "hal/data_sample.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// TODO Make static fields/methods non-static
|
||||
class ScsiMon
|
||||
{
|
||||
public:
|
||||
|
||||
public:
|
||||
ScsiMon() = default;
|
||||
~ScsiMon() = default;
|
||||
|
||||
int run(const vector<char *>&);
|
||||
int run(const vector<char *> &);
|
||||
|
||||
inline static double ns_per_loop;
|
||||
|
||||
private:
|
||||
|
||||
void ParseArguments(const vector<char *>&);
|
||||
void PrintHelpText(const vector<char *>&) const;
|
||||
private:
|
||||
void ParseArguments(const vector<char *> &);
|
||||
void PrintHelpText(const vector<char *> &) const;
|
||||
void Banner() const;
|
||||
bool Init();
|
||||
void Cleanup() const;
|
||||
@ -41,11 +39,11 @@ private:
|
||||
|
||||
static inline volatile bool running;
|
||||
|
||||
unique_ptr<BUS> bus;
|
||||
shared_ptr<BUS> bus;
|
||||
|
||||
uint32_t buff_size = 1000000;
|
||||
|
||||
data_capture *data_buffer = nullptr;
|
||||
vector<shared_ptr<DataSample>> data_buffer;
|
||||
|
||||
uint32_t data_idx = 0;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2021-2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -96,13 +97,13 @@ for (i = 0; i < coll.length; i++) {
|
||||
)";
|
||||
|
||||
|
||||
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
static void print_html_data(ofstream& html_fp, const vector<shared_ptr<DataSample>> &data_capture_array)
|
||||
{
|
||||
const data_capture *data;
|
||||
shared_ptr<DataSample> data;
|
||||
bool prev_data_valid = false;
|
||||
bool curr_data_valid;
|
||||
uint32_t selected_id = 0;
|
||||
BUS::phase_t prev_phase = BUS::phase_t::busfree;
|
||||
phase_t prev_phase = phase_t::busfree;
|
||||
bool close_row = false;
|
||||
int data_space_count = 0;
|
||||
bool collapsible_div_active = false;
|
||||
@ -110,12 +111,11 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
|
||||
html_fp << "<table>" << endl;
|
||||
|
||||
for (uint32_t 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::phase_t::selection && !GetBsy(data)) {
|
||||
selected_id = GetData(data);
|
||||
for (auto data: data_capture_array) {
|
||||
curr_data_valid = data->GetACK() && data->GetREQ();
|
||||
phase_t phase = data->GetPhase();
|
||||
if (phase == phase_t::selection && !data->GetBSY()) {
|
||||
selected_id = data->GetDAT();
|
||||
}
|
||||
if (prev_phase != phase) {
|
||||
if (close_row) {
|
||||
@ -137,8 +137,8 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
}
|
||||
html_fp << "<tr>";
|
||||
close_row = true; // Close the row the next time around
|
||||
html_fp << "<td>" << (double)data->timestamp / 100000 << "</td>";
|
||||
html_fp << "<td>" << GetPhaseStr(data) << "</td>";
|
||||
html_fp << "<td>" << (double)data->GetTimestamp() / 100000 << "</td>";
|
||||
html_fp << "<td>" << data->GetPhaseStr() << "</td>";
|
||||
html_fp << "<td>" << std::hex << selected_id << "</td>";
|
||||
html_fp << "<td>";
|
||||
}
|
||||
@ -151,7 +151,7 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
html_fp << std::hex << data_space_count << ": ";
|
||||
}
|
||||
|
||||
html_fp << fmt::format("{0:02X}", GetData(data));
|
||||
html_fp << fmt::format("{0:02X}", data->GetDAT());
|
||||
|
||||
data_space_count++;
|
||||
if ((data_space_count % 4) == 0) {
|
||||
@ -171,17 +171,17 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
void scsimon_generate_html(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array)
|
||||
{
|
||||
LOGINFO("Creating HTML report file (%s)", filename)
|
||||
LOGINFO("Creating HTML report file (%s)", filename.c_str())
|
||||
|
||||
ofstream html_ofstream;
|
||||
|
||||
html_ofstream.open(filename, ios::out);
|
||||
html_ofstream.open(filename.c_str(), ios::out);
|
||||
|
||||
html_ofstream << html_header;
|
||||
print_copyright_info(html_ofstream);
|
||||
print_html_data(html_ofstream, data_capture_array, capture_count);
|
||||
print_html_data(html_ofstream, data_capture_array);
|
||||
|
||||
html_ofstream << html_footer;
|
||||
|
||||
|
@ -5,60 +5,59 @@
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2021-2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/data_sample_raspberry.h"
|
||||
#include "shared/log.h"
|
||||
#include "sm_reports.h"
|
||||
#include "string.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char timestamp_label[] = "\"timestamp\":\"0x";
|
||||
const char data_label[] = "\"data\":\"0x";
|
||||
const string timestamp_label = "\"timestamp\":\"0x";
|
||||
const string data_label = "\"data\":\"0x";
|
||||
|
||||
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz)
|
||||
uint32_t scsimon_read_json(const string &json_filename, vector<shared_ptr<DataSample>> &data_capture_array)
|
||||
{
|
||||
char str_buf[1024];
|
||||
FILE *fp = fopen(json_filename, "r");
|
||||
std::ifstream json_file(json_filename);
|
||||
uint32_t sample_count = 0;
|
||||
|
||||
while (fgets(str_buf, sizeof(str_buf), fp)) {
|
||||
char timestamp[1024];
|
||||
char data[1024];
|
||||
while (json_file) {
|
||||
string str_buf;
|
||||
std::getline(json_file, str_buf);
|
||||
string timestamp;
|
||||
string data;
|
||||
uint64_t timestamp_uint;
|
||||
uint32_t data_uint;
|
||||
char *ptr;
|
||||
|
||||
const char *timestamp_str = strstr(str_buf, timestamp_label);
|
||||
if (!timestamp_str)
|
||||
size_t timestamp_pos = str_buf.find(timestamp_label);
|
||||
if (timestamp_pos == string::npos)
|
||||
continue;
|
||||
strncpy(timestamp, ×tamp_str[strlen(timestamp_label)], 16);
|
||||
timestamp[16] = '\0';
|
||||
timestamp_uint = strtoull(timestamp, &ptr, 16);
|
||||
timestamp = str_buf.substr(timestamp_pos + timestamp_label.length(), 16);
|
||||
timestamp_uint = strtoull(timestamp.c_str(), &ptr, 16);
|
||||
|
||||
const char *data_str = strstr(str_buf, data_label);
|
||||
if (!data_str)
|
||||
size_t data_pos = str_buf.find(data_label);
|
||||
if (data_pos == string::npos)
|
||||
continue;
|
||||
strncpy(data, &data_str[strlen(data_label)], 8);
|
||||
data[8] = '\0';
|
||||
data_uint = static_cast<uint32_t>(strtoul(data, &ptr, 16));
|
||||
data = str_buf.substr(data_pos + data_label.length(), 8);
|
||||
data_uint = static_cast<uint32_t>(strtoul(data.c_str(), &ptr, 16));
|
||||
|
||||
// For reading in JSON files, we'll just assume raspberry pi data types
|
||||
data_capture_array.push_back(make_unique<DataSample_Raspberry>(data_uint, timestamp_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")
|
||||
if (sample_count == UINT32_MAX) {
|
||||
LOGWARN("Maximum number of samples read. Some data may not be included.")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp != nullptr) {
|
||||
fclose(fp);
|
||||
}
|
||||
json_file.close();
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
@ -68,20 +67,21 @@ uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture
|
||||
// Generate JSON Output File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
void scsimon_generate_json(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array)
|
||||
{
|
||||
LOGTRACE("Creating JSON file (%s)", filename)
|
||||
LOGTRACE("Creating JSON file (%s)", filename.c_str())
|
||||
ofstream json_ofstream;
|
||||
json_ofstream.open(filename, ios::out);
|
||||
json_ofstream.open(filename.c_str(), ios::out);
|
||||
|
||||
json_ofstream << "[" << endl;
|
||||
|
||||
uint32_t 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);
|
||||
size_t i = 0;
|
||||
size_t capture_count = data_capture_array.size();
|
||||
for (auto data : data_capture_array) {
|
||||
json_ofstream << fmt::format("{{\"id\": \"{0:d}\", \"timestamp\":\"{1:#016x}\", \"data\":\"{2:#08x}\"}}", i,
|
||||
data->GetTimestamp(), data->GetRawCapture());
|
||||
|
||||
if (i != (capture_count - 1))
|
||||
{
|
||||
if (i != (capture_count - 1)) {
|
||||
json_ofstream << ",";
|
||||
}
|
||||
json_ofstream << endl;
|
||||
@ -89,5 +89,4 @@ void scsimon_generate_json(const char *filename, const data_capture *data_captur
|
||||
}
|
||||
json_ofstream << "]" << endl;
|
||||
json_ofstream.close();
|
||||
|
||||
}
|
||||
|
@ -9,10 +9,11 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "data_sample.h"
|
||||
#include "hal/data_sample.h"
|
||||
#include <memory>
|
||||
|
||||
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz);
|
||||
uint32_t scsimon_read_json(const string &json_filename, vector<shared_ptr<DataSample>> &data_capture_array);
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
void scsimon_generate_html(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array);
|
||||
void scsimon_generate_json(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array);
|
||||
void scsimon_generate_value_change_dump(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array);
|
||||
|
@ -9,14 +9,14 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "shared/log.h"
|
||||
#include "hal/data_sample.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "data_sample.h"
|
||||
#include "shared/log.h"
|
||||
#include "sm_core.h"
|
||||
#include "sm_reports.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -49,79 +49,48 @@ const int PIN_PHASE = 0;
|
||||
// Variable declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static uint8_t prev_value[32] = {0xFF};
|
||||
static array<uint8_t,32> prev_value = {0xFF};
|
||||
|
||||
static uint8_t get_pin_value(uint32_t data, int pin)
|
||||
static void vcd_output_if_changed_phase(ofstream &fp, phase_t data, int pin, char symbol)
|
||||
{
|
||||
return (data >> pin) & 1;
|
||||
}
|
||||
|
||||
static uint8_t get_data_field(uint32_t data)
|
||||
{
|
||||
const uint32_t 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 (uint8_t)data_out;
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_phase(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
{
|
||||
const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != static_cast<uint8_t>(new_value)) {
|
||||
prev_value[pin] = static_cast<uint8_t>(new_value);
|
||||
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
|
||||
if (prev_value[pin] != static_cast<uint8_t>(data)) {
|
||||
prev_value[pin] = static_cast<uint8_t>(data);
|
||||
fp << "s" << BUS::GetPhaseStrRaw(data) << " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_bool(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
static void vcd_output_if_changed_bool(ofstream &fp, bool data, int pin, char symbol)
|
||||
{
|
||||
const uint8_t new_value = get_pin_value(data, pin);
|
||||
if (prev_value[pin] != new_value) {
|
||||
prev_value[pin] = new_value;
|
||||
fp << new_value << symbol << endl;
|
||||
if (prev_value[pin] != data) {
|
||||
prev_value[pin] = data;
|
||||
fp << data << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_byte(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
static void vcd_output_if_changed_byte(ofstream &fp, uint8_t data, int pin, char symbol)
|
||||
{
|
||||
const uint8_t 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;
|
||||
if (prev_value[pin] != data) {
|
||||
prev_value[pin] = data;
|
||||
fp << "b" << fmt::format("{0:8b}", data) << " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
void scsimon_generate_value_change_dump(const string &filename, const vector<shared_ptr<DataSample>> &data_capture_array)
|
||||
{
|
||||
LOGTRACE("Creating Value Change Dump file (%s)", filename)
|
||||
LOGTRACE("Creating Value Change Dump file (%s)", filename.c_str())
|
||||
ofstream vcd_ofstream;
|
||||
vcd_ofstream.open(filename, ios::out);
|
||||
vcd_ofstream.open(filename.c_str(), ios::out);
|
||||
|
||||
// Get the current time
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
const struct tm *timeinfo = localtime(&rawtime);
|
||||
char timestamp[256];
|
||||
strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo);
|
||||
struct tm timeinfo;
|
||||
localtime_r(&rawtime, &timeinfo);
|
||||
string timestamp;
|
||||
timestamp.resize(256);
|
||||
strftime(×tamp[0], timestamp.size(), "%d-%m-%Y %H-%M-%S", &timeinfo);
|
||||
|
||||
vcd_ofstream
|
||||
<< "$date" << endl
|
||||
vcd_ofstream << "$date" << endl
|
||||
<< timestamp << endl
|
||||
<< "$end" << endl
|
||||
<< "$version" << endl
|
||||
@ -135,8 +104,8 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
|
||||
<< "$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_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
|
||||
@ -147,8 +116,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
|
||||
<< "$enddefinitions $end" << endl;
|
||||
|
||||
// Initial values - default to zeros
|
||||
vcd_ofstream
|
||||
<< "$dumpvars" << endl
|
||||
vcd_ofstream << "$dumpvars" << endl
|
||||
<< "0" << SYMBOL_PIN_BSY << endl
|
||||
<< "0" << SYMBOL_PIN_SEL << endl
|
||||
<< "0" << SYMBOL_PIN_CD << endl
|
||||
@ -161,21 +129,19 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
|
||||
<< "b00000000 " << SYMBOL_PIN_DAT << endl
|
||||
<< "$end" << endl;
|
||||
|
||||
uint32_t i = 0;
|
||||
while (i < capture_count) {
|
||||
vcd_ofstream << "#" << (uint64_t)((double)data_capture_array[i].timestamp * ScsiMon::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++;
|
||||
for (shared_ptr<DataSample> cur_sample : data_capture_array) {
|
||||
vcd_ofstream << "#" << (double)cur_sample->GetTimestamp() * ScsiMon::ns_per_loop << endl;
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetBSY(), PIN_BSY, SYMBOL_PIN_BSY);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetSEL(), PIN_SEL, SYMBOL_PIN_SEL);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetCD(), PIN_CD, SYMBOL_PIN_CD);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetIO(), PIN_IO, SYMBOL_PIN_IO);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetMSG(), PIN_MSG, SYMBOL_PIN_MSG);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetREQ(), PIN_REQ, SYMBOL_PIN_REQ);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetACK(), PIN_ACK, SYMBOL_PIN_ACK);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetATN(), PIN_ATN, SYMBOL_PIN_ATN);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, cur_sample->GetRST(), PIN_RST, SYMBOL_PIN_RST);
|
||||
vcd_output_if_changed_byte(vcd_ofstream, cur_sample->GetDAT(), PIN_DT0, SYMBOL_PIN_DAT);
|
||||
vcd_output_if_changed_phase(vcd_ofstream, cur_sample->GetPhase(), PIN_PHASE, SYMBOL_PIN_PHASE);
|
||||
}
|
||||
vcd_ofstream.close();
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ using namespace spdlog;
|
||||
using namespace rascsi_interface;
|
||||
using namespace ras_util;
|
||||
using namespace protobuf_util;
|
||||
using namespace scsi_defs;
|
||||
|
||||
void Rascsi::Banner(const vector<char *>& args) const
|
||||
{
|
||||
@ -584,7 +585,7 @@ int Rascsi::run(const vector<char *>& args)
|
||||
// The initiator and target ID
|
||||
const uint8_t id_data = bus->GetDAT();
|
||||
|
||||
BUS::phase_t phase = BUS::phase_t::busfree;
|
||||
phase_t phase = phase_t::busfree;
|
||||
|
||||
// Identify the responsible controller
|
||||
auto controller = controller_manager->IdentifyController(id_data);
|
||||
@ -600,13 +601,13 @@ int Rascsi::run(const vector<char *>& args)
|
||||
device_logger.Trace("++++ Starting processing for unknown initiator ID");
|
||||
}
|
||||
|
||||
if (controller->Process(initiator_id) == BUS::phase_t::selection) {
|
||||
phase = BUS::phase_t::selection;
|
||||
if (controller->Process(initiator_id) == phase_t::selection) {
|
||||
phase = phase_t::selection;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to bus monitoring if the selection phase has not started
|
||||
if (phase != BUS::phase_t::selection) {
|
||||
if (phase != phase_t::selection) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -625,7 +626,7 @@ int Rascsi::run(const vector<char *>& args)
|
||||
phase = controller->Process(initiator_id);
|
||||
|
||||
// End when the bus is free
|
||||
if (phase == BUS::phase_t::busfree) {
|
||||
if (phase == phase_t::busfree) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ void RasDump::ParseArguments(const vector<char *>& args)
|
||||
buffer = vector<uint8_t>(buffer_size);
|
||||
}
|
||||
|
||||
void RasDump::WaitPhase(BUS::phase_t phase) const
|
||||
void RasDump::WaitPhase(phase_t phase) const
|
||||
{
|
||||
LOGDEBUG("Waiting for %s phase", BUS::GetPhaseStrRaw(phase))
|
||||
|
||||
@ -176,7 +176,7 @@ void RasDump::Command(scsi_command cmd, vector<uint8_t>& cdb) const
|
||||
|
||||
Selection();
|
||||
|
||||
WaitPhase(BUS::phase_t::command);
|
||||
WaitPhase(phase_t::command);
|
||||
|
||||
cdb[0] = static_cast<uint8_t>(cmd);
|
||||
cdb[1] = static_cast<uint8_t>(static_cast<byte>(cdb[1]) | static_cast<byte>(target_lun << 5));
|
||||
@ -189,7 +189,7 @@ void RasDump::Command(scsi_command cmd, vector<uint8_t>& cdb) const
|
||||
|
||||
void RasDump::DataIn(int length)
|
||||
{
|
||||
WaitPhase(BUS::phase_t::datain);
|
||||
WaitPhase(phase_t::datain);
|
||||
|
||||
if (!bus->ReceiveHandShake(buffer.data(), length)) {
|
||||
throw parser_exception("DATA IN failed");
|
||||
@ -198,7 +198,7 @@ void RasDump::DataIn(int length)
|
||||
|
||||
void RasDump::DataOut(int length)
|
||||
{
|
||||
WaitPhase(BUS::phase_t::dataout);
|
||||
WaitPhase(phase_t::dataout);
|
||||
|
||||
if (!bus->SendHandShake(buffer.data(), length, BUS::SEND_NO_DELAY)) {
|
||||
throw parser_exception("DATA OUT failed");
|
||||
@ -207,7 +207,7 @@ void RasDump::DataOut(int length)
|
||||
|
||||
void RasDump::Status() const
|
||||
{
|
||||
WaitPhase(BUS::phase_t::status);
|
||||
WaitPhase(phase_t::status);
|
||||
|
||||
if (array<uint8_t, 256> buf; bus->ReceiveHandShake(buf.data(), 1) != 1) {
|
||||
throw parser_exception("STATUS failed");
|
||||
@ -216,7 +216,7 @@ void RasDump::Status() const
|
||||
|
||||
void RasDump::MessageIn() const
|
||||
{
|
||||
WaitPhase(BUS::phase_t::msgin);
|
||||
WaitPhase(phase_t::msgin);
|
||||
|
||||
if (array<uint8_t, 256> buf; bus->ReceiveHandShake(buf.data(), 1) != 1) {
|
||||
throw parser_exception("MESSAGE IN failed");
|
||||
|
@ -36,7 +36,7 @@ private:
|
||||
void ParseArguments(const vector<char *>&);
|
||||
int DumpRestore();
|
||||
pair<uint64_t, uint32_t> GetDeviceInfo();
|
||||
void WaitPhase(BUS::phase_t) const;
|
||||
void WaitPhase(phase_t) const;
|
||||
void Selection() const;
|
||||
void Command(scsi_defs::scsi_command, vector<uint8_t>&) const;
|
||||
void DataIn(int);
|
||||
|
20
cpp/scsiloop.cpp
Normal file
20
cpp/scsiloop.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsiloop/scsiloop_core.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const vector<char *> args(argv, argv + argc);
|
||||
|
||||
return ScsiLoop().run(args);
|
||||
}
|
175
cpp/scsiloop/scsiloop_core.cpp
Normal file
175
cpp/scsiloop/scsiloop_core.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
// [ Loopback tester utility ]
|
||||
//
|
||||
// For more information, see:
|
||||
// https://github.com/akuker/RASCSI/wiki/Troubleshooting#Loopback_Testing
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "shared/log.h"
|
||||
#include "shared/rascsi_version.h"
|
||||
#include "shared/rasutil.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
|
||||
#include "scsiloop/scsiloop_core.h"
|
||||
#include "scsiloop/scsiloop_cout.h"
|
||||
#include "scsiloop/scsiloop_gpio.h"
|
||||
#include "scsiloop/scsiloop_timer.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <signal.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
|
||||
|
||||
using namespace std;
|
||||
using namespace spdlog;
|
||||
|
||||
string current_log_level = "unknown"; // Some versions of spdlog do not support get_log_level()
|
||||
|
||||
void ScsiLoop::Banner(const vector<char *> &args) const
|
||||
{
|
||||
cout << ras_util::Banner("SCSI Loopback Test");
|
||||
cout << "Connect type: " << CONNECT_DESC << '\n' << flush;
|
||||
|
||||
if ((args.size() > 1 && strcmp(args[1], "-h") == 0) || (args.size() > 1 && strcmp(args[1], "--help") == 0)) {
|
||||
cout << "\nUsage: " << args[0] << " [-L log_level] ...\n\n";
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScsiLoop::SetLogLevel(const string &log_level)
|
||||
{
|
||||
if (log_level == "trace") {
|
||||
set_level(level::trace);
|
||||
} else if (log_level == "debug") {
|
||||
set_level(level::debug);
|
||||
} else if (log_level == "info") {
|
||||
set_level(level::info);
|
||||
} else if (log_level == "warn") {
|
||||
set_level(level::warn);
|
||||
} else if (log_level == "err") {
|
||||
set_level(level::err);
|
||||
} else if (log_level == "critical") {
|
||||
set_level(level::critical);
|
||||
} else if (log_level == "off") {
|
||||
set_level(level::off);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
current_log_level = log_level;
|
||||
|
||||
LOGINFO("Set log level to '%s'", current_log_level.c_str())
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScsiLoop::TerminationHandler(int signum)
|
||||
{
|
||||
exit(signum);
|
||||
}
|
||||
|
||||
bool ScsiLoop::ParseArgument(const vector<char *> &args)
|
||||
{
|
||||
string name;
|
||||
string log_level;
|
||||
|
||||
const char *locale = setlocale(LC_MESSAGES, "");
|
||||
if (locale == nullptr || !strcmp(locale, "C")) {
|
||||
locale = "en";
|
||||
}
|
||||
|
||||
opterr = 1;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(static_cast<int>(args.size()), args.data(), "-L:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'L':
|
||||
log_level = optarg;
|
||||
continue;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (optopt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!log_level.empty()) {
|
||||
SetLogLevel(log_level);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ScsiLoop::run(const vector<char *> &args)
|
||||
{
|
||||
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits.
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
// Output the Banner
|
||||
Banner(args);
|
||||
|
||||
// ParseArgument() requires the bus to have been initialized first, which requires the root user.
|
||||
// The -v option should be available for any user, which requires special handling.
|
||||
for (auto this_arg : args) {
|
||||
if (!strcasecmp(this_arg, "-v")) {
|
||||
cout << rascsi_get_version_string() << endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a thread-safe stdout logger to process the log messages
|
||||
const auto logger = stdout_color_mt("scsiloop stdout logger");
|
||||
set_level(level::info);
|
||||
current_log_level = "info";
|
||||
|
||||
vector<string> error_list;
|
||||
|
||||
if (!ParseArgument(args)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Signal handler to detach all devices on a KILL or TERM signal
|
||||
struct sigaction termination_handler;
|
||||
termination_handler.sa_handler = TerminationHandler;
|
||||
sigemptyset(&termination_handler.sa_mask);
|
||||
termination_handler.sa_flags = 0;
|
||||
sigaction(SIGINT, &termination_handler, nullptr);
|
||||
sigaction(SIGTERM, &termination_handler, nullptr);
|
||||
|
||||
// This must be executed before the timer test, since this initializes the timer
|
||||
ScsiLoop_GPIO gpio_test;
|
||||
|
||||
int result = ScsiLoop_Timer::RunTimerTest(error_list);
|
||||
result += gpio_test.RunLoopbackTest(error_list);
|
||||
|
||||
if (result == 0) {
|
||||
// Only test the dat inputs/outputs if the loopback test passed.
|
||||
result += gpio_test.RunDataInputTest(error_list);
|
||||
result += gpio_test.RunDataOutputTest(error_list);
|
||||
}
|
||||
|
||||
ScsiLoop_Cout::PrintErrors(error_list);
|
||||
gpio_test.Cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
32
cpp/scsiloop/scsiloop_core.h
Normal file
32
cpp/scsiloop/scsiloop_core.h
Normal file
@ -0,0 +1,32 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ScsiLoop
|
||||
{
|
||||
public:
|
||||
ScsiLoop() = default;
|
||||
~ScsiLoop() = default;
|
||||
|
||||
int run(const vector<char *> &args);
|
||||
|
||||
private:
|
||||
void Banner(const vector<char *> &) const;
|
||||
static void TerminationHandler(int signum);
|
||||
bool ParseArgument(const vector<char *> &);
|
||||
bool SetLogLevel(const string &);
|
||||
};
|
40
cpp/scsiloop/scsiloop_cout.cpp
Normal file
40
cpp/scsiloop/scsiloop_cout.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsiloop_cout.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void ScsiLoop_Cout::StartTest(const string &test_name)
|
||||
{
|
||||
cout << CYAN << "Testing " << test_name << ":" << WHITE;
|
||||
}
|
||||
void ScsiLoop_Cout::PrintUpdate()
|
||||
{
|
||||
cout << ".";
|
||||
}
|
||||
|
||||
void ScsiLoop_Cout::FinishTest(const string &test_name, int failures)
|
||||
{
|
||||
if (failures == 0) {
|
||||
cout << GREEN << "OK!" << WHITE << endl;
|
||||
} else {
|
||||
cout << RED << test_name << " FAILED! - " << failures << " errors!" << WHITE << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ScsiLoop_Cout::PrintErrors(vector<string> &test_errors)
|
||||
{
|
||||
if (test_errors.size() > 0) {
|
||||
for (auto err_string : test_errors) {
|
||||
cout << RED << err_string << endl;
|
||||
}
|
||||
}
|
||||
}
|
33
cpp/scsiloop/scsiloop_cout.h
Normal file
33
cpp/scsiloop/scsiloop_cout.h
Normal file
@ -0,0 +1,33 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ScsiLoop_Cout
|
||||
{
|
||||
public:
|
||||
static void StartTest(const string &test_name);
|
||||
static void PrintUpdate();
|
||||
static void FinishTest(const string &test_name, int failures);
|
||||
static void PrintErrors(vector<string> &test_errors);
|
||||
|
||||
private:
|
||||
const static inline string RESET = "\033[0m";
|
||||
const static inline string BLACK = "\033[30m"; /* Black */
|
||||
const static inline string RED = "\033[31m"; /* Red */
|
||||
const static inline string GREEN = "\033[32m"; /* Green */
|
||||
const static inline string YELLOW = "\033[33m"; /* Yellow */
|
||||
const static inline string BLUE = "\033[34m"; /* Blue */
|
||||
const static inline string MAGENTA = "\033[35m"; /* Magenta */
|
||||
const static inline string CYAN = "\033[36m"; /* Cyan */
|
||||
const static inline string WHITE = "\033[37m"; /* White */
|
||||
};
|
592
cpp/scsiloop/scsiloop_gpio.cpp
Normal file
592
cpp/scsiloop/scsiloop_gpio.cpp
Normal file
@ -0,0 +1,592 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded 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;
|
||||
}
|
81
cpp/scsiloop/scsiloop_gpio.h
Normal file
81
cpp/scsiloop/scsiloop_gpio.h
Normal file
@ -0,0 +1,81 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hal/gpiobus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ScsiLoop_GPIO
|
||||
{
|
||||
public:
|
||||
ScsiLoop_GPIO();
|
||||
~ScsiLoop_GPIO() = default;
|
||||
int RunLoopbackTest(vector<string> &error_list);
|
||||
int RunDataInputTest(vector<string> &error_list);
|
||||
int RunDataOutputTest(vector<string> &error_list);
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
struct loopback_connections_struct {
|
||||
int this_pin;
|
||||
int connected_pin;
|
||||
int dir_ctrl_pin;
|
||||
};
|
||||
typedef loopback_connections_struct loopback_connection;
|
||||
|
||||
std::map<int, string> pin_name_lookup;
|
||||
std::vector<loopback_connection> loopback_conn_table;
|
||||
|
||||
void set_dtd_out();
|
||||
void set_dtd_in();
|
||||
void set_ind_out();
|
||||
void set_ind_in();
|
||||
void set_tad_out();
|
||||
void set_tad_in();
|
||||
void set_output_channel(int out_gpio);
|
||||
void loopback_setup();
|
||||
|
||||
int test_gpio_pin(loopback_connection &gpio_rec, vector<string> &error_list, bool &loopback_adapter_missing);
|
||||
|
||||
void set_dat_inputs_loop(uint8_t value);
|
||||
|
||||
void dat_input_test_setup();
|
||||
void dat_output_test_setup();
|
||||
|
||||
uint8_t get_dat_outputs_loop();
|
||||
|
||||
int local_pin_dtd = -1;
|
||||
int local_pin_tad = -1;
|
||||
int local_pin_ind = -1;
|
||||
int local_pin_ack = -1;
|
||||
int local_pin_sel = -1;
|
||||
int local_pin_atn = -1;
|
||||
int local_pin_rst = -1;
|
||||
int local_pin_cd = -1;
|
||||
int local_pin_io = -1;
|
||||
int local_pin_msg = -1;
|
||||
int local_pin_req = -1;
|
||||
int local_pin_bsy = -1;
|
||||
|
||||
int local_pin_dt0 = -1;
|
||||
int local_pin_dt1 = -1;
|
||||
int local_pin_dt2 = -1;
|
||||
int local_pin_dt3 = -1;
|
||||
int local_pin_dt4 = -1;
|
||||
int local_pin_dt5 = -1;
|
||||
int local_pin_dt6 = -1;
|
||||
int local_pin_dt7 = -1;
|
||||
int local_pin_dp = -1;
|
||||
|
||||
shared_ptr<BUS> bus;
|
||||
};
|
91
cpp/scsiloop/scsiloop_timer.cpp
Normal file
91
cpp/scsiloop/scsiloop_timer.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsiloop_timer.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "scsiloop/scsiloop_cout.h"
|
||||
#include "shared/log.h"
|
||||
|
||||
int ScsiLoop_Timer::RunTimerTest(vector<string> &error_list)
|
||||
{
|
||||
uint32_t timer_test_failures = 0;
|
||||
|
||||
ScsiLoop_Cout::StartTest("hardware timer");
|
||||
|
||||
// Allow +/- 2% tolerance when testing the timers
|
||||
double timer_tolerance_percent = 0.02;
|
||||
const uint32_t one_second_in_ns = 1000000;
|
||||
|
||||
//------------------------------------------------------
|
||||
// Test SysTimer::GetTimerLow()
|
||||
LOGDEBUG("++ Testing SysTimer::GetTimerLow()")
|
||||
uint32_t before = SysTimer::GetTimerLow();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
usleep(100000);
|
||||
ScsiLoop_Cout::PrintUpdate();
|
||||
}
|
||||
uint32_t after = SysTimer::GetTimerLow();
|
||||
|
||||
uint32_t elapsed_nanosecs = after - before;
|
||||
|
||||
LOGDEBUG("Elapsed time: %d %08X", elapsed_nanosecs, elapsed_nanosecs);
|
||||
|
||||
if ((elapsed_nanosecs > (one_second_in_ns * (1.0 + timer_tolerance_percent))) ||
|
||||
(elapsed_nanosecs < (one_second_in_ns * (1.0 - timer_tolerance_percent)))) {
|
||||
error_list.push_back(fmt::format("SysTimer::GetTimerLow() test: Expected time approx: {}, but actually {}",
|
||||
one_second_in_ns, elapsed_nanosecs));
|
||||
timer_test_failures++;
|
||||
} else {
|
||||
ScsiLoop_Cout::PrintUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// Test SysTimer::SleepUsec()
|
||||
LOGDEBUG("++ Testing SysTimer::SleepUsec()")
|
||||
|
||||
uint32_t expected_usec_result = 1000 * 100;
|
||||
before = SysTimer::GetTimerLow();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
SysTimer::SleepUsec(1000);
|
||||
}
|
||||
after = SysTimer::GetTimerLow();
|
||||
elapsed_nanosecs = after - before;
|
||||
LOGDEBUG("SysTimer::SleepUsec() Average %d", (uint32_t)(elapsed_nanosecs / 100));
|
||||
|
||||
if ((elapsed_nanosecs > expected_usec_result * (1.0 + timer_tolerance_percent)) ||
|
||||
(elapsed_nanosecs < expected_usec_result * (1.0 - timer_tolerance_percent))) {
|
||||
error_list.push_back(fmt::format("SysTimer::SleepUsec Test: Expected time approx: {}, but actually {}",
|
||||
expected_usec_result, elapsed_nanosecs));
|
||||
timer_test_failures++;
|
||||
} else {
|
||||
ScsiLoop_Cout::PrintUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// Test SysTimer::SleepNsec()
|
||||
LOGDEBUG("++ Testing SysTimer::SleepNsec()")
|
||||
|
||||
before = SysTimer::GetTimerLow();
|
||||
SysTimer::SleepNsec(1000000);
|
||||
after = SysTimer::GetTimerLow();
|
||||
LOGDEBUG("SysTimer::SleepNSec: %d (expected ~1000)", (uint32_t)(after - before));
|
||||
|
||||
elapsed_nanosecs = after - before;
|
||||
if ((elapsed_nanosecs > (1000 * (1.0 + timer_tolerance_percent))) ||
|
||||
(elapsed_nanosecs < (1000 * (1.0 - timer_tolerance_percent)))) {
|
||||
error_list.push_back(
|
||||
fmt::format("SysTimer::SleepNsec Test: Expected time approx: 1000, but actually {}", elapsed_nanosecs));
|
||||
timer_test_failures++;
|
||||
} else {
|
||||
ScsiLoop_Cout::PrintUpdate();
|
||||
}
|
||||
|
||||
ScsiLoop_Cout::FinishTest("hardware timer", timer_test_failures);
|
||||
return timer_test_failures;
|
||||
}
|
19
cpp/scsiloop/scsiloop_timer.h
Normal file
19
cpp/scsiloop/scsiloop_timer.h
Normal file
@ -0,0 +1,19 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded for Raspberry Pi
|
||||
// Loopback tester utility
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ScsiLoop_Timer
|
||||
{
|
||||
public:
|
||||
static int RunTimerTest(vector<string> &error_list);
|
||||
};
|
@ -13,8 +13,9 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace scsi_defs {
|
||||
enum class scsi_level : int {
|
||||
namespace scsi_defs
|
||||
{
|
||||
enum class scsi_level : int {
|
||||
SCSI_1_CCS = 1,
|
||||
SCSI_2 = 2,
|
||||
SPC = 3,
|
||||
@ -23,18 +24,33 @@ namespace scsi_defs {
|
||||
SPC_4 = 6,
|
||||
SPC_5 = 7,
|
||||
SPC_6 = 8
|
||||
};
|
||||
};
|
||||
|
||||
enum class device_type : int {
|
||||
// Phase definitions
|
||||
enum class phase_t : int {
|
||||
busfree,
|
||||
arbitration,
|
||||
selection,
|
||||
reselection,
|
||||
command,
|
||||
datain,
|
||||
dataout,
|
||||
status,
|
||||
msgin,
|
||||
msgout,
|
||||
reserved
|
||||
};
|
||||
|
||||
enum class device_type : int {
|
||||
DIRECT_ACCESS = 0,
|
||||
PRINTER = 2,
|
||||
PROCESSOR = 3,
|
||||
CD_ROM = 5,
|
||||
OPTICAL_MEMORY = 7,
|
||||
COMMUNICATIONS = 9
|
||||
};
|
||||
};
|
||||
|
||||
enum class scsi_command : int {
|
||||
enum class scsi_command : int {
|
||||
eCmdTestUnitReady = 0x00,
|
||||
eCmdRezero = 0x01,
|
||||
eCmdRequestSense = 0x03,
|
||||
@ -86,15 +102,11 @@ namespace scsi_defs {
|
||||
eCmdReadCapacity16_ReadLong16 = 0x9E,
|
||||
eCmdWriteLong16 = 0x9F,
|
||||
eCmdReportLuns = 0xA0
|
||||
};
|
||||
};
|
||||
|
||||
enum class status : int {
|
||||
GOOD = 0x00,
|
||||
CHECK_CONDITION = 0x02,
|
||||
RESERVATION_CONFLICT = 0x18
|
||||
};
|
||||
enum class status : int { GOOD = 0x00, CHECK_CONDITION = 0x02, RESERVATION_CONFLICT = 0x18 };
|
||||
|
||||
enum class sense_key : int {
|
||||
enum class sense_key : int {
|
||||
NO_SENSE = 0x00,
|
||||
NOT_READY = 0x02,
|
||||
MEDIUM_ERROR = 0x03,
|
||||
@ -102,9 +114,9 @@ namespace scsi_defs {
|
||||
UNIT_ATTENTION = 0x06,
|
||||
DATA_PROTECT = 0x07,
|
||||
ABORTED_COMMAND = 0x0b
|
||||
};
|
||||
};
|
||||
|
||||
enum class asc : int {
|
||||
enum class asc : int {
|
||||
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
|
||||
WRITE_FAULT = 0x03,
|
||||
READ_FAULT = 0x11,
|
||||
@ -118,50 +130,49 @@ namespace scsi_defs {
|
||||
POWER_ON_OR_RESET = 0x29,
|
||||
MEDIUM_NOT_PRESENT = 0x3a,
|
||||
LOAD_OR_EJECT_FAILED = 0x53
|
||||
};
|
||||
|
||||
static const unordered_map<scsi_command, pair<int, const char *>> command_mapping = {
|
||||
{ scsi_command::eCmdTestUnitReady, make_pair(6, "TestUnitReady") },
|
||||
{ scsi_command::eCmdRezero, make_pair(6, "Rezero") },
|
||||
{ scsi_command::eCmdRequestSense, make_pair(6, "RequestSense") },
|
||||
{ scsi_command::eCmdFormatUnit, make_pair(6, "FormatUnit") },
|
||||
{ scsi_command::eCmdReassignBlocks, make_pair(6, "ReassignBlocks") },
|
||||
{ scsi_command::eCmdRead6, make_pair(6, "Read6/GetMessage10") },
|
||||
{ scsi_command::eCmdRetrieveStats,make_pair( 6, "RetrieveStats") },
|
||||
{ scsi_command::eCmdWrite6, make_pair(6, "Write6/Print/SendMessage10") },
|
||||
{ scsi_command::eCmdSeek6, make_pair(6, "Seek6") },
|
||||
{ scsi_command::eCmdSetIfaceMode, make_pair(6, "SetIfaceMode") },
|
||||
{ scsi_command::eCmdSetMcastAddr, make_pair(6, "SetMcastAddr") },
|
||||
{ scsi_command::eCmdEnableInterface, make_pair(6, "EnableInterface") },
|
||||
{ scsi_command::eCmdSynchronizeBuffer, make_pair(6, "SynchronizeBuffer") },
|
||||
{ scsi_command::eCmdInquiry, make_pair(6, "Inquiry") },
|
||||
{ scsi_command::eCmdModeSelect6, make_pair(6, "ModeSelect6") },
|
||||
{ scsi_command::eCmdReserve6, make_pair(6, "Reserve6") },
|
||||
{ scsi_command::eCmdRelease6, make_pair(6, "Release6") },
|
||||
{ scsi_command::eCmdModeSense6, make_pair(6, "ModeSense6") },
|
||||
{ scsi_command::eCmdStartStop, make_pair(6, "StartStop") },
|
||||
{ scsi_command::eCmdStopPrint, make_pair(6, "StopPrint") },
|
||||
{ scsi_command::eCmdSendDiagnostic, make_pair(6, "SendDiagnostic") },
|
||||
{ scsi_command::eCmdPreventAllowMediumRemoval, make_pair(6, "PreventAllowMediumRemoval") },
|
||||
{ scsi_command::eCmdReadCapacity10, make_pair(10, "ReadCapacity10") },
|
||||
{ scsi_command::eCmdRead10, make_pair(10, "Read10") },
|
||||
{ scsi_command::eCmdWrite10, make_pair(10, "Write10") },
|
||||
{ scsi_command::eCmdSeek10, make_pair(10, "Seek10") },
|
||||
{ scsi_command::eCmdVerify10, make_pair(10, "Verify10") },
|
||||
{ scsi_command::eCmdSynchronizeCache10, make_pair(10, "SynchronizeCache10") },
|
||||
{ scsi_command::eCmdReadDefectData10, make_pair(10, "ReadDefectData10") },
|
||||
{ scsi_command::eCmdReadLong10, make_pair(10, "ReadLong10") },
|
||||
{ scsi_command::eCmdWriteLong10, make_pair(10, "WriteLong10") },
|
||||
{ scsi_command::eCmdReadToc, make_pair(10, "ReadToc") },
|
||||
{ scsi_command::eCmdGetEventStatusNotification, make_pair(10, "GetEventStatusNotification") },
|
||||
{ scsi_command::eCmdModeSelect10, make_pair(10, "ModeSelect10") },
|
||||
{ scsi_command::eCmdModeSense10, make_pair(10, "ModeSense10") },
|
||||
{ scsi_command::eCmdRead16, make_pair(16, "Read16") },
|
||||
{ scsi_command::eCmdWrite16, make_pair(16, "Write16") },
|
||||
{ scsi_command::eCmdVerify16, make_pair(16, "Verify16") },
|
||||
{ scsi_command::eCmdSynchronizeCache16, make_pair(16, "SynchronizeCache16") },
|
||||
{ scsi_command::eCmdReadCapacity16_ReadLong16, make_pair(16, "ReadCapacity16/ReadLong16") },
|
||||
{ scsi_command::eCmdWriteLong16, make_pair(16, "WriteLong16") },
|
||||
{ scsi_command::eCmdReportLuns, make_pair(12, "ReportLuns") }
|
||||
};
|
||||
};
|
||||
|
||||
static const unordered_map<scsi_command, pair<int, const char *>> command_mapping = {
|
||||
{scsi_command::eCmdTestUnitReady, make_pair(6, "TestUnitReady")},
|
||||
{scsi_command::eCmdRezero, make_pair(6, "Rezero")},
|
||||
{scsi_command::eCmdRequestSense, make_pair(6, "RequestSense")},
|
||||
{scsi_command::eCmdFormatUnit, make_pair(6, "FormatUnit")},
|
||||
{scsi_command::eCmdReassignBlocks, make_pair(6, "ReassignBlocks")},
|
||||
{scsi_command::eCmdRead6, make_pair(6, "Read6/GetMessage10")},
|
||||
{scsi_command::eCmdRetrieveStats, make_pair(6, "RetrieveStats")},
|
||||
{scsi_command::eCmdWrite6, make_pair(6, "Write6/Print/SendMessage10")},
|
||||
{scsi_command::eCmdSeek6, make_pair(6, "Seek6")},
|
||||
{scsi_command::eCmdSetIfaceMode, make_pair(6, "SetIfaceMode")},
|
||||
{scsi_command::eCmdSetMcastAddr, make_pair(6, "SetMcastAddr")},
|
||||
{scsi_command::eCmdEnableInterface, make_pair(6, "EnableInterface")},
|
||||
{scsi_command::eCmdSynchronizeBuffer, make_pair(6, "SynchronizeBuffer")},
|
||||
{scsi_command::eCmdInquiry, make_pair(6, "Inquiry")},
|
||||
{scsi_command::eCmdModeSelect6, make_pair(6, "ModeSelect6")},
|
||||
{scsi_command::eCmdReserve6, make_pair(6, "Reserve6")},
|
||||
{scsi_command::eCmdRelease6, make_pair(6, "Release6")},
|
||||
{scsi_command::eCmdModeSense6, make_pair(6, "ModeSense6")},
|
||||
{scsi_command::eCmdStartStop, make_pair(6, "StartStop")},
|
||||
{scsi_command::eCmdStopPrint, make_pair(6, "StopPrint")},
|
||||
{scsi_command::eCmdSendDiagnostic, make_pair(6, "SendDiagnostic")},
|
||||
{scsi_command::eCmdPreventAllowMediumRemoval, make_pair(6, "PreventAllowMediumRemoval")},
|
||||
{scsi_command::eCmdReadCapacity10, make_pair(10, "ReadCapacity10")},
|
||||
{scsi_command::eCmdRead10, make_pair(10, "Read10")},
|
||||
{scsi_command::eCmdWrite10, make_pair(10, "Write10")},
|
||||
{scsi_command::eCmdSeek10, make_pair(10, "Seek10")},
|
||||
{scsi_command::eCmdVerify10, make_pair(10, "Verify10")},
|
||||
{scsi_command::eCmdSynchronizeCache10, make_pair(10, "SynchronizeCache10")},
|
||||
{scsi_command::eCmdReadDefectData10, make_pair(10, "ReadDefectData10")},
|
||||
{scsi_command::eCmdReadLong10, make_pair(10, "ReadLong10")},
|
||||
{scsi_command::eCmdWriteLong10, make_pair(10, "WriteLong10")},
|
||||
{scsi_command::eCmdReadToc, make_pair(10, "ReadToc")},
|
||||
{scsi_command::eCmdGetEventStatusNotification, make_pair(10, "GetEventStatusNotification")},
|
||||
{scsi_command::eCmdModeSelect10, make_pair(10, "ModeSelect10")},
|
||||
{scsi_command::eCmdModeSense10, make_pair(10, "ModeSense10")},
|
||||
{scsi_command::eCmdRead16, make_pair(16, "Read16")},
|
||||
{scsi_command::eCmdWrite16, make_pair(16, "Write16")},
|
||||
{scsi_command::eCmdVerify16, make_pair(16, "Verify16")},
|
||||
{scsi_command::eCmdSynchronizeCache16, make_pair(16, "SynchronizeCache16")},
|
||||
{scsi_command::eCmdReadCapacity16_ReadLong16, make_pair(16, "ReadCapacity16/ReadLong16")},
|
||||
{scsi_command::eCmdWriteLong16, make_pair(16, "WriteLong16")},
|
||||
{scsi_command::eCmdReportLuns, make_pair(12, "ReportLuns")}};
|
||||
}; // namespace scsi_defs
|
||||
|
@ -45,8 +45,8 @@ TEST(AbstractControllerTest, Reset)
|
||||
|
||||
controller->AddDevice(device);
|
||||
|
||||
controller->SetPhase(BUS::phase_t::status);
|
||||
EXPECT_EQ(BUS::phase_t::status, controller->GetPhase());
|
||||
controller->SetPhase(phase_t::status);
|
||||
EXPECT_EQ(phase_t::status, controller->GetPhase());
|
||||
controller->Reset();
|
||||
EXPECT_TRUE(controller->IsBusFree());
|
||||
EXPECT_EQ(status::GOOD, controller->GetStatus());
|
||||
@ -124,44 +124,44 @@ TEST(AbstractControllerTest, ProcessPhase)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockAbstractController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::selection);
|
||||
controller.SetPhase(phase_t::selection);
|
||||
EXPECT_CALL(controller, Selection);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::busfree);
|
||||
controller.SetPhase(phase_t::busfree);
|
||||
EXPECT_CALL(controller, BusFree);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::datain);
|
||||
controller.SetPhase(phase_t::datain);
|
||||
EXPECT_CALL(controller, DataIn);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::dataout);
|
||||
controller.SetPhase(phase_t::dataout);
|
||||
EXPECT_CALL(controller, DataOut);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::command);
|
||||
controller.SetPhase(phase_t::command);
|
||||
EXPECT_CALL(controller, Command);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::status);
|
||||
controller.SetPhase(phase_t::status);
|
||||
EXPECT_CALL(controller, Status);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgin);
|
||||
controller.SetPhase(phase_t::msgin);
|
||||
EXPECT_CALL(controller, MsgIn);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgout);
|
||||
controller.SetPhase(phase_t::msgout);
|
||||
EXPECT_CALL(controller, MsgOut);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reselection);
|
||||
controller.SetPhase(phase_t::reselection);
|
||||
EXPECT_THAT([&] { controller.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
|
||||
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
|
||||
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_THAT([&] { controller.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
|
||||
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
|
||||
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
|
||||
|
@ -7,8 +7,8 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "hal/bus.h"
|
||||
#include "mocks.h"
|
||||
|
||||
TEST(BusTest, GetCommandByteCount)
|
||||
{
|
||||
@ -59,78 +59,70 @@ TEST(BusTest, GetCommandByteCount)
|
||||
|
||||
TEST(BusTest, GetPhase)
|
||||
{
|
||||
EXPECT_EQ(BUS::phase_t::dataout, BUS::GetPhase(0b000));
|
||||
EXPECT_EQ(BUS::phase_t::datain, BUS::GetPhase(0b001));
|
||||
EXPECT_EQ(BUS::phase_t::command, BUS::GetPhase(0b010));
|
||||
EXPECT_EQ(BUS::phase_t::status, BUS::GetPhase(0b011));
|
||||
EXPECT_EQ(BUS::phase_t::reserved, BUS::GetPhase(0b100));
|
||||
EXPECT_EQ(BUS::phase_t::reserved, BUS::GetPhase(0b101));
|
||||
EXPECT_EQ(BUS::phase_t::msgout, BUS::GetPhase(0b110));
|
||||
EXPECT_EQ(BUS::phase_t::msgin, BUS::GetPhase(0b111));
|
||||
EXPECT_EQ(phase_t::dataout, BUS::GetPhase(0b000));
|
||||
EXPECT_EQ(phase_t::datain, BUS::GetPhase(0b001));
|
||||
EXPECT_EQ(phase_t::command, BUS::GetPhase(0b010));
|
||||
EXPECT_EQ(phase_t::status, BUS::GetPhase(0b011));
|
||||
EXPECT_EQ(phase_t::reserved, BUS::GetPhase(0b100));
|
||||
EXPECT_EQ(phase_t::reserved, BUS::GetPhase(0b101));
|
||||
EXPECT_EQ(phase_t::msgout, BUS::GetPhase(0b110));
|
||||
EXPECT_EQ(phase_t::msgin, BUS::GetPhase(0b111));
|
||||
|
||||
NiceMock<MockBus> bus;
|
||||
|
||||
EXPECT_EQ(BUS::phase_t::busfree, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::busfree, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetSEL()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::selection, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::selection, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetSEL()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetBSY()).WillByDefault(Return(true));
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
|
||||
EXPECT_EQ(BUS::phase_t::dataout, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::dataout, bus.GetPhase());
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::reserved, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::command, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::command, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::msgout, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::msgout, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::datain, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::datain, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::reserved, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
|
||||
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::msgin, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::msgin, bus.GetPhase());
|
||||
|
||||
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
|
||||
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
|
||||
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
|
||||
EXPECT_EQ(BUS::phase_t::status, bus.GetPhase());
|
||||
EXPECT_EQ(phase_t::status, bus.GetPhase());
|
||||
}
|
||||
|
||||
TEST(BusTest, GetPhaseStrRaw)
|
||||
{
|
||||
EXPECT_STREQ("busfree", BUS::GetPhaseStrRaw(BUS::phase_t::busfree));
|
||||
EXPECT_STREQ("arbitration", BUS::GetPhaseStrRaw(BUS::phase_t::arbitration));
|
||||
EXPECT_STREQ("selection", BUS::GetPhaseStrRaw(BUS::phase_t::selection));
|
||||
EXPECT_STREQ("reselection", BUS::GetPhaseStrRaw(BUS::phase_t::reselection));
|
||||
EXPECT_STREQ("command", BUS::GetPhaseStrRaw(BUS::phase_t::command));
|
||||
EXPECT_STREQ("datain", BUS::GetPhaseStrRaw(BUS::phase_t::datain));
|
||||
EXPECT_STREQ("dataout", BUS::GetPhaseStrRaw(BUS::phase_t::dataout));
|
||||
EXPECT_STREQ("status", BUS::GetPhaseStrRaw(BUS::phase_t::status));
|
||||
EXPECT_STREQ("msgin", BUS::GetPhaseStrRaw(BUS::phase_t::msgin));
|
||||
EXPECT_STREQ("msgout", BUS::GetPhaseStrRaw(BUS::phase_t::msgout));
|
||||
EXPECT_STREQ("reserved", BUS::GetPhaseStrRaw(BUS::phase_t::reserved));
|
||||
}
|
||||
|
||||
TEST(BusTest, GetPinRaw)
|
||||
{
|
||||
EXPECT_EQ(0, BUS::GetPinRaw(0, 0));
|
||||
EXPECT_EQ(0, BUS::GetPinRaw(0, 7));
|
||||
EXPECT_EQ(1, BUS::GetPinRaw(-1, 0));
|
||||
EXPECT_EQ(1, BUS::GetPinRaw(-1, 7));
|
||||
EXPECT_STREQ("busfree", BUS::GetPhaseStrRaw(phase_t::busfree));
|
||||
EXPECT_STREQ("arbitration", BUS::GetPhaseStrRaw(phase_t::arbitration));
|
||||
EXPECT_STREQ("selection", BUS::GetPhaseStrRaw(phase_t::selection));
|
||||
EXPECT_STREQ("reselection", BUS::GetPhaseStrRaw(phase_t::reselection));
|
||||
EXPECT_STREQ("command", BUS::GetPhaseStrRaw(phase_t::command));
|
||||
EXPECT_STREQ("datain", BUS::GetPhaseStrRaw(phase_t::datain));
|
||||
EXPECT_STREQ("dataout", BUS::GetPhaseStrRaw(phase_t::dataout));
|
||||
EXPECT_STREQ("status", BUS::GetPhaseStrRaw(phase_t::status));
|
||||
EXPECT_STREQ("msgin", BUS::GetPhaseStrRaw(phase_t::msgin));
|
||||
EXPECT_STREQ("msgout", BUS::GetPhaseStrRaw(phase_t::msgout));
|
||||
EXPECT_STREQ("reserved", BUS::GetPhaseStrRaw(phase_t::reserved));
|
||||
}
|
||||
|
234
cpp/test/gpiobus_raspberry_test.cpp
Normal file
234
cpp/test/gpiobus_raspberry_test.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "hal/gpiobus_raspberry.h"
|
||||
#include "mocks.h"
|
||||
#include "stdlib.h"
|
||||
#include "test/test_shared.h"
|
||||
|
||||
class SetableGpiobusRaspberry : public GPIOBUS_Raspberry
|
||||
{
|
||||
public:
|
||||
void TestSetGpios(uint32_t value)
|
||||
{
|
||||
*level = ~value;
|
||||
}
|
||||
void TestSetGpioPin(int pin, bool value)
|
||||
{
|
||||
// Level is inverted logic
|
||||
if (!value) {
|
||||
*level |= (1 << pin);
|
||||
} else {
|
||||
*level &= ~(1 << pin);
|
||||
}
|
||||
}
|
||||
SetableGpiobusRaspberry()
|
||||
{
|
||||
level = new uint32_t(); // NOSONAR: This is a pointer to a register on the real hardware
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
uint32_t get_dt_ranges(const char *filename, uint32_t offset);
|
||||
uint32_t bcm_host_get_peripheral_address();
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetDtRanges)
|
||||
{
|
||||
string soc_ranges_file = "/proc/device-tree/soc/ranges";
|
||||
|
||||
vector<uint8_t> data;
|
||||
// If bytes 4-7 are non-zero, get_peripheral address should return those bytes
|
||||
data = vector<uint8_t>(
|
||||
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF});
|
||||
CreateTempFileWithData(soc_ranges_file, data);
|
||||
EXPECT_EQ(0x44556677, GPIOBUS_Raspberry::bcm_host_get_peripheral_address());
|
||||
DeleteTempFile("/proc/device-tree/soc/ranges");
|
||||
|
||||
// If bytes 4-7 are zero, get_peripheral address should return bytes 8-11
|
||||
data = vector<uint8_t>(
|
||||
{0x00, 0x11, 0x22, 0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF});
|
||||
CreateTempFileWithData(soc_ranges_file, data);
|
||||
EXPECT_EQ(0x8899AABB, GPIOBUS_Raspberry::bcm_host_get_peripheral_address());
|
||||
DeleteTempFile("/proc/device-tree/soc/ranges");
|
||||
|
||||
// If bytes 4-7 are zero, and 8-11 are 0xFF, get_peripheral address should return a default address of 0x20000000
|
||||
data = vector<uint8_t>(
|
||||
{0x00, 0x11, 0x22, 0x33, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xDD, 0xEE, 0xFF});
|
||||
CreateTempFileWithData(soc_ranges_file, data);
|
||||
EXPECT_EQ(0x20000000, GPIOBUS_Raspberry::bcm_host_get_peripheral_address());
|
||||
DeleteTempFile("/proc/device-tree/soc/ranges");
|
||||
|
||||
CleanupAllTempFiles();
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetDat)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
EXPECT_EQ(0, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT0, true);
|
||||
EXPECT_EQ(0x01, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT1, true);
|
||||
EXPECT_EQ(0x03, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT2, true);
|
||||
EXPECT_EQ(0x07, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT3, true);
|
||||
EXPECT_EQ(0x0F, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT4, true);
|
||||
EXPECT_EQ(0x1F, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT5, true);
|
||||
EXPECT_EQ(0x3F, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT6, true);
|
||||
EXPECT_EQ(0x7F, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpioPin(PIN_DT7, true);
|
||||
EXPECT_EQ(0xFF, bus.GetDAT());
|
||||
|
||||
bus.TestSetGpios(0xFFFFFFFF);
|
||||
EXPECT_EQ(0xFF, bus.GetDAT());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetBSY)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_BSY, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetBSY());
|
||||
bus.TestSetGpioPin(PIN_BSY, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetBSY());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetSEL)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_SEL, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetSEL());
|
||||
bus.TestSetGpioPin(PIN_SEL, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetSEL());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetATN)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_ATN, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetATN());
|
||||
bus.TestSetGpioPin(PIN_ATN, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetATN());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetACK)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_ACK, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetACK());
|
||||
bus.TestSetGpioPin(PIN_ACK, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetACK());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetRST)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_RST, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetRST());
|
||||
bus.TestSetGpioPin(PIN_RST, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetRST());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetMSG)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_MSG, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetMSG());
|
||||
bus.TestSetGpioPin(PIN_MSG, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetMSG());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetCD)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_CD, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetCD());
|
||||
bus.TestSetGpioPin(PIN_CD, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetCD());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetIO)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_IO, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetIO());
|
||||
bus.TestSetGpioPin(PIN_IO, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetIO());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetREQ)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_REQ, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetREQ());
|
||||
bus.TestSetGpioPin(PIN_REQ, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetREQ());
|
||||
}
|
||||
|
||||
TEST(GpiobusRaspberry, GetDP)
|
||||
{
|
||||
SetableGpiobusRaspberry bus;
|
||||
|
||||
bus.TestSetGpios(0x00);
|
||||
bus.TestSetGpioPin(PIN_DP, true);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(true, bus.GetDP());
|
||||
bus.TestSetGpioPin(PIN_DP, false);
|
||||
bus.Acquire();
|
||||
EXPECT_EQ(false, bus.GetDP());
|
||||
}
|
59
cpp/test/linux_os_stubs.cpp
Normal file
59
cpp/test/linux_os_stubs.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "test/linux_os_stubs.h"
|
||||
#include "test/test_shared.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace filesystem;
|
||||
|
||||
extern "C" {
|
||||
|
||||
#ifdef __USE_LARGEFILE64
|
||||
FILE *__wrap_fopen64(const char *__restrict __filename, const char *__restrict __modes)
|
||||
#else
|
||||
FILE *__wrap_fopen(const char *__restrict __filename, const char *__restrict __modes)
|
||||
#endif
|
||||
{
|
||||
path new_filename;
|
||||
bool create_directory = false;
|
||||
|
||||
// If we're trying to open up the device tree soc ranges,
|
||||
// re-direct it to a temporary local file.
|
||||
if (string(__filename) == "/proc/device-tree/soc/ranges") {
|
||||
create_directory = true;
|
||||
new_filename = test_data_temp_path;
|
||||
new_filename += path(__filename);
|
||||
} else {
|
||||
new_filename = path(__filename);
|
||||
}
|
||||
|
||||
if (create_directory) {
|
||||
create_directories(new_filename.parent_path());
|
||||
}
|
||||
#ifdef __USE_LARGEFILE64
|
||||
return __real_fopen64(new_filename.c_str(), __modes);
|
||||
#else
|
||||
return __real_fopen(new_filename.c_str(), __modes);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end extern "C"
|
21
cpp/test/linux_os_stubs.h
Normal file
21
cpp/test/linux_os_stubs.h
Normal file
@ -0,0 +1,21 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 akuker
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// This header file should ONLY be used in test procedures. It bypasses the
|
||||
// standard c library functionality. DO NOT USE THIS IN PRODUCTION CODE.
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#ifdef __USE_LARGEFILE64
|
||||
FILE *__real_fopen64(const char *__restrict __filename, const char *__restrict __modes);
|
||||
#else
|
||||
FILE *__real_fopen(const char *__restrict __filename, const char *__restrict __modes);
|
||||
#endif
|
||||
}
|
@ -53,6 +53,9 @@ public:
|
||||
MOCK_METHOD(void, SetIO, (bool), (override));
|
||||
MOCK_METHOD(bool, GetREQ, (), (const override));
|
||||
MOCK_METHOD(void, SetREQ, (bool), (override));
|
||||
MOCK_METHOD(bool, GetACT, (), (const override));
|
||||
MOCK_METHOD(void, SetACT, (bool), (override));
|
||||
MOCK_METHOD(void, SetENB, (bool), (override));
|
||||
MOCK_METHOD(uint8_t, GetDAT, (), (override));
|
||||
MOCK_METHOD(void, SetDAT, (uint8_t), (override));
|
||||
MOCK_METHOD(bool, GetDP, (), (const override));
|
||||
@ -62,6 +65,14 @@ public:
|
||||
MOCK_METHOD(int, SendHandShake, (uint8_t *, int, int), (override));
|
||||
MOCK_METHOD(bool, GetSignal, (int), (const override));
|
||||
MOCK_METHOD(void, SetSignal, (int, bool), (override));
|
||||
MOCK_METHOD(bool, PollSelectEvent, (), (override));
|
||||
MOCK_METHOD(void, ClearSelectEvent, (), (override));
|
||||
MOCK_METHOD(unique_ptr<DataSample>, GetSample, (uint64_t), (override));
|
||||
MOCK_METHOD(void, PinConfig, (int, int), (override));
|
||||
MOCK_METHOD(void, PullConfig, (int , int ), (override));
|
||||
MOCK_METHOD(void, SetControl, (int , bool ), (override));
|
||||
MOCK_METHOD(void, SetMode, (int , int ), (override));
|
||||
MOCK_METHOD(int, GetMode, (int ), (override));
|
||||
|
||||
MockBus() = default;
|
||||
~MockBus() override = default;
|
||||
@ -73,7 +84,7 @@ class MockPhaseHandler : public PhaseHandler
|
||||
|
||||
public:
|
||||
|
||||
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(void, Status, (), ());
|
||||
MOCK_METHOD(void, DataIn, (), ());
|
||||
MOCK_METHOD(void, DataOut, (), ());
|
||||
@ -140,7 +151,7 @@ class MockAbstractController : public AbstractController //NOSONAR Having many f
|
||||
|
||||
public:
|
||||
|
||||
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(int, GetEffectiveLun, (), (const override));
|
||||
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
|
||||
MOCK_METHOD(int, GetInitiatorId, (), (const override));
|
||||
|
@ -14,7 +14,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
{
|
||||
MockPhaseHandler handler;
|
||||
|
||||
handler.SetPhase(BUS::phase_t::selection);
|
||||
handler.SetPhase(phase_t::selection);
|
||||
EXPECT_TRUE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
@ -24,7 +24,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::busfree);
|
||||
handler.SetPhase(phase_t::busfree);
|
||||
EXPECT_TRUE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
@ -34,7 +34,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::command);
|
||||
handler.SetPhase(phase_t::command);
|
||||
EXPECT_TRUE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
@ -44,7 +44,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::status);
|
||||
handler.SetPhase(phase_t::status);
|
||||
EXPECT_TRUE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
@ -54,7 +54,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::datain);
|
||||
handler.SetPhase(phase_t::datain);
|
||||
EXPECT_TRUE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
@ -64,7 +64,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::dataout);
|
||||
handler.SetPhase(phase_t::dataout);
|
||||
EXPECT_TRUE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
@ -74,7 +74,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::msgin);
|
||||
handler.SetPhase(phase_t::msgin);
|
||||
EXPECT_TRUE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
@ -84,7 +84,7 @@ TEST(PhaseHandlerTest, Phases)
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::msgout);
|
||||
handler.SetPhase(phase_t::msgout);
|
||||
EXPECT_TRUE(handler.IsMsgOut());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
|
@ -34,26 +34,26 @@ TEST(ScsiControllerTest, Process)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
ON_CALL(*bus, GetRST).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST);
|
||||
EXPECT_CALL(*bus, Reset);
|
||||
EXPECT_CALL(controller, Reset);
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller.Process(0));
|
||||
EXPECT_EQ(phase_t::reserved, controller.Process(0));
|
||||
|
||||
controller.SetPhase(BUS::phase_t::busfree);
|
||||
controller.SetPhase(phase_t::busfree);
|
||||
ON_CALL(*bus, GetRST).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST);
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.Process(0));
|
||||
EXPECT_EQ(phase_t::busfree, controller.Process(0));
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST);
|
||||
EXPECT_CALL(*bus, Reset);
|
||||
EXPECT_CALL(controller, Reset);
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.Process(0));
|
||||
EXPECT_EQ(phase_t::busfree, controller.Process(0));
|
||||
}
|
||||
|
||||
TEST(ScsiControllerTest, BusFree)
|
||||
@ -62,30 +62,30 @@ TEST(ScsiControllerTest, BusFree)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::busfree);
|
||||
controller.SetPhase(phase_t::busfree);
|
||||
controller.BusFree();
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
|
||||
|
||||
controller.SetStatus(status::CHECK_CONDITION);
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.BusFree();
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
|
||||
controller.ScheduleShutdown(AbstractController::rascsi_shutdown_mode::NONE);
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.BusFree();
|
||||
|
||||
controller.ScheduleShutdown(AbstractController::rascsi_shutdown_mode::STOP_PI);
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.BusFree();
|
||||
|
||||
controller.ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI);
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.BusFree();
|
||||
|
||||
controller.ScheduleShutdown(AbstractController::rascsi_shutdown_mode::STOP_RASCSI);
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_EXIT(controller.BusFree(), ExitedWithCode(EXIT_SUCCESS), "");
|
||||
}
|
||||
|
||||
@ -95,55 +95,55 @@ TEST(ScsiControllerTest, Selection)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
auto controller = make_shared<MockScsiController>(controller_manager, 0);
|
||||
|
||||
controller->SetPhase(BUS::phase_t::selection);
|
||||
controller->SetPhase(phase_t::selection);
|
||||
ON_CALL(*bus, GetSEL).WillByDefault(Return(true));
|
||||
ON_CALL(*bus, GetBSY).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*bus, GetATN).Times(0);
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::selection, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::selection, controller->GetPhase());
|
||||
|
||||
ON_CALL(*bus, GetSEL).WillByDefault(Return(true));
|
||||
ON_CALL(*bus, GetBSY).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*bus, GetATN).Times(0);
|
||||
EXPECT_CALL(*controller, Status);
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::selection, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::selection, controller->GetPhase());
|
||||
|
||||
ON_CALL(*bus, GetSEL).WillByDefault(Return(false));
|
||||
ON_CALL(*bus, GetBSY).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*bus, GetATN).Times(0);
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::selection, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::selection, controller->GetPhase());
|
||||
|
||||
ON_CALL(*bus, GetSEL).WillByDefault(Return(false));
|
||||
ON_CALL(*bus, GetBSY).WillByDefault(Return(true));
|
||||
ON_CALL(*bus, GetATN).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*bus, GetATN);
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::command, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::command, controller->GetPhase());
|
||||
|
||||
controller->SetPhase(BUS::phase_t::selection);
|
||||
controller->SetPhase(phase_t::selection);
|
||||
ON_CALL(*bus, GetSEL).WillByDefault(Return(false));
|
||||
ON_CALL(*bus, GetBSY).WillByDefault(Return(true));
|
||||
ON_CALL(*bus, GetATN).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*bus, GetATN);
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::msgout, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::msgout, controller->GetPhase());
|
||||
|
||||
controller->SetPhase(BUS::phase_t::reserved);
|
||||
controller->SetPhase(phase_t::reserved);
|
||||
ON_CALL(*bus, GetDAT).WillByDefault(Return(0));
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, controller->GetPhase());
|
||||
|
||||
ON_CALL(*bus, GetDAT).WillByDefault(Return(1));
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller->GetPhase()) << "There is no device that can be selected";
|
||||
EXPECT_EQ(phase_t::reserved, controller->GetPhase()) << "There is no device that can be selected";
|
||||
|
||||
auto device = make_shared<MockPrimaryDevice>(0);
|
||||
controller->AddDevice(device);
|
||||
EXPECT_CALL(*bus, SetBSY(true));
|
||||
controller->Selection();
|
||||
EXPECT_EQ(BUS::phase_t::selection, controller->GetPhase());
|
||||
EXPECT_EQ(phase_t::selection, controller->GetPhase());
|
||||
}
|
||||
|
||||
TEST(ScsiControllerTest, Command)
|
||||
@ -152,26 +152,26 @@ TEST(ScsiControllerTest, Command)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::command);
|
||||
controller.SetPhase(phase_t::command);
|
||||
EXPECT_CALL(controller, Status);
|
||||
controller.Command();
|
||||
EXPECT_EQ(BUS::phase_t::command, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::command, controller.GetPhase());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, SetMSG(false));
|
||||
EXPECT_CALL(*bus, SetCD(true));
|
||||
EXPECT_CALL(*bus, SetIO(false));
|
||||
controller.Command();
|
||||
EXPECT_EQ(BUS::phase_t::command, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::command, controller.GetPhase());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
ON_CALL(*bus, CommandHandShake).WillByDefault(Return(6));
|
||||
EXPECT_CALL(*bus, SetMSG(false));
|
||||
EXPECT_CALL(*bus, SetCD(true));
|
||||
EXPECT_CALL(*bus, SetIO(false));
|
||||
EXPECT_CALL(controller, Execute);
|
||||
controller.Command();
|
||||
EXPECT_EQ(BUS::phase_t::command, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::command, controller.GetPhase());
|
||||
}
|
||||
|
||||
TEST(ScsiControllerTest, MsgIn)
|
||||
@ -180,12 +180,12 @@ TEST(ScsiControllerTest, MsgIn)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, SetMSG(true));
|
||||
EXPECT_CALL(*bus, SetCD(true));
|
||||
EXPECT_CALL(*bus, SetIO(true));
|
||||
controller.MsgIn();
|
||||
EXPECT_EQ(BUS::phase_t::msgin, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::msgin, controller.GetPhase());
|
||||
EXPECT_FALSE(controller.HasValidLength());
|
||||
EXPECT_EQ(0, controller.GetOffset());
|
||||
}
|
||||
@ -196,12 +196,12 @@ TEST(ScsiControllerTest, MsgOut)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, SetMSG(true));
|
||||
EXPECT_CALL(*bus, SetCD(true));
|
||||
EXPECT_CALL(*bus, SetIO(false));
|
||||
controller.MsgOut();
|
||||
EXPECT_EQ(BUS::phase_t::msgout, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::msgout, controller.GetPhase());
|
||||
EXPECT_EQ(1, controller.GetLength());
|
||||
EXPECT_EQ(0, controller.GetOffset());
|
||||
}
|
||||
@ -212,18 +212,18 @@ TEST(ScsiControllerTest, DataIn)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.SetLength(0);
|
||||
EXPECT_CALL(controller, Status);
|
||||
controller.DataIn();
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
|
||||
|
||||
controller.SetLength(1);
|
||||
EXPECT_CALL(*bus, SetMSG(false));
|
||||
EXPECT_CALL(*bus, SetCD(false));
|
||||
EXPECT_CALL(*bus, SetIO(true));
|
||||
controller.DataIn();
|
||||
EXPECT_EQ(BUS::phase_t::datain, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::datain, controller.GetPhase());
|
||||
EXPECT_EQ(0, controller.GetOffset());
|
||||
}
|
||||
|
||||
@ -233,18 +233,18 @@ TEST(ScsiControllerTest, DataOut)
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
controller.SetLength(0);
|
||||
EXPECT_CALL(controller, Status);
|
||||
controller.DataOut();
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
|
||||
|
||||
controller.SetLength(1);
|
||||
EXPECT_CALL(*bus, SetMSG(false));
|
||||
EXPECT_CALL(*bus, SetCD(false));
|
||||
EXPECT_CALL(*bus, SetIO(false));
|
||||
controller.DataOut();
|
||||
EXPECT_EQ(BUS::phase_t::dataout, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::dataout, controller.GetPhase());
|
||||
EXPECT_EQ(0, controller.GetOffset());
|
||||
}
|
||||
|
||||
@ -255,33 +255,33 @@ TEST(ScsiControllerTest, Error)
|
||||
MockScsiController controller(controller_manager, 0);
|
||||
|
||||
ON_CALL(*bus, GetRST).WillByDefault(Return(true));
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST());
|
||||
EXPECT_CALL(*bus, Reset);
|
||||
EXPECT_CALL(controller, Reset);
|
||||
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
|
||||
|
||||
ON_CALL(*bus, GetRST).WillByDefault(Return(false));
|
||||
controller.SetPhase(BUS::phase_t::status);
|
||||
controller.SetPhase(phase_t::status);
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST());
|
||||
EXPECT_CALL(*bus, Reset).Times(0);
|
||||
EXPECT_CALL(controller, Reset).Times(0);
|
||||
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgin);
|
||||
controller.SetPhase(phase_t::msgin);
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST());
|
||||
EXPECT_CALL(*bus, Reset).Times(0);
|
||||
EXPECT_CALL(controller, Reset).Times(0);
|
||||
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
|
||||
EXPECT_EQ(BUS::phase_t::busfree, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
controller.SetPhase(phase_t::reserved);
|
||||
EXPECT_CALL(*bus, Acquire);
|
||||
EXPECT_CALL(*bus, GetRST());
|
||||
EXPECT_CALL(*bus, Reset).Times(0);
|
||||
@ -289,7 +289,7 @@ TEST(ScsiControllerTest, Error)
|
||||
EXPECT_CALL(controller, Status);
|
||||
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
|
||||
EXPECT_EQ(status::RESERVATION_CONFLICT, controller.GetStatus());
|
||||
EXPECT_EQ(BUS::phase_t::reserved, controller.GetPhase());
|
||||
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
|
||||
}
|
||||
|
||||
TEST(ScsiControllerTest, RequestSense)
|
||||
|
@ -7,20 +7,26 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "test_shared.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "mocks.h"
|
||||
#include "shared/rascsi_exceptions.h"
|
||||
#include "shared/rascsi_version.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "test_shared.h"
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
|
||||
using namespace std;
|
||||
using namespace filesystem;
|
||||
|
||||
shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType type, MockAbstractController& controller, const string& extension)
|
||||
// Inlude the process id in the temp file path so that multiple instances of the test procedures
|
||||
// could run on the same host.
|
||||
const path test_data_temp_path(temp_directory_path() /
|
||||
path(fmt::format("rascsi-test-{}",
|
||||
getpid()))); // NOSONAR Publicly writable directory is fine here
|
||||
|
||||
shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType type, MockAbstractController &controller, const string &extension)
|
||||
{
|
||||
DeviceFactory device_factory;
|
||||
|
||||
@ -33,23 +39,23 @@ shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType type, MockAbstractController
|
||||
return device;
|
||||
}
|
||||
|
||||
void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string& ident, int additional_length,
|
||||
bool removable, const string& extension)
|
||||
void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string &ident, int additional_length,
|
||||
bool removable, const string &extension)
|
||||
{
|
||||
auto bus = make_shared<MockBus>();
|
||||
auto controller_manager = make_shared<ControllerManager>(*bus);
|
||||
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
|
||||
auto device = CreateDevice(type, *controller, extension);
|
||||
|
||||
auto& cmd = controller->GetCmd();
|
||||
auto &cmd = controller->GetCmd();
|
||||
|
||||
// ALLOCATION LENGTH
|
||||
cmd[4] = 255;
|
||||
EXPECT_CALL(*controller, DataIn());
|
||||
device->Dispatch(scsi_command::eCmdInquiry);
|
||||
const vector<uint8_t>& buffer = controller->GetBuffer();
|
||||
const vector<uint8_t> &buffer = controller->GetBuffer();
|
||||
EXPECT_EQ(t, static_cast<device_type>(buffer[0]));
|
||||
EXPECT_EQ(removable ? 0x80: 0x00, buffer[1]);
|
||||
EXPECT_EQ(removable ? 0x80 : 0x00, buffer[1]);
|
||||
EXPECT_EQ(l, static_cast<scsi_level>(buffer[2]));
|
||||
EXPECT_EQ(l > scsi_level::SCSI_2 ? scsi_level::SCSI_2 : l, static_cast<scsi_level>(buffer[3]));
|
||||
EXPECT_EQ(additional_length, buffer[4]);
|
||||
@ -58,8 +64,7 @@ void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string& i
|
||||
ostringstream s;
|
||||
s << ident << setw(2) << setfill('0') << rascsi_major_version << rascsi_minor_version;
|
||||
product_data = s.str();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
product_data = ident;
|
||||
}
|
||||
EXPECT_TRUE(!memcmp(product_data.c_str(), &buffer[8], 28));
|
||||
@ -67,10 +72,13 @@ void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string& i
|
||||
|
||||
pair<int, path> OpenTempFile()
|
||||
{
|
||||
const string filename = string(temp_directory_path()) + "/rascsi_test-XXXXXX"; //NOSONAR Publicly writable directory is fine here
|
||||
const string filename =
|
||||
string(test_data_temp_path) + "/rascsi_test-XXXXXX"; // NOSONAR Publicly writable directory is fine here
|
||||
vector<char> f(filename.begin(), filename.end());
|
||||
f.push_back(0);
|
||||
|
||||
create_directories(path(filename).parent_path());
|
||||
|
||||
const int fd = mkstemp(f.data());
|
||||
EXPECT_NE(-1, fd) << "Couldn't create temporary file '" << f.data() << "'";
|
||||
|
||||
@ -89,14 +97,48 @@ path CreateTempFile(int size)
|
||||
return path(filename);
|
||||
}
|
||||
|
||||
int GetInt16(const vector<byte>& buf, int offset)
|
||||
void CreateTempFileWithData(string filename, vector<uint8_t> &data)
|
||||
{
|
||||
path new_filename = test_data_temp_path;
|
||||
new_filename += path(filename);
|
||||
|
||||
create_directories(new_filename.parent_path());
|
||||
|
||||
FILE *fp = fopen(new_filename.c_str(), "wb");
|
||||
if (fp == nullptr) {
|
||||
printf("ERROR: Unable to open file %s\n", new_filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size_written = fwrite(&data[0], sizeof(uint8_t), data.size(), fp);
|
||||
|
||||
if (size_written != sizeof(vector<uint8_t>::value_type) * data.size()) {
|
||||
printf("Expected to write %zu bytes, but only wrote %zu to %s", size_written,
|
||||
sizeof(vector<uint8_t>::value_type) * data.size(), filename.c_str());
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void DeleteTempFile(string filename)
|
||||
{
|
||||
path temp_file = test_data_temp_path;
|
||||
temp_file += path(filename);
|
||||
remove(temp_file);
|
||||
}
|
||||
|
||||
void CleanupAllTempFiles()
|
||||
{
|
||||
remove_all(test_data_temp_path);
|
||||
}
|
||||
|
||||
int GetInt16(const vector<byte> &buf, int offset)
|
||||
{
|
||||
assert(buf.size() > static_cast<size_t>(offset) + 1);
|
||||
|
||||
return (to_integer<int>(buf[offset]) << 8) | to_integer<int>(buf[offset + 1]);
|
||||
}
|
||||
|
||||
uint32_t GetInt32(const vector<byte>& buf, int offset)
|
||||
uint32_t GetInt32(const vector<byte> &buf, int offset)
|
||||
{
|
||||
assert(buf.size() > static_cast<size_t>(offset) + 3);
|
||||
|
||||
|
@ -22,6 +22,8 @@ using namespace rascsi_interface;
|
||||
class PrimaryDevice;
|
||||
class MockAbstractController;
|
||||
|
||||
extern const path test_data_temp_path;
|
||||
|
||||
shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType, MockAbstractController&, const string& = "");
|
||||
|
||||
void TestInquiry(PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level, const string&,
|
||||
@ -30,5 +32,13 @@ void TestInquiry(PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level, co
|
||||
pair<int, path> OpenTempFile();
|
||||
path CreateTempFile(int);
|
||||
|
||||
|
||||
// create a file with the specified data
|
||||
void CreateTempFileWithData(string filename, vector<uint8_t> &data);
|
||||
|
||||
void DeleteTempFile(string filename);
|
||||
// Call this at the end of every test case to make sure things are cleaned up
|
||||
void CleanupAllTempFiles();
|
||||
|
||||
int GetInt16(const vector<byte>&, int);
|
||||
uint32_t GetInt32(const vector<byte>&, int);
|
||||
|
35
doc/scsiloop.1
Normal file
35
doc/scsiloop.1
Normal file
@ -0,0 +1,35 @@
|
||||
.TH scsiloop 1
|
||||
.SH NAME
|
||||
scsiloop \- Tool for testing the RaSCSI board with a loopback adapter installed
|
||||
.SH SYNOPSIS
|
||||
.B scsiloop
|
||||
[\fB\-L\fR \fILOG_LEVEL\fR]
|
||||
.SH DESCRIPTION
|
||||
.B scsiloop
|
||||
Performs a self-test of the RaSCSI hardware to ensure that the board is functioning properly. In order for this tool to work, a special loopback cable MUST be attached to the RaSCSI SCSI connector.
|
||||
|
||||
In addition to testing the GPIO signals, scsiloop will perform a self-test of the hardware timers that are built into the system on a chip (SoC).
|
||||
|
||||
The loopback connections for the DB25 connector are shown here:
|
||||
|
||||
|Pin | Name | Pin | Name |
|
||||
+----+------+-----+------+
|
||||
| 1 | REQ | 13 | DB7 |
|
||||
| 2 | MSG | 12 | DB6 |
|
||||
| 3 | I/O | 11 | DB5 |
|
||||
| 4 | RST | 10 | DB3 |
|
||||
| 5 | ACK | 8 | DB0 |
|
||||
| 6 | BSY | 20 | DBP |
|
||||
| 15 | C/D | 23 | DB4 |
|
||||
| 17 | ATN | 22 | DB2 |
|
||||
| 19 | SEL | 21 | DB1 |
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-L\fI " " \fILOG_LEVEL
|
||||
The rascsi log level (trace, debug, info, warn, err, off). The default log level is 'info'.
|
||||
|
||||
.SH SEE ALSO
|
||||
rasctl(1), rascsi(1), scsimon(1)
|
||||
|
||||
Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/>
|
41
doc/scsiloop_man_page.txt
Normal file
41
doc/scsiloop_man_page.txt
Normal file
@ -0,0 +1,41 @@
|
||||
!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!!
|
||||
!! ------ The native file is scsiloop.1. Re-run 'make docs' after updating
|
||||
|
||||
|
||||
scsiloop(1) General Commands Manual scsiloop(1)
|
||||
|
||||
NAME
|
||||
scsiloop - Tool for testing the RaSCSI board with a loopback adapter installed
|
||||
|
||||
SYNOPSIS
|
||||
scsiloop [-L LOG_LEVEL]
|
||||
|
||||
DESCRIPTION
|
||||
scsiloop Performs a self-test of the RaSCSI hardware to ensure that the board is functioning properly. In order for this tool to work, a special loopback cable MUST be attached to the RaSCSI SCSI connector.
|
||||
|
||||
In addition to testing the GPIO signals, scsiloop will perform a self-test of the hardware timers that are built into the system on a chip (SoC).
|
||||
|
||||
The loopback connections for the DB25 connector are shown here:
|
||||
|
||||
|Pin | Name | Pin | Name |
|
||||
+----+------+-----+------+
|
||||
| 1 | REQ | 13 | DB7 |
|
||||
| 2 | MSG | 12 | DB6 |
|
||||
| 3 | I/O | 11 | DB5 |
|
||||
| 4 | RST | 10 | DB3 |
|
||||
| 5 | ACK | 8 | DB0 |
|
||||
| 6 | BSY | 20 | DBP |
|
||||
| 15 | C/D | 23 | DB4 |
|
||||
| 17 | ATN | 22 | DB2 |
|
||||
| 19 | SEL | 21 | DB1 |
|
||||
|
||||
OPTIONS
|
||||
-L LOG_LEVEL
|
||||
The rascsi log level (trace, debug, info, warn, err, off). The default log level is 'info'.
|
||||
|
||||
SEE ALSO
|
||||
rasctl(1), rascsi(1), scsimon(1)
|
||||
|
||||
Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/>
|
||||
|
||||
scsiloop(1)
|
Loading…
Reference in New Issue
Block a user