From 67c5e8df8c5c8ffdec13074076b3dbfbcaa93df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Kub=C3=A1nek?= Date: Tue, 22 Aug 2023 11:06:04 +0200 Subject: [PATCH 1/6] Read LVDT values --- include/cRIO/ElectromechanicalPneumaticILC.h | 16 ++++++++++++++++ src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp | 9 +++++++++ tests/test_ElectromechanicalPneumaticILC.cpp | 2 ++ 3 files changed, 27 insertions(+) diff --git a/include/cRIO/ElectromechanicalPneumaticILC.h b/include/cRIO/ElectromechanicalPneumaticILC.h index 0f01d6df..e9563ab8 100644 --- a/include/cRIO/ElectromechanicalPneumaticILC.h +++ b/include/cRIO/ElectromechanicalPneumaticILC.h @@ -49,6 +49,13 @@ class ElectromechanicalPneumaticILC : public virtual ILC { */ void reportHardpointForceStatus(uint8_t address) { callFunction(address, 67, 1800); } + /** + * Unicast command to read hardpoint LVDT. ILC command 122 (0x7a). + * + * @param address ILC address + */ + void reportHardpointLVDT(uint8_t address) { callFunction(address, 122, 400); } + void setSAAForceOffset(uint8_t address, bool slewFlag, float primary) { callFunction(address, 75, 1800, static_cast(slewFlag ? 0xFF : 0x00), int24_t(primary * 1000)); @@ -99,6 +106,15 @@ class ElectromechanicalPneumaticILC : public virtual ILC { virtual void processHardpointForceStatus(uint8_t address, uint8_t status, int32_t encoderPostion, float loadCellForce) = 0; + /** + * Called when response from call to command 122 (0x7a) is read. + * + * @param address returned from this ILC + * @param breakawayLVDT breakway LVDT value + * @param displacementLVDT displacement LVDT value + */ + virtual void processHardpointLVDT(uint8_t address, float breakawayLVDT, float displacementLVDT) = 0; + virtual void processSAAForceStatus(uint8_t address, uint8_t status, float primaryLoadCellForce) = 0; virtual void processDAAForceStatus(uint8_t address, uint8_t status, float primaryLoadCellForce, float secondaryLoadCellForce) = 0; diff --git a/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp b/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp index 2a71c346..d9d2dad7 100644 --- a/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp +++ b/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp @@ -36,6 +36,13 @@ ElectromechanicalPneumaticILC::ElectromechanicalPneumaticILC(uint8_t bus) : ILC( processHardpointForceStatus(address, status, encoderPosition, loadCellForce); }; + auto hardpointLVDT = [this](uint8_t address) { + float breakwayLVDT = read(); + float displacementLVDT = read(); + checkCRC(); + processHardpointLVDT(address, breakwayLVDT, displacementLVDT); + }; + auto forceActuatorForceStatus = [this](uint8_t address) { uint8_t status = read(); float primary = read(); @@ -98,6 +105,8 @@ ElectromechanicalPneumaticILC::ElectromechanicalPneumaticILC(uint8_t bus) : ILC( addResponse(110, calibrationData, 238); addResponse(119, pressureData, 247); + + addResponse(122, hardpointLVDT, 250); } } // namespace cRIO diff --git a/tests/test_ElectromechanicalPneumaticILC.cpp b/tests/test_ElectromechanicalPneumaticILC.cpp index 705bd81b..4adedcaa 100644 --- a/tests/test_ElectromechanicalPneumaticILC.cpp +++ b/tests/test_ElectromechanicalPneumaticILC.cpp @@ -77,6 +77,8 @@ class TestElectromechanicalPneumaticILC : public ElectromechanicalPneumaticILC { void processHardpointForceStatus(uint8_t address, uint8_t status, int32_t encoderPosition, float loadCellForce) override {} + void processHardpointLVDT(uint8_t address, float breakawayLVDT, float displacementLVDT) override {} + virtual void processSAAForceStatus(uint8_t address, uint8_t status, float primaryLoadCellForce) override { primaryForce = primaryLoadCellForce; secondaryForce = NAN; From f1f2e45a8947aea658809c0c4f6d05cdd2be2754 Mon Sep 17 00:00:00 2001 From: Petr Kubanek Date: Fri, 8 Sep 2023 13:02:06 +0200 Subject: [PATCH 2/6] ts_pre_commit_conf file, version history --- .github/workflows/changelog.yaml | 19 +++++++++++++++++++ .github/workflows/clang-format.yaml | 16 ---------------- .gitignore | 6 ++++++ .ts_pre_commit_config.yaml | 9 +++++++++ doc/version-history.rst | 14 ++++++++++++++ include/cRIO/SimulatedILC.h | 1 - 6 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/changelog.yaml delete mode 100644 .github/workflows/clang-format.yaml create mode 100644 .ts_pre_commit_config.yaml create mode 100644 doc/version-history.rst diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml new file mode 100644 index 00000000..63ae426a --- /dev/null +++ b/.github/workflows/changelog.yaml @@ -0,0 +1,19 @@ +name: ChangelogUpdated +on: + pull_request: + types: [assigned, opened, synchronize, reopened, labeled, unlabeled] + branches: + - develop +jobs: + build: + name: Check Actions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Changelog check + uses: Zomzog/changelog-checker@v1.2.0 + with: + fileName: doc/version-history.rst + checkNotification: Simple + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/clang-format.yaml b/.github/workflows/clang-format.yaml deleted file mode 100644 index eb231791..00000000 --- a/.github/workflows/clang-format.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: test-clang-format - -on: [push] - -jobs: - clang-format: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: DoozyX/clang-format-lint-action@v0.11 - with: - source: './src/LSST ./tests' - extensions: 'h,cpp' - clangFormatVersion: 9 - style: file diff --git a/.gitignore b/.gitignore index b2cc61dc..dd4cbebc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ tests/test_* !tests/test_*.cpp !tests/test_*.c +.pre-commit-config.yaml +.clang-format +.flake8 +.isort.cfg +.mypy.ini +.ruff.toml diff --git a/.ts_pre_commit_config.yaml b/.ts_pre_commit_config.yaml new file mode 100644 index 00000000..4944a0c6 --- /dev/null +++ b/.ts_pre_commit_config.yaml @@ -0,0 +1,9 @@ +black: true +check-xml: true +check-yaml: true +clang-format: true +flake8: true +format-xmllint: true +isort: true +mypy: true +ruff: true diff --git a/doc/version-history.rst b/doc/version-history.rst new file mode 100644 index 00000000..be5fae0f --- /dev/null +++ b/doc/version-history.rst @@ -0,0 +1,14 @@ +############### +Version History +############### + +v1.8.0 +====== + +* LVDT ElectroMechanical readout + +v1.7.0 +====== + +* offsets,.. ILC commands +* improved re-heater gain management diff --git a/include/cRIO/SimulatedILC.h b/include/cRIO/SimulatedILC.h index afda6988..e31fab4e 100644 --- a/include/cRIO/SimulatedILC.h +++ b/include/cRIO/SimulatedILC.h @@ -68,4 +68,3 @@ class SimulatedILC : public ModbusBuffer { } // namespace LSST #endif // CRIO_SIMULATIONBUFFER_H_ - From a2e00cf599f08bb43f3b1e06cf68f56906518909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Kub=C3=A1nek?= Date: Tue, 12 Sep 2023 10:02:55 +0200 Subject: [PATCH 3/6] Modified MPU - allow paraller readout --- Makefile.inc | 6 ++-- doc/version-history.rst | 5 +++ include/cRIO/MPU.h | 28 +++++++--------- include/cRIO/MPUTelemetry.h | 58 ++++++++++++++-------------------- src/LSST/cRIO/MPU.cpp | 56 +++++++++++--------------------- src/LSST/cRIO/MPUTelemetry.cpp | 46 +++++++-------------------- 6 files changed, 72 insertions(+), 127 deletions(-) diff --git a/Makefile.inc b/Makefile.inc index 4255ceca..8db249b8 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -24,13 +24,15 @@ else endif PKG_LIBS := $(shell pkg-config yaml-cpp --libs $(silence)) \ - $(shell pkg-config spdlog --libs $(silence)) + $(shell pkg-config spdlog --libs $(silence)) \ + $(shell pkg-config fmt --libs $(silence)) LIBS += $(PKG_LIBS) -ldl -lpthread BOOST_CPPFLAGS := -I/usr/include/boost169 PKG_CPP_FLAGS := $(shell pkg-config yaml-cpp --cflags $(silence)) \ - $(shell pkg-config spdlog --cflags $(silence)) + $(shell pkg-config spdlog --cflags $(silence)) \ + $(shell pkg-config fmt --cflags $(silence)) CPP_FLAGS += $(PKG_CPP_FLAGS) diff --git a/doc/version-history.rst b/doc/version-history.rst index be5fae0f..cfd7bcd7 100644 --- a/doc/version-history.rst +++ b/doc/version-history.rst @@ -2,6 +2,11 @@ Version History ############### +v1.9.0 +====== + +* MPU changed to SerialMultiplex + v1.8.0 ====== diff --git a/include/cRIO/MPU.h b/include/cRIO/MPU.h index acfe62b0..8e8a30d0 100644 --- a/include/cRIO/MPU.h +++ b/include/cRIO/MPU.h @@ -41,19 +41,11 @@ namespace cRIO { * https://github.com/lsst-ts/Modbus_Processing_Unit for command details. */ namespace MPUCommands { -const static uint8_t STOP = 0; -const static uint8_t WRITE_BYTE = 1; -const static uint8_t WAIT_MS = 2; -const static uint8_t READ = 3; -const static uint8_t LOOP = 4; -const static uint8_t CHECK_CRC = 5; -const static uint8_t OUTPUT = 6; -const static uint8_t WRITE = 20; -const static uint8_t TELEMETRY_BYTE = 30; -const static uint8_t TELEMETRY_16 = 31; -const static uint8_t TELEMETRY_32 = 32; -const static uint8_t TELEMETRY_64 = 33; -const static uint8_t EXIT = 255; +const static uint8_t WRITE = 1; +const static uint8_t READ_US = 2; +const static uint8_t READ_MS = 3; +const static uint8_t TELEMETRY = 254; +const static uint8_t CLEAR = 255; } // namespace MPUCommands /** @@ -89,7 +81,7 @@ class MPU : public ModbusBuffer { void readEndOfFrame() override {} - void readInputStatus(uint16_t address, uint16_t count = 1, uint8_t timeout = 100); + void readInputStatus(uint16_t address, uint16_t count = 1, uint16_t timeout = 100); /** * Reads holding register(s). @@ -98,7 +90,7 @@ class MPU : public ModbusBuffer { * @param count number of registers to read * @param timeout timeout for register readout (in ms) */ - void readHoldingRegisters(uint16_t address, uint16_t count, uint8_t timeout = 100); + void readHoldingRegisters(uint16_t address, uint16_t count, uint16_t timeout = 100); /** * Write single register. @@ -107,7 +99,7 @@ class MPU : public ModbusBuffer { * @param value register value * @param timeout timeout (in ms) */ - void presetHoldingRegister(uint16_t address, uint16_t value, uint8_t timeout = 100); + void presetHoldingRegister(uint16_t address, uint16_t value, uint16_t timeout = 100); /** * Sets modbus holding registers. @@ -117,7 +109,7 @@ class MPU : public ModbusBuffer { * @param count number of registers to write * @param timeout timeout (in ms) */ - void presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t count, uint8_t timeout = 100); + void presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t count, uint16_t timeout = 100); /** * Returns commands buffer. @@ -137,6 +129,8 @@ class MPU : public ModbusBuffer { } private: + void _pushTimeout(uint16_t timeout); + std::vector _commands; uint8_t _bus; uint8_t _mpu_address; diff --git a/include/cRIO/MPUTelemetry.h b/include/cRIO/MPUTelemetry.h index bc4e111c..41cf3236 100644 --- a/include/cRIO/MPUTelemetry.h +++ b/include/cRIO/MPUTelemetry.h @@ -38,26 +38,12 @@ class MPUTelemetry { * * @param data[45] data as received from FPGA */ - MPUTelemetry(uint8_t data[45]); - uint16_t instructionPointer; /// Current MPU instruction pointer - uint64_t outputCounter; /// Current MPU output counter - uint64_t inputCounter; /// Current MPU input counter - uint64_t outputTimeouts; /// Current MPU output timeouts counter - uint64_t inputTimeouts; /// Current MPU input timeouts counter - uint16_t instructionPointerOnError; /// Instruction counter on MPU error - uint16_t writeTimeout; /// Write timeout (in ms) - uint16_t readTimeout; /// Read timeout (in ms) - uint8_t errorStatus; /// True if any error was triggered - uint16_t errorCode; /// MPU error code - uint16_t modbusCRC; /// CRC received from FPGA - uint16_t calculatedCRC; /// CRC calculated for message - - /** - * Check that received CRC matches calculated CRC. - * - * @throws std::runtime_exception on mismatch - */ - void checkCRC(); + MPUTelemetry(uint8_t* data); + uint32_t writeBytes; /// Number of bytes written + uint32_t readHWBytes; /// Read HW bytes + uint32_t readBytes; /// Number of bytes read + uint16_t writeTimedout; /// Timedout counter of writes to output FIFO + uint16_t readTimedout; /// read timedout counter friend std::ostream& operator<<(std::ostream& os, const MPUTelemetry& tel); @@ -71,21 +57,23 @@ class MPUTelemetry { */ template bool sendUpdates(message* msg) { - bool send = false; - if (msg->writeTimeout != writeTimeout || msg->readTimeout != readTimeout || - msg->instructionPointerOnError != instructionPointerOnError || msg->errorCode != errorCode) { - send = true; - } - msg->instructionPointer = instructionPointer; - msg->outputCounter = outputCounter; - msg->inputCounter = inputCounter; - msg->outputTimeouts = outputTimeouts; - msg->inputTimeouts = inputTimeouts; - msg->instructionPointerOnError = instructionPointerOnError; - msg->writeTimeout = writeTimeout; - msg->readTimeout = readTimeout; - msg->errorCode = errorCode; - return send; + return false; + + /** + if (msg->readBytes != readBytes || msg->writeTimedout != writeTimedout || + msg->instructionPointerOnError != instructionPointerOnError || msg->errorCode != errorCode) { + send = true; + } + msg->instructionPointer = instructionPointer; + msg->outputCounter = outputCounter; + msg->inputCounter = inputCounter; + msg->outputTimeouts = outputTimeouts; + msg->inputTimeouts = inputTimeouts; + msg->instructionPointerOnError = instructionPointerOnError; + msg->writeTimeout = writeTimeout; + msg->readTimeout = readTimeout; + msg->errorCode = errorCode; + return send; */ } }; diff --git a/src/LSST/cRIO/MPU.cpp b/src/LSST/cRIO/MPU.cpp index 96bb7813..0495641e 100644 --- a/src/LSST/cRIO/MPU.cpp +++ b/src/LSST/cRIO/MPU.cpp @@ -141,7 +141,7 @@ void MPU::clearCommanded() { _presetRegisters.clear(); } -void MPU::readInputStatus(uint16_t address, uint16_t count, uint8_t timeout) { +void MPU::readInputStatus(uint16_t address, uint16_t count, uint16_t timeout) { callFunction(_mpu_address, 2, 0, address, count); // write request @@ -151,26 +151,19 @@ void MPU::readInputStatus(uint16_t address, uint16_t count, uint8_t timeout) { _commands.push_back(b); } - _commands.push_back(MPUCommands::WAIT_MS); - _commands.push_back(timeout); - // read response - _commands.push_back(MPUCommands::READ); + _commands.push_back(MPUCommands::READ_MS); _contains_read = true; // extras: device address, function, length (all 1 byte), CRC (2 bytes) = 5 total _commands.push_back(5 + ceil(count / 8.0)); - _commands.push_back(MPUCommands::CHECK_CRC); + _pushTimeout(timeout); _readInputStatus.push_back(std::pair(address, count)); } -void MPU::readHoldingRegisters(uint16_t address, uint16_t count, uint8_t timeout) { - // remove EXIT if commands were already pushed to buffer - if (!_commands.empty()) { - _commands.pop_back(); - } - +void MPU::readHoldingRegisters(uint16_t address, uint16_t count, uint16_t timeout) { clear(true); + callFunction(_mpu_address, 3, 0, address, count); // write request @@ -180,25 +173,19 @@ void MPU::readHoldingRegisters(uint16_t address, uint16_t count, uint8_t timeout _commands.push_back(b); } - _commands.push_back(MPUCommands::WAIT_MS); - _commands.push_back(timeout); - // read response - _commands.push_back(MPUCommands::READ); + _commands.push_back(MPUCommands::READ_MS); _contains_read = true; // extras: device address, function, length (all 1 byte), CRC (2 bytes) = 5 total _commands.push_back(5 + count * 2); - - _commands.push_back(MPUCommands::OUTPUT); - - _commands.push_back(MPUCommands::EXIT); + _pushTimeout(timeout); for (uint16_t add = address; add < address + count; add++) { _readRegisters.push_back(add); } } -void MPU::presetHoldingRegister(uint16_t address, uint16_t value, uint8_t timeout) { +void MPU::presetHoldingRegister(uint16_t address, uint16_t value, uint16_t timeout) { write(_mpu_address); write(6); write(address); @@ -217,24 +204,17 @@ void MPU::presetHoldingRegister(uint16_t address, uint16_t value, uint8_t timeou _commands.push_back(b); } - _commands.push_back(MPUCommands::WAIT_MS); - _commands.push_back(timeout); - // read response - _commands.push_back(MPUCommands::READ); + _commands.push_back(MPUCommands::READ_MS); _contains_read = true; // extras: device address, function (all 1 byte), address, number of registers written, CRC (2 bytes) _commands.push_back(8); - - _commands.push_back(MPUCommands::OUTPUT); - - _commands.push_back(MPUCommands::CHECK_CRC); - _commands.push_back(MPUCommands::EXIT); + _pushTimeout(timeout); _presetRegister.push_back(std::pair(address, value)); } -void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t count, uint8_t timeout) { +void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t count, uint16_t timeout) { write(_mpu_address); write(16); write(address); @@ -246,8 +226,6 @@ void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t cou } writeCRC(); - writeEndOfFrame(); - writeWaitForRx(0); pushCommanded(_mpu_address, 16); @@ -258,14 +236,16 @@ void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t cou _commands.push_back(b); } - _commands.push_back(MPUCommands::WAIT_MS); - _commands.push_back(timeout); - // read response - _commands.push_back(MPUCommands::READ); + _commands.push_back(MPUCommands::READ_MS); // extras: device address, function (all 1 byte), address, number of registers written, CRC (2 bytes) _commands.push_back(8); - _commands.push_back(MPUCommands::CHECK_CRC); + _pushTimeout(timeout); _presetRegisters.push_back(std::pair(address, count)); } + +void MPU::_pushTimeout(uint16_t timeout) { + _commands.push_back(timeout >> 8 & 0xff); + _commands.push_back(timeout & 0xff); +} diff --git a/src/LSST/cRIO/MPUTelemetry.cpp b/src/LSST/cRIO/MPUTelemetry.cpp index a8d45966..bfa4ba08 100644 --- a/src/LSST/cRIO/MPUTelemetry.cpp +++ b/src/LSST/cRIO/MPUTelemetry.cpp @@ -31,44 +31,20 @@ namespace LSST { namespace cRIO { -MPUTelemetry::MPUTelemetry(uint8_t data[45]) { - instructionPointer = be16toh(*(reinterpret_cast(data + 0))); - outputCounter = be64toh(*(reinterpret_cast(data + 2))); - inputCounter = be64toh(*(reinterpret_cast(data + 10))); - outputTimeouts = be64toh(*(reinterpret_cast(data + 18))); - inputTimeouts = be64toh(*(reinterpret_cast(data + 26))); - instructionPointerOnError = be16toh(*(reinterpret_cast(data + 34))); - writeTimeout = be16toh(*(reinterpret_cast(data + 36))); - readTimeout = be16toh(*(reinterpret_cast(data + 38))); - errorStatus = data[40]; - errorCode = be16toh(*(reinterpret_cast(data + 41))); - modbusCRC = be16toh(*(reinterpret_cast(data + 43))); - - calculatedCRC = ModbusBuffer::CRC(data, 43).get(); -} - -void MPUTelemetry::checkCRC() { - if (calculatedCRC != modbusCRC) { - throw std::runtime_error( - fmt::format("Mismatched telemetry Modbus CRC - expected 0x{:X}, calculated 0x{:X}", modbusCRC, - calculatedCRC)); - } - - ModbusBuffer::CRC crc{}; +MPUTelemetry::MPUTelemetry(uint8_t* data) { + writeBytes = be32toh(*(reinterpret_cast(data + 0))); + readHWBytes = be32toh(*(reinterpret_cast(data + 4))); + readBytes = be32toh(*(reinterpret_cast(data + 8))); + writeTimedout = be16toh(*(reinterpret_cast(data + 12))); + readTimedout = be16toh(*(reinterpret_cast(data + 14))); } std::ostream &operator<<(std::ostream &os, const MPUTelemetry &tel) { - os << std::setw(20) << "IP: " << tel.instructionPointer << std::endl - << std::setw(20) << "Output (Writes): " << tel.outputCounter << std::endl - << std::setw(20) << "Input (Reads): " << tel.inputCounter << std::endl - << std::setw(20) << "Out Timeouts: " << tel.outputTimeouts << std::endl - << std::setw(20) << "In Timeouts: " << tel.inputTimeouts << std::endl - << std::setw(20) << "IP on error : " << tel.instructionPointerOnError << std::endl - << std::setw(20) << "Write timeout: " << tel.writeTimeout << std::endl - << std::setw(20) << "Read timeout: " << tel.readTimeout << std::endl - << std::setw(20) << "Error status: " << +tel.errorStatus << std::endl - << std::setw(20) << "Error code: " << tel.errorCode << std::endl; - + os << std::setw(20) << "Write bytes: " << tel.writeBytes << std::endl + << std::setw(20) << "Read HW bytes: " << tel.readHWBytes << std::endl + << std::setw(20) << "Read bytes: " << tel.readBytes << std::endl + << std::setw(20) << "Write Timedout: " << tel.writeTimedout << std::endl + << std::setw(20) << "Read timedout: " << tel.readTimedout << std::endl; return os; } From 7ebab030db4039bc27c25d3840a34092c49bd481 Mon Sep 17 00:00:00 2001 From: Petr Kubanek Date: Thu, 14 Sep 2023 23:37:42 +0200 Subject: [PATCH 4/6] fix tests --- tests/test_MPU.cpp | 146 ++++++++++++++++-------------------- tests/test_MPUTelemetry.cpp | 56 +++----------- 2 files changed, 75 insertions(+), 127 deletions(-) diff --git a/tests/test_MPU.cpp b/tests/test_MPU.cpp index 9f0a7074..dd8e2fd2 100644 --- a/tests/test_MPU.cpp +++ b/tests/test_MPU.cpp @@ -32,7 +32,7 @@ TEST_CASE("Test MPU read input status", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 15); + REQUIRE(commands.size() == 14); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -44,11 +44,10 @@ TEST_CASE("Test MPU read input status", "[MPU]") { REQUIRE(commands[7] == 0x16); REQUIRE(commands[8] == 0xBA); REQUIRE(commands[9] == 0xA9); - REQUIRE(commands[10] == MPUCommands::WAIT_MS); - REQUIRE(commands[11] == 108); - REQUIRE(commands[12] == MPUCommands::READ); - REQUIRE(commands[13] == 8); - REQUIRE(commands[14] == MPUCommands::CHECK_CRC); + REQUIRE(commands[10] == MPUCommands::READ_MS); + REQUIRE(commands[11] == 8); + REQUIRE(commands[12] == 0); + REQUIRE(commands[13] == 108); std::vector res = {0x11, 0x02, 0x03, 0xAC, 0xDB, 0x35, 0x20, 0x18}; @@ -97,7 +96,7 @@ TEST_CASE("Test MPU read holding registers", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 16); + REQUIRE(commands.size() == 14); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -109,12 +108,10 @@ TEST_CASE("Test MPU read holding registers", "[MPU]") { REQUIRE(commands[7] == 10); REQUIRE(commands[8] == 0x34); REQUIRE(commands[9] == 0xD0); - REQUIRE(commands[10] == MPUCommands::WAIT_MS); - REQUIRE(commands[11] == 101); - REQUIRE(commands[12] == MPUCommands::READ); - REQUIRE(commands[13] == 25); - REQUIRE(commands[14] == MPUCommands::OUTPUT); - REQUIRE(commands[15] == MPUCommands::EXIT); + REQUIRE(commands[10] == MPUCommands::READ_MS); + REQUIRE(commands[11] == 25); + REQUIRE(commands[12] == 0); + REQUIRE(commands[13] == 101); std::vector res = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -146,7 +143,7 @@ TEST_CASE("Test MPU reading multiple registers - failed response", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 31); + REQUIRE(commands.size() == 28); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -158,29 +155,25 @@ TEST_CASE("Test MPU reading multiple registers - failed response", "[MPU]") { REQUIRE(commands[7] == 10); REQUIRE(commands[8] == 0x34); REQUIRE(commands[9] == 0xD0); - REQUIRE(commands[10] == MPUCommands::WAIT_MS); - REQUIRE(commands[11] == 101); - REQUIRE(commands[12] == MPUCommands::READ); - REQUIRE(commands[13] == 25); - REQUIRE(commands[14] == MPUCommands::OUTPUT); - - REQUIRE(commands[15] == MPUCommands::WRITE); - REQUIRE(commands[16] == 8); - REQUIRE(commands[17] == 12); - REQUIRE(commands[18] == 3); - REQUIRE(commands[19] == 0); - REQUIRE(commands[20] == 103); - REQUIRE(commands[21] == 0); - REQUIRE(commands[22] == 10); - REQUIRE(commands[23] == 0x75); - REQUIRE(commands[24] == 0x0F); - REQUIRE(commands[25] == MPUCommands::WAIT_MS); - REQUIRE(commands[26] == 101); - REQUIRE(commands[27] == MPUCommands::READ); - REQUIRE(commands[28] == 25); - REQUIRE(commands[29] == MPUCommands::OUTPUT); - - REQUIRE(commands[30] == MPUCommands::EXIT); + REQUIRE(commands[10] == MPUCommands::READ_MS); + REQUIRE(commands[11] == 25); + REQUIRE(commands[12] == 0); + REQUIRE(commands[13] == 101); + + REQUIRE(commands[14] == MPUCommands::WRITE); + REQUIRE(commands[15] == 8); + REQUIRE(commands[16] == 12); + REQUIRE(commands[17] == 3); + REQUIRE(commands[18] == 0); + REQUIRE(commands[19] == 103); + REQUIRE(commands[20] == 0); + REQUIRE(commands[21] == 10); + REQUIRE(commands[22] == 0x75); + REQUIRE(commands[23] == 0x0F); + REQUIRE(commands[24] == MPUCommands::READ_MS); + REQUIRE(commands[25] == 25); + REQUIRE(commands[26] == 0); + REQUIRE(commands[27] == 101); std::vector res1 = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -217,7 +210,7 @@ TEST_CASE("Test MPU reading multiple registers - successful response", "[MPU]") auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 31); + REQUIRE(commands.size() == 28); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -229,29 +222,25 @@ TEST_CASE("Test MPU reading multiple registers - successful response", "[MPU]") REQUIRE(commands[7] == 10); REQUIRE(commands[8] == 0x34); REQUIRE(commands[9] == 0xD0); - REQUIRE(commands[10] == MPUCommands::WAIT_MS); - REQUIRE(commands[11] == 101); - REQUIRE(commands[12] == MPUCommands::READ); - REQUIRE(commands[13] == 25); - REQUIRE(commands[14] == MPUCommands::OUTPUT); - - REQUIRE(commands[15] == MPUCommands::WRITE); - REQUIRE(commands[16] == 8); - REQUIRE(commands[17] == 12); - REQUIRE(commands[18] == 3); - REQUIRE(commands[19] == 0); - REQUIRE(commands[20] == 103); - REQUIRE(commands[21] == 0); - REQUIRE(commands[22] == 10); - REQUIRE(commands[23] == 0x75); - REQUIRE(commands[24] == 0x0F); - REQUIRE(commands[25] == MPUCommands::WAIT_MS); - REQUIRE(commands[26] == 101); - REQUIRE(commands[27] == MPUCommands::READ); - REQUIRE(commands[28] == 25); - REQUIRE(commands[29] == MPUCommands::OUTPUT); - - REQUIRE(commands[30] == MPUCommands::EXIT); + REQUIRE(commands[10] == MPUCommands::READ_MS); + REQUIRE(commands[11] == 25); + REQUIRE(commands[12] == 0); + REQUIRE(commands[13] == 101); + + REQUIRE(commands[14] == MPUCommands::WRITE); + REQUIRE(commands[15] == 8); + REQUIRE(commands[16] == 12); + REQUIRE(commands[17] == 3); + REQUIRE(commands[18] == 0); + REQUIRE(commands[19] == 103); + REQUIRE(commands[20] == 0); + REQUIRE(commands[21] == 10); + REQUIRE(commands[22] == 0x75); + REQUIRE(commands[23] == 0x0F); + REQUIRE(commands[24] == MPUCommands::READ_MS); + REQUIRE(commands[25] == 25); + REQUIRE(commands[26] == 0); + REQUIRE(commands[27] == 101); std::vector res1 = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -324,7 +313,7 @@ TEST_CASE("Test MPU preset holding register", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 17); + REQUIRE(commands.size() == 14); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -336,13 +325,10 @@ TEST_CASE("Test MPU preset holding register", "[MPU]") { REQUIRE(commands[7] == 0x03); REQUIRE(commands[8] == 0x9A); REQUIRE(commands[9] == 0x9B); - REQUIRE(commands[10] == MPUCommands::WAIT_MS); - REQUIRE(commands[11] == 102); - REQUIRE(commands[12] == MPUCommands::READ); - REQUIRE(commands[13] == 8); - REQUIRE(commands[14] == MPUCommands::OUTPUT); - REQUIRE(commands[15] == MPUCommands::CHECK_CRC); - REQUIRE(commands[16] == MPUCommands::EXIT); + REQUIRE(commands[10] == MPUCommands::READ_MS); + REQUIRE(commands[11] == 8); + REQUIRE(commands[12] == 0); + REQUIRE(commands[13] == 102); std::vector res = {0x11, 0x06, 0x00, 0x01, 0x00, 0x03, 0x9A, 0x9B}; @@ -357,7 +343,7 @@ TEST_CASE("Test MPU preset holding registers", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 20); + REQUIRE(commands.size() == 19); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 9 + 2 * regs.size()); @@ -374,11 +360,10 @@ TEST_CASE("Test MPU preset holding registers", "[MPU]") { REQUIRE(commands[12] == 0x04); REQUIRE(commands[13] == 0xED); REQUIRE(commands[14] == 0x3A); - REQUIRE(commands[15] == MPUCommands::WAIT_MS); - REQUIRE(commands[16] == 102); - REQUIRE(commands[17] == MPUCommands::READ); - REQUIRE(commands[18] == 8); - REQUIRE(commands[19] == MPUCommands::CHECK_CRC); + REQUIRE(commands[15] == MPUCommands::READ_MS); + REQUIRE(commands[16] == 8); + REQUIRE(commands[17] == 0); + REQUIRE(commands[18] == 102); std::vector res = {17, 16, 0x17, 0x18, 0, 2, 0xC6, 0xEB}; @@ -393,7 +378,7 @@ TEST_CASE("Test MPU preset holding registers by simplymodbus.ca", "[MPU]") { auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 20); + REQUIRE(commands.size() == 19); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 9 + 2 * regs.size()); @@ -410,11 +395,10 @@ TEST_CASE("Test MPU preset holding registers by simplymodbus.ca", "[MPU]") { REQUIRE(commands[12] == 0x02); REQUIRE(commands[13] == 0xC6); REQUIRE(commands[14] == 0xF0); - REQUIRE(commands[15] == MPUCommands::WAIT_MS); - REQUIRE(commands[16] == 102); - REQUIRE(commands[17] == MPUCommands::READ); - REQUIRE(commands[18] == 8); - REQUIRE(commands[19] == MPUCommands::CHECK_CRC); + REQUIRE(commands[15] == MPUCommands::READ_MS); + REQUIRE(commands[16] == 8); + REQUIRE(commands[17] == 0); + REQUIRE(commands[18] == 102); std::vector res = {0x11, 0x10, 0x00, 0x01, 0x00, 0x02, 0x12, 0x98}; diff --git a/tests/test_MPUTelemetry.cpp b/tests/test_MPUTelemetry.cpp index 081fba47..5d29c2f6 100644 --- a/tests/test_MPUTelemetry.cpp +++ b/tests/test_MPUTelemetry.cpp @@ -28,55 +28,19 @@ using namespace LSST::cRIO; -uint8_t data[45] = { - 0x00, 0x01, // current IP - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, // outputCounter - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // inputCounter - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // outputTimeouts - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, // inputTimeouts - 0x00, 0x05, // instructionPointerOnError - 0x00, 0x06, // writeTimeout - 0x00, 0x07, // readTimeout - 0x00, // errorStatus - 0x00, 0x08, // errorCode - 0xB6, 0x35, // modbusCRC - +uint8_t data[16] = { + 0x01, 0x02, 0x03, 0x04, // write bytes + 0x05, 0x06, 0x07, 0x08, // read HW bytes }; TEST_CASE("Test MPU telemetry class", "[MPUTelemetry]") { MPUTelemetry mpuTel(data); - REQUIRE(mpuTel.instructionPointer == 0x01); - REQUIRE(mpuTel.outputCounter == 0x01020304050607ff); - REQUIRE(mpuTel.inputCounter == 0x02); - REQUIRE(mpuTel.outputTimeouts == 0x03); - REQUIRE(mpuTel.inputTimeouts == 0x04); - REQUIRE(mpuTel.instructionPointerOnError == 0x05); - REQUIRE(mpuTel.writeTimeout == 0x06); - REQUIRE(mpuTel.readTimeout == 0x07); - REQUIRE(mpuTel.errorStatus == 0x00); - REQUIRE(mpuTel.errorCode == 0x08); - REQUIRE(mpuTel.modbusCRC == mpuTel.calculatedCRC); - - REQUIRE_NOTHROW(mpuTel.checkCRC()); - - data[43] = 0xB7; - - MPUTelemetry mpuTelFailed(data); - REQUIRE_THROWS(mpuTelFailed.checkCRC()); + REQUIRE(mpuTel.writeBytes == 0x01020304); } struct testMsg_t { - uint16_t instructionPointer; /// Current MPU instruction pointer - uint64_t outputCounter; /// Current MPU output counter - uint64_t inputCounter; /// Current MPU input counter - uint64_t outputTimeouts; /// Current MPU output timeouts counter - uint64_t inputTimeouts; /// Current MPU input timeouts counter - uint16_t instructionPointerOnError; /// Instruction counter on MPU error - uint16_t writeTimeout; /// - uint16_t readTimeout; - uint8_t errorStatus; - uint16_t errorCode; + uint32_t writeBytes; // Written bytes }; TEST_CASE("Test MPU sending", "[MPUTelemetry]") { @@ -85,11 +49,11 @@ TEST_CASE("Test MPU sending", "[MPUTelemetry]") { struct testMsg_t testMsg; memset(&testMsg, '0', sizeof(testMsg)); - REQUIRE(mpuTel.sendUpdates(&testMsg) == true); - REQUIRE(mpuTel.sendUpdates(&testMsg) == false); + // TODO add test once telemetry will be again reporetd through SAL - testMsg.errorCode = 1; + // REQUIRE(mpuTel.sendUpdates(&testMsg) == true); + // REQUIRE(mpuTel.sendUpdates(&testMsg) == false); - REQUIRE(mpuTel.sendUpdates(&testMsg) == true); - REQUIRE(mpuTel.sendUpdates(&testMsg) == false); + // REQUIRE(mpuTel.sendUpdates(&testMsg) == true); + // REQUIRE(mpuTel.sendUpdates(&testMsg) == false); } From dc09e6fb95dd589e0f5958872d985d62a065439f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Kub=C3=A1nek?= Date: Fri, 15 Sep 2023 23:35:00 +0000 Subject: [PATCH 5/6] Pass timedout argument --- include/cRIO/FPGA.h | 3 ++- include/cRIO/MPU.h | 22 ++++++++++++++++++++++ include/cRIO/MPUTelemetry.h | 2 -- src/LSST/cRIO/FPGA.cpp | 4 +++- src/LSST/cRIO/MPUTelemetry.cpp | 8 ++------ tests/TestFPGA.h | 4 +++- tests/test_CSC.cpp | 4 +++- tests/test_FirmwareLoad.cpp | 4 +++- 8 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/cRIO/FPGA.h b/include/cRIO/FPGA.h index 1c21a10a..b16c237c 100644 --- a/include/cRIO/FPGA.h +++ b/include/cRIO/FPGA.h @@ -186,11 +186,12 @@ class FPGA : public SimpleFPGA { * * @param irqs IRQ mask. Each interrupt corresponds to a bit * @param timeout timeout in milliseconds + * @param timedout true if call timedouted, false if finished in time * @param triggered * * @note the method shall allocate context (for IRQ handling) as needed from the current thread id */ - virtual void waitOnIrqs(uint32_t irqs, uint32_t timeout, uint32_t* triggered = NULL) = 0; + virtual void waitOnIrqs(uint32_t irqs, uint32_t timeout, bool& timedout, uint32_t* triggered = NULL) = 0; /** * Acknowledges IRQs. Clear IRQs on FPGA. diff --git a/include/cRIO/MPU.h b/include/cRIO/MPU.h index 8e8a30d0..4f304d11 100644 --- a/include/cRIO/MPU.h +++ b/include/cRIO/MPU.h @@ -118,7 +118,29 @@ class MPU : public ModbusBuffer { */ std::vector getCommandVector() { return _commands; } + /*** + * Returns cached input state. Input state shall be cached - queried with + * readInputStatus method. + * + * @param address input state address + * + * @return cached input state + * + * @throws std::out_of_range if the address isn't cached + */ + bool getInputStatus(uint16_t address) { return _inputStatus.at(address); } + + /*** + * Returns register value. This access only cached values - register shall be first read + * using readHoldingRegisters method. + * + * @param address register address + * + * @return cached regiter value + * + * @throws std::runtime_error when register value isn't cached + */ uint16_t getRegister(uint16_t address) { std::lock_guard lg(_registerMutex); try { diff --git a/include/cRIO/MPUTelemetry.h b/include/cRIO/MPUTelemetry.h index 41cf3236..d23412df 100644 --- a/include/cRIO/MPUTelemetry.h +++ b/include/cRIO/MPUTelemetry.h @@ -40,9 +40,7 @@ class MPUTelemetry { */ MPUTelemetry(uint8_t* data); uint32_t writeBytes; /// Number of bytes written - uint32_t readHWBytes; /// Read HW bytes uint32_t readBytes; /// Number of bytes read - uint16_t writeTimedout; /// Timedout counter of writes to output FIFO uint16_t readTimedout; /// read timedout counter friend std::ostream& operator<<(std::ostream& os, const MPUTelemetry& tel); diff --git a/src/LSST/cRIO/FPGA.cpp b/src/LSST/cRIO/FPGA.cpp index 88ea1fcc..803cfc6e 100644 --- a/src/LSST/cRIO/FPGA.cpp +++ b/src/LSST/cRIO/FPGA.cpp @@ -69,7 +69,9 @@ void FPGA::ilcCommands(ILC &ilc) { uint32_t irq = getIrq(bus); - waitOnIrqs(irq, 5000); + bool timedout = false; + + waitOnIrqs(irq, 5000, timedout); ackIrqs(irq); // get back response diff --git a/src/LSST/cRIO/MPUTelemetry.cpp b/src/LSST/cRIO/MPUTelemetry.cpp index bfa4ba08..865da6e6 100644 --- a/src/LSST/cRIO/MPUTelemetry.cpp +++ b/src/LSST/cRIO/MPUTelemetry.cpp @@ -33,17 +33,13 @@ namespace cRIO { MPUTelemetry::MPUTelemetry(uint8_t* data) { writeBytes = be32toh(*(reinterpret_cast(data + 0))); - readHWBytes = be32toh(*(reinterpret_cast(data + 4))); - readBytes = be32toh(*(reinterpret_cast(data + 8))); - writeTimedout = be16toh(*(reinterpret_cast(data + 12))); - readTimedout = be16toh(*(reinterpret_cast(data + 14))); + readBytes = be32toh(*(reinterpret_cast(data + 4))); + readTimedout = be16toh(*(reinterpret_cast(data + 8))); } std::ostream &operator<<(std::ostream &os, const MPUTelemetry &tel) { os << std::setw(20) << "Write bytes: " << tel.writeBytes << std::endl - << std::setw(20) << "Read HW bytes: " << tel.readHWBytes << std::endl << std::setw(20) << "Read bytes: " << tel.readBytes << std::endl - << std::setw(20) << "Write Timedout: " << tel.writeTimedout << std::endl << std::setw(20) << "Read timedout: " << tel.readTimedout << std::endl; return os; } diff --git a/tests/TestFPGA.h b/tests/TestFPGA.h index 3af599e8..aef19ab1 100644 --- a/tests/TestFPGA.h +++ b/tests/TestFPGA.h @@ -53,7 +53,9 @@ class TestFPGA : public LSST::cRIO::FPGA, public LSST::cRIO::PrintILC { void writeCommandFIFO(uint16_t* data, size_t length, uint32_t timeout) override; void writeRequestFIFO(uint16_t* data, size_t length, uint32_t timeout) override; void readU16ResponseFIFO(uint16_t* data, size_t length, uint32_t timeout) override; - void waitOnIrqs(uint32_t irqs, uint32_t timeout, uint32_t* triggered = NULL) override {} + void waitOnIrqs(uint32_t irqs, uint32_t timeout, bool& timedout, uint32_t* triggered = NULL) override { + timedout = false; + } void ackIrqs(uint32_t irqs) override {} void setPages(uint8_t* pages) { _pages = pages; } diff --git a/tests/test_CSC.cpp b/tests/test_CSC.cpp index 755a6f00..01cc52d0 100644 --- a/tests/test_CSC.cpp +++ b/tests/test_CSC.cpp @@ -50,7 +50,9 @@ class TestFPGA : public FPGA { void writeCommandFIFO(uint16_t*, size_t, uint32_t) override {} void writeRequestFIFO(uint16_t*, size_t, uint32_t) override {} void readU16ResponseFIFO(uint16_t*, size_t, uint32_t) override {} - void waitOnIrqs(uint32_t, uint32_t, uint32_t*) override {} + void waitOnIrqs(uint32_t irqs, uint32_t timeout, bool& timedout, uint32_t* triggered = NULL) override { + timedout = false; + } void ackIrqs(uint32_t) override {} }; diff --git a/tests/test_FirmwareLoad.cpp b/tests/test_FirmwareLoad.cpp index cd87d112..e05bd7e5 100644 --- a/tests/test_FirmwareLoad.cpp +++ b/tests/test_FirmwareLoad.cpp @@ -61,7 +61,9 @@ class TestFPGA : public FPGA { void writeCommandFIFO(uint16_t* data, size_t length, uint32_t timeout) override; void writeRequestFIFO(uint16_t* data, size_t length, uint32_t timeout) override {} void readU16ResponseFIFO(uint16_t* data, size_t length, uint32_t timeout) override; - void waitOnIrqs(uint32_t irqs, uint32_t timeout, uint32_t* triggered = NULL) override {} + void waitOnIrqs(uint32_t irqs, uint32_t timeout, bool& timedout, uint32_t* triggered = NULL) override { + timedout = false; + } void ackIrqs(uint32_t irqs) override {} private: From 2f3b2452c044ea64e9abb6ed04924f6c5b78885e Mon Sep 17 00:00:00 2001 From: Petr Kubanek Date: Mon, 18 Sep 2023 23:33:15 +0200 Subject: [PATCH 6/6] MPU loopWrite, loopRead and runLoop methods --- doc/version-history.rst | 19 ----------- include/cRIO/FPGA.h | 7 ++-- include/cRIO/MPU.h | 59 ++++++++++++++++++++++++++++++++-- include/cRIO/MPUTelemetry.h | 6 ++-- include/cRIO/ModbusBuffer.h | 5 +++ include/cRIO/SimpleFPGA.h | 3 +- include/cRIO/SimulatedMPU.h | 3 ++ src/LSST/cRIO/FPGA.cpp | 2 +- src/LSST/cRIO/MPU.cpp | 44 ++++++++++++++++++++++++- src/LSST/cRIO/MPUTelemetry.cpp | 2 +- src/LSST/cRIO/ModbusBuffer.cpp | 27 +++++++++------- tests/test_ILC.cpp | 3 +- tests/test_MPU.cpp | 45 ++++++++++++++++++-------- 13 files changed, 166 insertions(+), 59 deletions(-) delete mode 100644 doc/version-history.rst diff --git a/doc/version-history.rst b/doc/version-history.rst deleted file mode 100644 index cfd7bcd7..00000000 --- a/doc/version-history.rst +++ /dev/null @@ -1,19 +0,0 @@ -############### -Version History -############### - -v1.9.0 -====== - -* MPU changed to SerialMultiplex - -v1.8.0 -====== - -* LVDT ElectroMechanical readout - -v1.7.0 -====== - -* offsets,.. ILC commands -* improved re-heater gain management diff --git a/include/cRIO/FPGA.h b/include/cRIO/FPGA.h index b16c237c..9ca9873e 100644 --- a/include/cRIO/FPGA.h +++ b/include/cRIO/FPGA.h @@ -27,15 +27,16 @@ #include #include -#include "ILC.h" -#include "MPU.h" -#include "SimpleFPGA.h" +#include +#include using namespace std::chrono_literals; namespace LSST { namespace cRIO { +class MPU; + /** * Interface class for cRIO FPGA. Subclasses can talk either to the real HW, or * be a software simulator. diff --git a/include/cRIO/MPU.h b/include/cRIO/MPU.h index 4f304d11..140a3938 100644 --- a/include/cRIO/MPU.h +++ b/include/cRIO/MPU.h @@ -23,6 +23,7 @@ #ifndef CRIO_MPU_H_ #define CRIO_MPU_H_ +#include #include #include #include @@ -31,6 +32,7 @@ #include +#include #include namespace LSST { @@ -38,19 +40,29 @@ namespace cRIO { /** * Modbus Processing Unit (MPU) commands. Please see - * https://github.com/lsst-ts/Modbus_Processing_Unit for command details. + * https://github.com/lsst-ts/ts_M1M3Thermal/blob/develop/doc/version-history.rst */ namespace MPUCommands { const static uint8_t WRITE = 1; const static uint8_t READ_US = 2; const static uint8_t READ_MS = 3; +const static uint8_t IRQ = 240; const static uint8_t TELEMETRY = 254; const static uint8_t CLEAR = 255; } // namespace MPUCommands +typedef enum { WRITE, READ, IDLE } loop_state_t; + /** * The Modbus Processing Unit class. Prepares buffer with commands to send to * FPGA, read responses & telemetry values. + * + * Values can be queried in a loop. Code then calls registered callback + * function everytime new data become available. For code to work that way, + * interrupt ( + * + * If FPGA is instructed to raise an interrupt during (most likely at the end + * of) buffer execution with the 240 opcode, */ class MPU : public ModbusBuffer { public: @@ -71,6 +83,8 @@ class MPU : public ModbusBuffer { */ uint8_t getBus() { return _bus; } + virtual uint32_t getIrq() { return 1 << (10 + getBus()); } + void setAddress(uint8_t address) { _mpu_address = address; } bool containsRead() { return _contains_read; } @@ -116,7 +130,44 @@ class MPU : public ModbusBuffer { * * @return current command buffer */ - std::vector getCommandVector() { return _commands; } + std::vector getCommandVector(); + + /*** + * Called to set loop read timeout. + * + * @param callback function to call when new data are available + * @param timeout timeout. If data cannot be retrieved within timeout, + * callback function is called with timedout parameter set to true. + */ + void setLoopTimeOut(std::chrono::microseconds timeout) { _loop_timeout = timeout; } + + /*** + * Called to write commands to retrieve values needed in loopRead. + */ + virtual void loopWrite() = 0; + + /*** + * Called to process data read in the loop. + * + * @param timeout + */ + virtual void loopRead(bool timedout) = 0; + + /** + * Runs command loop. This is a state machine, with state stored in + * _loopStatus variable. + * + * In WRITE state, it calls loopWrite to prepare commands for FPGA. + * + * In READ state, it waits for bus IRQ. If wait succeed (IRQ was triggered), + * it reads the output data into a buffer, process the acquired buffer, and + * calls callback (if set). + * + * @param FPGA fpga used to process MPU commands. + */ + void runLoop(FPGA &fpga); + + loop_state_t getLoopState() { return _loop_state; } /*** * Returns cached input state. Input state shall be cached - queried with @@ -168,6 +219,10 @@ class MPU : public ModbusBuffer { std::map _inputStatus; std::map _registers; + + std::chrono::microseconds _loop_timeout; + std::chrono::time_point _loop_next_read; + loop_state_t _loop_state; }; } // namespace cRIO diff --git a/include/cRIO/MPUTelemetry.h b/include/cRIO/MPUTelemetry.h index d23412df..5373287b 100644 --- a/include/cRIO/MPUTelemetry.h +++ b/include/cRIO/MPUTelemetry.h @@ -39,9 +39,9 @@ class MPUTelemetry { * @param data[45] data as received from FPGA */ MPUTelemetry(uint8_t* data); - uint32_t writeBytes; /// Number of bytes written - uint32_t readBytes; /// Number of bytes read - uint16_t readTimedout; /// read timedout counter + uint32_t writeBytes; /// Number of bytes written + uint32_t readBytes; /// Number of bytes read + uint16_t readTimedout; /// read timedout counter friend std::ostream& operator<<(std::ostream& os, const MPUTelemetry& tel); diff --git a/include/cRIO/ModbusBuffer.h b/include/cRIO/ModbusBuffer.h index 92cdb973..a851707e 100644 --- a/include/cRIO/ModbusBuffer.h +++ b/include/cRIO/ModbusBuffer.h @@ -500,6 +500,11 @@ class ModbusBuffer { EndOfBuffer(); }; + class EmptyCommanded : public std::runtime_error { + public: + EmptyCommanded(uint8_t address, uint8_t function); + }; + class UnmatchedFunction : public std::runtime_error { public: UnmatchedFunction(uint8_t address, uint8_t function); diff --git a/include/cRIO/SimpleFPGA.h b/include/cRIO/SimpleFPGA.h index b0b0b2ae..2a7fe8cf 100644 --- a/include/cRIO/SimpleFPGA.h +++ b/include/cRIO/SimpleFPGA.h @@ -26,8 +26,7 @@ #include #include -#include "ILC.h" -#include "MPU.h" +#include namespace LSST { namespace cRIO { diff --git a/include/cRIO/SimulatedMPU.h b/include/cRIO/SimulatedMPU.h index 4912dda2..61bb1903 100644 --- a/include/cRIO/SimulatedMPU.h +++ b/include/cRIO/SimulatedMPU.h @@ -32,6 +32,9 @@ class SimulatedMPU : public MPU { public: SimulatedMPU() : MPU(0, 0) {} SimulatedMPU(uint16_t* buffer, size_t length) : MPU(0, 0) { setBuffer(buffer, length); } + + void loopWrite() override {} + void loopRead(bool timedout) override {} }; } // namespace cRIO diff --git a/src/LSST/cRIO/FPGA.cpp b/src/LSST/cRIO/FPGA.cpp index 803cfc6e..1aa25349 100644 --- a/src/LSST/cRIO/FPGA.cpp +++ b/src/LSST/cRIO/FPGA.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include namespace LSST { namespace cRIO { diff --git a/src/LSST/cRIO/MPU.cpp b/src/LSST/cRIO/MPU.cpp index 0495641e..2237f317 100644 --- a/src/LSST/cRIO/MPU.cpp +++ b/src/LSST/cRIO/MPU.cpp @@ -27,6 +27,8 @@ using namespace LSST::cRIO; MPU::MPU(uint8_t bus, uint8_t mpu_address) : _bus(bus), _mpu_address(mpu_address), _contains_read(false) { + _loop_state = loop_state_t::WRITE; + addResponse( 2, [this](uint8_t address) { @@ -133,6 +135,9 @@ MPU::MPU(uint8_t bus, uint8_t mpu_address) : _bus(bus), _mpu_address(mpu_address void MPU::clearCommanded() { clear(); + + _loop_state = loop_state_t::WRITE; + _commands.clear(); _readInputStatus.clear(); @@ -214,7 +219,7 @@ void MPU::presetHoldingRegister(uint16_t address, uint16_t value, uint16_t timeo _presetRegister.push_back(std::pair(address, value)); } -void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t count, uint16_t timeout) { +void MPU::presetHoldingRegisters(uint16_t address, uint16_t* values, uint8_t count, uint16_t timeout) { write(_mpu_address); write(16); write(address); @@ -245,6 +250,43 @@ void MPU::presetHoldingRegisters(uint16_t address, uint16_t *values, uint8_t cou _presetRegisters.push_back(std::pair(address, count)); } +std::vector MPU::getCommandVector() { + _commands.push_back(MPUCommands::IRQ); + return _commands; +} + +void MPU::runLoop(FPGA& fpga) { + switch (_loop_state) { + case loop_state_t::WRITE: + clearCommanded(); + _loop_next_read = std::chrono::steady_clock::now() + _loop_timeout; + loopWrite(); + fpga.writeMPUFIFO(*this); + _loop_state = loop_state_t::READ; + break; + case loop_state_t::READ: { + bool timedout; + fpga.waitOnIrqs(getIrq(), 0, timedout); + if (timedout) { + if (_loop_next_read > std::chrono::steady_clock::now()) { + return; + } + } else { + fpga.readMPUFIFO(*this); + } + + loopRead(timedout); + _loop_state = loop_state_t::IDLE; + } break; + case loop_state_t::IDLE: + if (_loop_next_read > std::chrono::steady_clock::now()) { + return; + } + _loop_state = loop_state_t::WRITE; + break; + } +} + void MPU::_pushTimeout(uint16_t timeout) { _commands.push_back(timeout >> 8 & 0xff); _commands.push_back(timeout & 0xff); diff --git a/src/LSST/cRIO/MPUTelemetry.cpp b/src/LSST/cRIO/MPUTelemetry.cpp index 865da6e6..0cbd4fcc 100644 --- a/src/LSST/cRIO/MPUTelemetry.cpp +++ b/src/LSST/cRIO/MPUTelemetry.cpp @@ -31,7 +31,7 @@ namespace LSST { namespace cRIO { -MPUTelemetry::MPUTelemetry(uint8_t* data) { +MPUTelemetry::MPUTelemetry(uint8_t *data) { writeBytes = be32toh(*(reinterpret_cast(data + 0))); readBytes = be32toh(*(reinterpret_cast(data + 4))); readTimedout = be16toh(*(reinterpret_cast(data + 8))); diff --git a/src/LSST/cRIO/ModbusBuffer.cpp b/src/LSST/cRIO/ModbusBuffer.cpp index 304f82d9..5d8aa9f0 100644 --- a/src/LSST/cRIO/ModbusBuffer.cpp +++ b/src/LSST/cRIO/ModbusBuffer.cpp @@ -18,7 +18,6 @@ * this program. If not, see . */ -#include #include #include @@ -46,8 +45,8 @@ void ModbusBuffer::reset() { void ModbusBuffer::clear(bool onlyBuffers) { _buffer.clear(); - std::queue> emptyQ; if (onlyBuffers == false) { + std::queue> emptyQ; _commanded.swap(emptyQ); } reset(); @@ -116,7 +115,7 @@ uint32_t ModbusBuffer::readDelay() { break; default: throw std::runtime_error( - fmt::format("Expected delay, finds {:04x} (@ offset {})", _buffer[_index], _index)); + fmt::format("Expected delay, finds {:04x} (@ offset {}).", _buffer[_index], _index)); } _index++; return ret; @@ -173,7 +172,8 @@ void ModbusBuffer::checkCommandedEmpty() { os << +(c.first) << ":" << +(c.second); _commanded.pop(); } - throw std::runtime_error("Responses for those pairs weren't received: " + os.str()); + throw std::runtime_error( + fmt::format("Responses for those pairs weren't received: {}.", os.str())); } void ModbusBuffer::addResponse(uint8_t func, std::function action, uint8_t errorResponse, @@ -223,11 +223,11 @@ void ModbusBuffer::processResponse(uint16_t* response, size_t length) { ModbusBuffer::UnknownResponse::UnknownResponse(uint8_t address, uint8_t func) : std::runtime_error(fmt::format( - "Unknown function {1} (0x{1:02x}) in ModBus response for address {0}", address, func)) {} + "Unknown function {1} (0x{1:02x}) in ModBus response for address {0}.", address, func)) {} ModbusBuffer::Exception::Exception(uint8_t address, uint8_t func, uint8_t exception) : std::runtime_error(fmt::format( - "ModBus Exception {2} (ModBus address {0}, ModBus response function {1} (0x{1:02x}))", + "ModBus Exception {2} (ModBus address {0}, ModBus response function {1} (0x{1:02x})).", address, func, exception)) {} void ModbusBuffer::CRC::add(uint8_t data) { @@ -243,10 +243,15 @@ void ModbusBuffer::CRC::add(uint8_t data) { } ModbusBuffer::CRCError::CRCError(uint16_t calculated, uint16_t received) - : std::runtime_error(fmt::format("checkCRC invalid CRC - expected 0x{:04x}, got 0x{:04x}", calculated, - received)) {} + : std::runtime_error(fmt::format("checkCRC invalid CRC - expected 0x{:04x}, got 0x{:04x}.", + calculated, received)) {} -ModbusBuffer::EndOfBuffer::EndOfBuffer() : std::runtime_error("End of buffer while reading response") {} +ModbusBuffer::EndOfBuffer::EndOfBuffer() : std::runtime_error("End of buffer while reading response.") {} + +ModbusBuffer::EmptyCommanded::EmptyCommanded(uint8_t address, uint8_t func) + : std::runtime_error( + fmt::format("Empty commanded buffer, but reply was received. Address {}, function {}.", + address, func)) {} ModbusBuffer::UnmatchedFunction::UnmatchedFunction(uint8_t address, uint8_t func) : std::runtime_error(fmt::format( @@ -255,7 +260,7 @@ ModbusBuffer::UnmatchedFunction::UnmatchedFunction(uint8_t address, uint8_t func ModbusBuffer::UnmatchedFunction::UnmatchedFunction(uint8_t address, uint8_t func, uint8_t expectedAddress, uint8_t expectedFunction) : std::runtime_error(fmt::format("Invalid response received - expected {0} (0x{0:02x}) from {1}, got " - "{2} (0x{2:02x}) from {3}", + "{2} (0x{2:02x}) from {3}.", expectedFunction, expectedAddress, func, address)) {} uint16_t ModbusBuffer::getByteInstruction(uint8_t data) { @@ -303,7 +308,7 @@ void ModbusBuffer::broadcastFunction(uint8_t address, uint8_t function, uint8_t void ModbusBuffer::checkCommanded(uint8_t address, uint8_t function) { if (_commanded.empty()) { - throw UnmatchedFunction(address, function); + throw EmptyCommanded(address, function); } std::pair last = _commanded.front(); _commanded.pop(); diff --git a/tests/test_ILC.cpp b/tests/test_ILC.cpp index 4222e5ce..49049d96 100644 --- a/tests/test_ILC.cpp +++ b/tests/test_ILC.cpp @@ -449,8 +449,7 @@ TEST_CASE("Unmatched response", "[ILC]") { // missing command ilc1.clear(); ilc1.reportServerID(132); - REQUIRE_THROWS_AS(ilc1.processResponse(ilc2.getBuffer(), ilc2.getLength()), - ModbusBuffer::UnmatchedFunction); + REQUIRE_THROWS_AS(ilc1.processResponse(ilc2.getBuffer(), ilc2.getLength()), ModbusBuffer::EmptyCommanded); // invalid address ilc1.clear(); diff --git a/tests/test_MPU.cpp b/tests/test_MPU.cpp index dd8e2fd2..6a736486 100644 --- a/tests/test_MPU.cpp +++ b/tests/test_MPU.cpp @@ -26,13 +26,21 @@ using namespace LSST::cRIO; +class TestMPU : public MPU { +public: + TestMPU(uint8_t bus, uint8_t mpu_address) : MPU(bus, mpu_address) {} + + void loopWrite() override {} + void loopRead(bool timedout) override {} +}; + TEST_CASE("Test MPU read input status", "[MPU]") { - MPU mpu(1, 0x11); + TestMPU mpu(1, 0x11); mpu.readInputStatus(0x00C4, 0x0016, 108); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 14); + REQUIRE(commands.size() == 15); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -48,6 +56,7 @@ TEST_CASE("Test MPU read input status", "[MPU]") { REQUIRE(commands[11] == 8); REQUIRE(commands[12] == 0); REQUIRE(commands[13] == 108); + REQUIRE(commands[14] == MPUCommands::IRQ); std::vector res = {0x11, 0x02, 0x03, 0xAC, 0xDB, 0x35, 0x20, 0x18}; @@ -91,12 +100,12 @@ TEST_CASE("Test MPU read input status", "[MPU]") { } TEST_CASE("Test MPU read holding registers", "[MPU]") { - MPU mpu(1, 12); + TestMPU mpu(1, 12); mpu.readHoldingRegisters(3, 10, 101); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 14); + REQUIRE(commands.size() == 15); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -112,6 +121,7 @@ TEST_CASE("Test MPU read holding registers", "[MPU]") { REQUIRE(commands[11] == 25); REQUIRE(commands[12] == 0); REQUIRE(commands[13] == 101); + REQUIRE(commands[14] == MPUCommands::IRQ); std::vector res = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -137,13 +147,13 @@ TEST_CASE("Test MPU read holding registers", "[MPU]") { } TEST_CASE("Test MPU reading multiple registers - failed response", "[MPU]") { - MPU mpu(1, 12); + TestMPU mpu(1, 12); mpu.readHoldingRegisters(3, 10, 101); mpu.readHoldingRegisters(103, 10, 101); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 28); + REQUIRE(commands.size() == 29); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -175,6 +185,8 @@ TEST_CASE("Test MPU reading multiple registers - failed response", "[MPU]") { REQUIRE(commands[26] == 0); REQUIRE(commands[27] == 101); + REQUIRE(commands[28] == MPUCommands::IRQ); + std::vector res1 = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -204,13 +216,13 @@ TEST_CASE("Test MPU reading multiple registers - failed response", "[MPU]") { } TEST_CASE("Test MPU reading multiple registers - successful response", "[MPU]") { - MPU mpu(1, 12); + TestMPU mpu(1, 12); mpu.readHoldingRegisters(3, 10, 101); mpu.readHoldingRegisters(103, 10, 101); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 28); + REQUIRE(commands.size() == 29); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -242,6 +254,8 @@ TEST_CASE("Test MPU reading multiple registers - successful response", "[MPU]") REQUIRE(commands[26] == 0); REQUIRE(commands[27] == 101); + REQUIRE(commands[28] == MPUCommands::IRQ); + std::vector res1 = {12, 3, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0xcf, 0xde}; @@ -307,13 +321,13 @@ TEST_CASE("Test MPU reading multiple registers - successful response", "[MPU]") } TEST_CASE("Test MPU preset holding register", "[MPU]") { - MPU mpu(5, 0x11); + TestMPU mpu(5, 0x11); mpu.presetHoldingRegister(0x0001, 0x0003, 102); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 14); + REQUIRE(commands.size() == 15); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 8); @@ -329,6 +343,7 @@ TEST_CASE("Test MPU preset holding register", "[MPU]") { REQUIRE(commands[11] == 8); REQUIRE(commands[12] == 0); REQUIRE(commands[13] == 102); + REQUIRE(commands[14] == MPUCommands::IRQ); std::vector res = {0x11, 0x06, 0x00, 0x01, 0x00, 0x03, 0x9A, 0x9B}; @@ -336,14 +351,14 @@ TEST_CASE("Test MPU preset holding register", "[MPU]") { } TEST_CASE("Test MPU preset holding registers", "[MPU]") { - MPU mpu(5, 17); + TestMPU mpu(5, 17); std::vector regs = {0x0102, 0x0304}; mpu.presetHoldingRegisters(0x1718, regs.data(), regs.size(), 102); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 19); + REQUIRE(commands.size() == 20); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 9 + 2 * regs.size()); @@ -364,6 +379,7 @@ TEST_CASE("Test MPU preset holding registers", "[MPU]") { REQUIRE(commands[16] == 8); REQUIRE(commands[17] == 0); REQUIRE(commands[18] == 102); + REQUIRE(commands[19] == MPUCommands::IRQ); std::vector res = {17, 16, 0x17, 0x18, 0, 2, 0xC6, 0xEB}; @@ -371,14 +387,14 @@ TEST_CASE("Test MPU preset holding registers", "[MPU]") { } TEST_CASE("Test MPU preset holding registers by simplymodbus.ca", "[MPU]") { - MPU mpu(5, 0x11); + TestMPU mpu(5, 0x11); std::vector regs = {0x000A, 0x0102}; mpu.presetHoldingRegisters(0x0001, regs.data(), regs.size(), 102); auto commands = mpu.getCommandVector(); - REQUIRE(commands.size() == 19); + REQUIRE(commands.size() == 20); REQUIRE(commands[0] == MPUCommands::WRITE); REQUIRE(commands[1] == 9 + 2 * regs.size()); @@ -399,6 +415,7 @@ TEST_CASE("Test MPU preset holding registers by simplymodbus.ca", "[MPU]") { REQUIRE(commands[16] == 8); REQUIRE(commands[17] == 0); REQUIRE(commands[18] == 102); + REQUIRE(commands[19] == MPUCommands::IRQ); std::vector res = {0x11, 0x10, 0x00, 0x01, 0x00, 0x02, 0x12, 0x98};