Skip to content

Commit

Permalink
Transports classes to separate data transport from FPGA.
Browse files Browse the repository at this point in the history
  • Loading branch information
pkubanek committed Oct 2, 2024
1 parent f4b9c24 commit 73b7943
Show file tree
Hide file tree
Showing 12 changed files with 4,035 additions and 8 deletions.
3,762 changes: 3,762 additions & 0 deletions include/NiFpga/NiFpga.h

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions include/Transports/FPGASerialDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Serial communication through FPGA FIFOs.
*
* Developed for the Vera C. Rubin Observatory Telescope & Site Software Systems.
* This product includes software developed by the Vera C.Rubin Observatory Project
* (https://www.lsst.org). See the COPYRIGHT file at the top-level directory of
* this distribution for details of code ownership.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef __Transports_FPGASerialDevice__
#define __Transports_FPGASerialDevice__

#include <chrono>

#include "Transport.h"

namespace Transports {

/**
* Communicate with various serial devices hooked on cRIO serial ports.
*/
class FPGASerialDevice : public Transport {
public:
/**
* Construct object to communicate with serial device connected to cRIO.
* The FPGA in cRIO shall use SerialDevice.vi to communicate with the device.
*
* @param fpga_session
* @param write_fifo
* @param read_fifo
*/
FPGASerialDevice(uint32_t fpga_session, int write_fifo, int read_fifo);

void write(const char* buf, size_t len) override;

std::vector<uint8_t> read(size_t len, const std::chrono::duration<long int>& timeout,
LSST::cRIO::Thread* calling_thread = NULL) override;

private:
uint32_t _fpga_session;
int _write_fifo;
int _read_fifo;
};

} // namespace Transports

#endif // !__Transports_FPGASerialDevice__
89 changes: 89 additions & 0 deletions include/Transports/Transport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Transport base class for communication.
*
* Developed for the Vera C. Rubin Observatory Telescope & Site Software Systems.
* This product includes software developed by the Vera C.Rubin Observatory Project
* (https://www.lsst.org). See the COPYRIGHT file at the top-level directory of
* this distribution for details of code ownership.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef __Transports_Transport__
#define __Transports_Transport__

#include <vector>

#include <cRIO/Thread.h>

namespace Transports {

/**
* Base transport class. Provides abstract interface to write and read bytes to
* serial devices. The methods can throw errors on failures.
*/
class Transport {
public:
/**
* Opens transport connection.
*
* @throw std::runtime_error on failure
*/
virtual void open() {}

/**
* Closes transport connection.
*
* @throw std::runtime_error on failure
*/
virtual void close() {}

/**
* Send data to the other end of the transport.
*
* @param buf buffer to send
* @param size its size
*
* @throw std::runtime_error on failure
*/
virtual void write(const char* buf, size_t len) = 0;

/**
* Send data to the other end of the transport.
*
* @param data data to send
*
* @throw std::runtime_error on failure
*/
virtual void write(std::vector<uint8_t> buf) {
write(reinterpret_cast<const char*>(buf.data()), buf.size());
}

/**
* Reads data from transport. Returns data available until timeout expires. Can be interrupted by notifing
* interrupt_condition.
*
* @param len expected len to read. If timeout expires and data aren't available, returns what was read
* @param timeout maximal time to wait for data
* @param interrupt_condition if not NULL, shall be used for waiting
*
* @throw std::runtime_error on failure
*/
virtual std::vector<uint8_t> read(size_t len, const std::chrono::duration<long int>& timeout,
LSST::cRIO::Thread* calling_thread = NULL) = 0;
};

} // namespace Transports

#endif // !__Transports_Transport__
2 changes: 1 addition & 1 deletion include/cRIO/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class Application {
* Prints preamble for commands help. Can include tips which commands to
* use,..
*/
virtual void printGenericHelp() {};
virtual void printGenericHelp(){};

/**
* Process option from command line parsing.
Expand Down
4 changes: 2 additions & 2 deletions include/cRIO/ModbusBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,13 +411,13 @@ class ModbusBuffer {
* Called before responses are processed (before processXX methods are
* called).
*/
virtual void preProcess() {};
virtual void preProcess(){};

/**
* Called after responses are processed (after processXX methods are
* called).
*/
virtual void postProcess() {};
virtual void postProcess(){};

/**
* Thrown when an unknown response function is received. As unknown function
Expand Down
2 changes: 1 addition & 1 deletion include/cRIO/Task.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Task {
*
* @param ex exception raised during processing
*/
virtual void reportException(const std::exception &ex) {};
virtual void reportException(const std::exception &ex){};

static constexpr task_return_t DONT_RESCHEDULE = 0xFFFFFFFF;

Expand Down
14 changes: 14 additions & 0 deletions include/cRIO/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,22 @@ class Thread {
*/
bool joinable();

/**
* Returns whenever thread is running.
*
* @return true if the thread is running.
*/
bool isRunning();

/**
* Waits until given time and while thread is running (wasn't stopped).
*
* @param abs_time time to wait
*
* @return false if thread was requested to stop while waiting, otherwise true.
*/
bool wait_until(std::chrono::time_point<std::chrono::steady_clock> abs_time);

protected:
/**
* Mutex protecting keepRunning access, can be used in condition variable.
Expand Down
3 changes: 2 additions & 1 deletion src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ ElectromechanicalPneumaticILC::ElectromechanicalPneumaticILC(uint8_t bus) : ILC:

addResponse(ILC_EM_CMD::STEPPER_FORCE_STATUS, stepperForceStatus, 195);

addResponse(ILC_EM_CMD::SET_DCA_GAIN, [this](Modbus::Parser parser) { parser.checkCRC(); }, 201);
addResponse(
ILC_EM_CMD::SET_DCA_GAIN, [this](Modbus::Parser parser) { parser.checkCRC(); }, 201);

addResponse(ILC_EM_CMD::REPORT_DCA_GAIN, dcaGain, 202);

Expand Down
2 changes: 2 additions & 0 deletions src/LSST/cRIO/FPGA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ void FPGA::ilcCommands(ILC::ILCBusList &ilc, int32_t timeout) {
}

void FPGA::mpuCommands(MPU &mpu, const std::chrono::duration<double> &timeout) {
auto end = std::chrono::steady_clock::now() + timeout;

for (auto cmd : mpu) {
writeMPUFIFO(mpu, cmd.buffer, 0);

Expand Down
9 changes: 6 additions & 3 deletions src/LSST/cRIO/FPGACliApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ FPGACliApp::FPGACliApp(const char* name, const char* description)
"Temporary disable given ILC in * commands");
addILCCommand("@enable", std::bind(&FPGACliApp::enableILC, this, std::placeholders::_1),
"Re-enable given ILC in * commands");
addILCCommand("info", [](ILCUnit u) { u.first->reportServerID(u.second); }, "Print ILC info");
addILCCommand("status", [](ILCUnit u) { u.first->reportServerStatus(u.second); }, "Print ILC status");
addILCCommand(
"info", [](ILCUnit u) { u.first->reportServerID(u.second); }, "Print ILC info");
addILCCommand(
"status", [](ILCUnit u) { u.first->reportServerStatus(u.second); }, "Print ILC status");
addILCCommand(
"standby", [](ILCUnit u) { u.first->changeILCMode(u.second, ILC::Mode::Standby); },
"Change ILC mode to standby");
Expand All @@ -61,7 +63,8 @@ FPGACliApp::FPGACliApp(const char* name, const char* description)
addILCCommand(
"clear-faults", [](ILCUnit u) { u.first->changeILCMode(u.second, ILC::Mode::ClearFaults); },
"Clear ILC faults");
addILCCommand("reset", [](ILCUnit u) { u.first->resetServer(u.second); }, "Reset server");
addILCCommand(
"reset", [](ILCUnit u) { u.first->resetServer(u.second); }, "Reset server");

addCommand("program-ilc", std::bind(&FPGACliApp::programILC, this, std::placeholders::_1), "FS?",
NEED_FPGA, "<firmware hex file> <ILC...>", "Program ILC with new firmware.");
Expand Down
5 changes: 5 additions & 0 deletions src/LSST/cRIO/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ bool Thread::isRunning() {
return _threadStarted;
}

bool Thread::wait_until(std::chrono::time_point<std::chrono::steady_clock> abs_time) {
std::unique_lock<std::mutex> lg(runMutex);
return (runCondition.wait_until(lg, abs_time, [this] { return keepRunning == true; }));
}

void Thread::_run() {
{
std::unique_lock<std::mutex> lock(runMutex);
Expand Down
91 changes: 91 additions & 0 deletions src/Transports/FPGASerialDevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Serial communication through FPGA FIFOs.
*
* Developed for the Vera C. Rubin Observatory Telescope & Site Software Systems.
* This product includes software developed by the Vera C.Rubin Observatory Project
* (https://www.lsst.org). See the COPYRIGHT file at the top-level directory of
* this distribution for details of code ownership.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <cassert>

#include "cRIO/NiError.h"
#include "NiFpga/NiFpga.h"
#include "Transports/FPGASerialDevice.h"

using namespace LSST::cRIO;
using namespace Transports;

FPGASerialDevice::FPGASerialDevice(uint32_t fpga_session, int write_fifo, int read_fifo)
: _fpga_session(fpga_session), _write_fifo(write_fifo), _read_fifo(read_fifo) {}

void FPGASerialDevice::write(const char* buf, size_t len) {
assert(len < 255);

uint8_t header[2] = {1, static_cast<uint8_t>(len)};
NiThrowError("Writing FIFO write header",
NiFpga_WriteFifoU8(_fpga_session, _write_fifo, header, 2, 0, NULL));
NiThrowError("Writing FIFO write data",
NiFpga_WriteFifoU8(_fpga_session, _write_fifo, reinterpret_cast<const uint8_t*>(buf), len, 0,
NULL));
}

std::vector<uint8_t> FPGASerialDevice::read(size_t len, const std::chrono::duration<long int>& timeout,
LSST::cRIO::Thread* thread) {
auto end = std::chrono::steady_clock::now() + timeout;

std::vector<uint8_t> ret;

bool not_run = true;

do {
if (not_run == false) {
auto end_wait = std::chrono::steady_clock::now() + std::chrono::milliseconds(10);

thread->wait_until(end_wait < end ? end_wait : end);
} else {
not_run = true;
}

uint8_t data[255];

uint8_t req = 2;
NiThrowError("Reading FIFO requesting response",
NiFpga_WriteFifoU8(_fpga_session, _write_fifo, &req, 1, 0, NULL));

uint8_t response[2];
NiThrowError("Reading FIFO reading response and its length",
NiFpga_WriteFifoU8(_fpga_session, _read_fifo, response, 2, 1, NULL));

if (response[0] != 2) {
throw std::runtime_error(fmt::format("Invalid reply from bus - {}, expected 2", response[0]));
}
if (response[1] == 0) {
continue;
}

NiThrowError("ThermalFPGA::readMPUFIFO: reading response",
NiFpga_ReadFifoU8(_fpga_session, _read_fifo, data, response[1], 0, NULL));

ret.insert(ret.end(), data, data + response[1]);
if (ret.size() >= len) {
break;
}

} while (end <= std::chrono::steady_clock::now());

return ret;
}

0 comments on commit 73b7943

Please sign in to comment.