|
| 1 | +// Copyright CERN and copyright holders of ALICE O2. This software is |
| 2 | +// distributed under the terms of the GNU General Public License v3 (GPL |
| 3 | +// Version 3), copied verbatim in the file "COPYING". |
| 4 | +// |
| 5 | +// See http://alice-o2.web.cern.ch/license for full licensing information. |
| 6 | +// |
| 7 | +// In applying this license CERN does not waive the privileges and immunities |
| 8 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 9 | +// or submit itself to any jurisdiction. |
| 10 | + |
| 11 | +/// \file AlfClient.cxx |
| 12 | +/// \brief Definition of the command line tool to run an ALF client |
| 13 | +/// |
| 14 | +/// \author Pascal Boeschoten ([email protected]) |
| 15 | +/// \author Kostas Alexopoulos ([email protected]) |
| 16 | + |
| 17 | +#include <boost/algorithm/string/case_conv.hpp> |
| 18 | +#include <boost/asio.hpp> |
| 19 | +#include <chrono> |
| 20 | +#include <cstdlib> |
| 21 | +#include <thread> |
| 22 | + |
| 23 | +#include "AlfClient.h" |
| 24 | +#include "Common/Program.h" |
| 25 | +#include "Common/GuardFunction.h" |
| 26 | +#include "DimServices/ServiceNames.h" |
| 27 | +#include "Logger.h" |
| 28 | + |
| 29 | +namespace ip = boost::asio::ip; |
| 30 | +namespace po = boost::program_options; |
| 31 | + |
| 32 | +namespace AliceO2 |
| 33 | +{ |
| 34 | +namespace Alf |
| 35 | +{ |
| 36 | + |
| 37 | +AliceO2::InfoLogger::InfoLogger logger; |
| 38 | + |
| 39 | +class AlfClient : public AliceO2::Common::Program |
| 40 | +{ |
| 41 | + public: |
| 42 | + AlfClient() |
| 43 | + { |
| 44 | + } |
| 45 | + |
| 46 | + virtual Description getDescription() override |
| 47 | + { |
| 48 | + return { "ALF DIM Client", "ALICE Low-level Front-end DIM client", "o2-alf-client" }; |
| 49 | + } |
| 50 | + |
| 51 | + virtual void addOptions(po::options_description& options) override |
| 52 | + { |
| 53 | + options.add_options()("dim-dns-node", |
| 54 | + po::value<std::string>(&mOptions.dimDnsNode)->default_value(""), |
| 55 | + "The DIM DNS node to connect to if the env var is not set"); |
| 56 | + options.add_options()("serial", |
| 57 | + po::value<int>(&mOptions.serial), |
| 58 | + "CRU serial number"); |
| 59 | + options.add_options()("link", |
| 60 | + po::value<int>(&mOptions.link), |
| 61 | + "Link number"); |
| 62 | + options.add_options()("alf-id", |
| 63 | + po::value<std::string>(&mOptions.alfId)->default_value(""), |
| 64 | + "Hostname of node running the ALF server(required)"); |
| 65 | + options.add_options()("ic", |
| 66 | + po::bool_switch(&mOptions.ic)->default_value(false), |
| 67 | + "Flag enabling the ic tests"); |
| 68 | + options.add_options()("sca", |
| 69 | + po::bool_switch(&mOptions.sca)->default_value(false), |
| 70 | + "Flag enabling the sca tests"); |
| 71 | + options.add_options()("swt", |
| 72 | + po::bool_switch(&mOptions.swt)->default_value(false), |
| 73 | + "Flag enabling the swt tests"); |
| 74 | + options.add_options()("swt-stress", |
| 75 | + po::bool_switch(&mOptions.swtStress)->default_value(false), |
| 76 | + "Flag enabling the swt-stress tests"); |
| 77 | + options.add_options()("swt-stress-cycles", |
| 78 | + po::value<int>(&mOptions.swtStressCycles)->default_value(2), |
| 79 | + "Number of cycles for which to run the SWT stress test"); |
| 80 | + options.add_options()("swt-stress-words", |
| 81 | + po::value<int>(&mOptions.swtStressWords)->default_value(1000), |
| 82 | + "Number of SWT words to write and read in one go"); |
| 83 | + } |
| 84 | + |
| 85 | + virtual void run(const po::variables_map&) override |
| 86 | + { |
| 87 | + if (mOptions.alfId == "") { |
| 88 | + getErrorLogger() << "Parameter alf-id is required." << endm; |
| 89 | + return; |
| 90 | + } |
| 91 | + |
| 92 | + getLogger() << "ALF client initializations..." << endm; |
| 93 | + |
| 94 | + if (mOptions.dimDnsNode != "") { |
| 95 | + getLogger() << "Setting DIM_DNS_NODE from argument." << endm; |
| 96 | + getLogger() << "DIM_DNS_NODE=" << mOptions.dimDnsNode << endm; |
| 97 | + setenv("DIM_DNS_NODE", mOptions.dimDnsNode.c_str(), true); |
| 98 | + } else if (const char* dimDnsNode = std::getenv("DIM_DNS_NODE")) { |
| 99 | + getLogger() << "Picked up DIM_DMS_NODE from the environment." << endm; |
| 100 | + getLogger() << "DIM_DNS_NODE=" << dimDnsNode << endm; |
| 101 | + mOptions.dimDnsNode = dimDnsNode; |
| 102 | + } else { |
| 103 | + BOOST_THROW_EXCEPTION(AlfException() << ErrorInfo::Message("DIM_DNS_NODE env variable not set, and no relevant argument provided.")); // InfoLogger and errors? |
| 104 | + } |
| 105 | + |
| 106 | + std::string alfId = mOptions.alfId; |
| 107 | + boost::to_upper(alfId); |
| 108 | + |
| 109 | + getLogger() << "Starting the DIM Client using ALF ID=" << alfId << ", serial=" << mOptions.serial << " and link=" << mOptions.link << endm; |
| 110 | + |
| 111 | + AlfLink link = AlfLink{ alfId, mOptions.serial, mOptions.link, nullptr }; |
| 112 | + |
| 113 | + ServiceNames names(link); |
| 114 | + Alf::RegisterReadRpc registerReadRpc(names.registerRead()); |
| 115 | + Alf::RegisterWriteRpc registerWriteRpc(names.registerWrite()); |
| 116 | + Alf::SwtSequenceRpc swtSequence(names.swtSequence()); |
| 117 | + Alf::ScaSequenceRpc scaSequence(names.scaSequence()); |
| 118 | + Alf::IcSequenceRpc icSequence(names.icSequence()); |
| 119 | + Alf::IcGbtI2cWriteRpc icGbtI2cWriteRpc(names.icGbtI2cWrite()); |
| 120 | + |
| 121 | + // Test register write and read |
| 122 | + uint32_t wAddress = 0x00f00078; |
| 123 | + uint32_t wValue = 0x4; |
| 124 | + uint32_t rAddress = 0x00f0005c; |
| 125 | + registerWriteRpc.writeRegister(wAddress, wValue); |
| 126 | + uint32_t rValue = registerReadRpc.readRegister(rAddress); |
| 127 | + getLogger() << "[REGISTER] Wrote: " << Util::formatValue(wValue) << " Read: " << Util::formatValue(rValue) << endm; |
| 128 | + |
| 129 | + if (mOptions.swt) { |
| 130 | + auto swtOut = swtSequence.write({ std::make_pair("0x0000000000000000000", "write"), |
| 131 | + std::make_pair("", "reset"), |
| 132 | + std::make_pair("0x000000001234", "write"), |
| 133 | + std::make_pair("", "read"), |
| 134 | + std::make_pair("0xdeadbeef", "write"), |
| 135 | + std::make_pair("1", "read"), |
| 136 | + std::make_pair("0xbadc0ffee", "write"), |
| 137 | + std::make_pair("4", "read") }); |
| 138 | + getLogger() << "[SWT_SEQUENCE] output: " << swtOut << endm; |
| 139 | + } |
| 140 | + |
| 141 | + if (mOptions.swtStress) { |
| 142 | + for (int cycle = 0; cycle < mOptions.swtStressCycles; cycle++) { |
| 143 | + // Make the input pairs |
| 144 | + std::vector<std::pair<std::string, std::string>> swtStressPairs; |
| 145 | + swtStressPairs.push_back(std::make_pair("", "reset")); |
| 146 | + for (int i = 0; i < mOptions.swtStressWords; i++) { |
| 147 | + std::stringstream ss; |
| 148 | + ss << "0x" << std::hex << i; |
| 149 | + swtStressPairs.push_back(std::make_pair(ss.str(), "write")); |
| 150 | + } |
| 151 | + swtStressPairs.push_back(std::make_pair("1000", "read")); |
| 152 | + |
| 153 | + auto swtStressOut = swtSequence.write(swtStressPairs); |
| 154 | + getLogger() << "[SWT stress] cycle " << cycle << endm; |
| 155 | + //getLogger() << "[SWT stress] output: " << swtStressOut << endm; |
| 156 | + std::cout << "[SWT stress] output: " << swtStressOut << std::endl; // Infologger gets filled up here... |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + if (mOptions.sca) { |
| 161 | + auto scaOut = scaSequence.write({ std::make_pair("0x00010002", "0xff000000"), |
| 162 | + std::make_pair("0x00020004", "0xff000000"), |
| 163 | + std::make_pair("0x00030006", "0xff000000"), |
| 164 | + std::make_pair("0x0B950282", "0x50010000"), |
| 165 | + std::make_pair("0x0B9601DE", "0x50000000"), |
| 166 | + std::make_pair("0x0B970471", "0x50000000"), |
| 167 | + std::make_pair("0x0B980461", "0x50000000") }); |
| 168 | + getLogger() << "[SCA_SEQUENCE] output: " << scaOut << endm; |
| 169 | + } |
| 170 | + |
| 171 | + if (mOptions.ic) { |
| 172 | + auto icOut = icSequence.write({ |
| 173 | + std::make_pair("0x54,0xff", "write"), |
| 174 | + std::make_pair("0x54", "read"), |
| 175 | + std::make_pair("0x55,0xff", "write"), |
| 176 | + std::make_pair("0x55", "read"), |
| 177 | + std::make_pair("0x56,0xff", "write"), |
| 178 | + std::make_pair("0x56", "read"), |
| 179 | + }); |
| 180 | + getLogger() << "[IC_SEQUENCE] output: " << icOut << endm; |
| 181 | + |
| 182 | + icGbtI2cWriteRpc.write(0x3); |
| 183 | + } |
| 184 | + |
| 185 | + getLogger() << "See ya!" << endm; |
| 186 | + } |
| 187 | + |
| 188 | + private: |
| 189 | + struct OptionsStruct { |
| 190 | + std::string dimDnsNode = ""; |
| 191 | + int serial = -1; |
| 192 | + int link = -1; |
| 193 | + std::string alfId = ""; |
| 194 | + bool ic = false; |
| 195 | + bool sca = false; |
| 196 | + bool swt = false; |
| 197 | + bool swtStress = false; |
| 198 | + int swtStressCycles = 2; |
| 199 | + int swtStressWords = 1000; |
| 200 | + } mOptions; |
| 201 | +}; |
| 202 | + |
| 203 | +} // namespace Alf |
| 204 | +} // namespace AliceO2 |
| 205 | + |
| 206 | +int main(int argc, char** argv) |
| 207 | +{ |
| 208 | + return AliceO2::Alf::AlfClient().execute(argc, argv); |
| 209 | +} |
0 commit comments