Merge branch 'develop' into mueller/system-subsystems
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good

This commit is contained in:
2022-03-08 08:53:10 +01:00
9 changed files with 0 additions and 0 deletions

View File

@ -1,12 +0,0 @@
target_sources(${TARGET_NAME} PUBLIC
GpioCookie.cpp
LinuxLibgpioIF.cpp
)
target_link_libraries(${TARGET_NAME} PUBLIC
gpiod
)

View File

@ -1,32 +0,0 @@
#include "GpioCookie.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
GpioCookie::GpioCookie() {}
ReturnValue_t GpioCookie::addGpio(gpioId_t gpioId, GpioBase* gpioConfig) {
if (gpioConfig == nullptr) {
sif::debug << "GpioCookie::addGpio: gpioConfig is nullpointer" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
auto gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
auto statusPair = gpioMap.emplace(gpioId, gpioConfig);
if (statusPair.second == false) {
#if FSFW_VERBOSE_LEVEL >= 1
sif::error << "GpioCookie::addGpio: Failed to add GPIO " << gpioId << " to GPIO map"
<< std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
#if FSFW_VERBOSE_LEVEL >= 1
sif::error << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
GpioMap GpioCookie::getGpioMap() const { return gpioMap; }
GpioCookie::~GpioCookie() {}

View File

@ -1,39 +0,0 @@
#ifndef LINUX_GPIO_GPIOCOOKIE_H_
#define LINUX_GPIO_GPIOCOOKIE_H_
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include "GpioIF.h"
#include "gpioDefinitions.h"
/**
* @brief Cookie for the GpioIF. Allows the GpioIF to determine which
* GPIOs to initialize and whether they should be configured as in- or
* output.
* @details One GpioCookie can hold multiple GPIO configurations. To add a new
* GPIO configuration to a GpioCookie use the GpioCookie::addGpio
* function.
*
* @author J. Meier
*/
class GpioCookie : public CookieIF {
public:
GpioCookie();
virtual ~GpioCookie();
ReturnValue_t addGpio(gpioId_t gpioId, GpioBase* gpioConfig);
/**
* @brief Get map with registered GPIOs.
*/
GpioMap getGpioMap() const;
private:
/**
* Returns a copy of the internal GPIO map.
*/
GpioMap gpioMap;
};
#endif /* LINUX_GPIO_GPIOCOOKIE_H_ */

View File

@ -1,54 +0,0 @@
#ifndef LINUX_GPIO_GPIOIF_H_
#define LINUX_GPIO_GPIOIF_H_
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include "gpioDefinitions.h"
class GpioCookie;
/**
* @brief This class defines the interface for objects requiring the control
* over GPIOs.
* @author J. Meier
*/
class GpioIF : public HasReturnvaluesIF {
public:
virtual ~GpioIF(){};
/**
* @brief Called by the GPIO using object.
* @param cookie Cookie specifying informations of the GPIOs required
* by a object.
*/
virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0;
/**
* @brief By implementing this function a child must provide the
* functionality to pull a certain GPIO to high logic level.
*
* @param gpioId A unique number which specifies the GPIO to drive.
* @return Returns RETURN_OK for success. This should never return RETURN_FAILED.
*/
virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0;
/**
* @brief By implementing this function a child must provide the
* functionality to pull a certain GPIO to low logic level.
*
* @param gpioId A unique number which specifies the GPIO to drive.
*/
virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0;
/**
* @brief This function requires a child to implement the functionality to read the state of
* an ouput or input gpio.
*
* @param gpioId A unique number which specifies the GPIO to read.
* @param gpioState State of GPIO will be written to this pointer.
*/
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
};
#endif /* LINUX_GPIO_GPIOIF_H_ */

View File

@ -1,295 +0,0 @@
#include "LinuxLibgpioIF.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <gpiod.h>
#include <linux/gpio/gpioDefinitions.h>
#include <unistd.h>
#include <utility>
#include "GpioCookie.h"
LinuxLibgpioIF::LinuxLibgpioIF(object_id_t objectId) : SystemObject(objectId) {
struct gpiod_chip* chip = gpiod_chip_open_by_label("/amba_pl/gpio@42030000");
sif::debug << chip->name << std::endl;
}
LinuxLibgpioIF::~LinuxLibgpioIF() {}
ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
ReturnValue_t result;
if (gpioCookie == nullptr) {
sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl;
return RETURN_FAILED;
}
GpioMap mapToAdd = gpioCookie->getGpioMap();
/* Check whether this ID already exists in the map and remove duplicates */
result = checkForConflicts(mapToAdd);
if (result != RETURN_OK) {
return result;
}
result = configureGpios(mapToAdd);
if (result != RETURN_OK) {
return RETURN_FAILED;
}
/* Register new GPIOs in gpioMap */
gpioMap.insert(mapToAdd.begin(), mapToAdd.end());
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
for (auto& gpioConfig : mapToAdd) {
switch (gpioConfig.second->gpioType) {
case (gpio::GpioTypes::NONE): {
return GPIO_INVALID_INSTANCE;
}
case (gpio::GpioTypes::GPIOD_REGULAR): {
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureRegularGpio(gpioConfig.first, regularGpio);
break;
}
case (gpio::GpioTypes::CALLBACK): {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioConfig.second);
if (gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioConfig.first, gpio::GpioOperation::WRITE,
gpioCallback->initValue, gpioCallback->callbackArgs);
}
}
}
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular* regularGpio) {
std::string chipname;
unsigned int lineNum;
struct gpiod_chip* chip;
gpio::Direction direction;
std::string consumer;
struct gpiod_line* lineHandle;
int result = 0;
chipname = regularGpio->chipname;
chip = gpiod_chip_open_by_name(chipname.c_str());
if (!chip) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to open chip " << chipname
<< ". Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED;
}
lineNum = regularGpio->lineNum;
lineHandle = gpiod_chip_get_line(chip, lineNum);
if (!lineHandle) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to open line for GPIO with id " << gpioId
<< std::endl;
gpiod_chip_close(chip);
return RETURN_FAILED;
}
direction = regularGpio->direction;
consumer = regularGpio->consumer;
/* Configure direction and add a description to the GPIO */
switch (direction) {
case (gpio::OUT): {
result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio->initValue);
if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " << lineNum
<< " from GPIO instance with ID: " << gpioId << std::endl;
gpiod_line_release(lineHandle);
return RETURN_FAILED;
}
break;
}
case (gpio::IN): {
result = gpiod_line_request_input(lineHandle, consumer.c_str());
if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " << lineNum
<< " from GPIO instance with ID: " << gpioId << std::endl;
gpiod_line_release(lineHandle);
return RETURN_FAILED;
}
break;
}
default: {
sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" << std::endl;
return GPIO_INVALID_INSTANCE;
}
}
/**
* Write line handle to GPIO configuration instance so it can later be used to set or
* read states of GPIOs.
*/
regularGpio->lineHandle = lineHandle;
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
sif::warning << "LinuxLibgpioIF::driveGpio: Unknown GPIOD ID " << gpioId << std::endl;
return UNKNOWN_GPIO_ID;
}
if (gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 1);
} else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if (gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, 1,
gpioCallback->callbackArgs);
}
return GPIO_TYPE_FAILURE;
}
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
sif::warning << "LinuxLibgpioIF::driveGpio: Unknown GPIOD ID " << gpioId << std::endl;
return UNKNOWN_GPIO_ID;
}
if (gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 0);
} else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if (gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, 0,
gpioCallback->callbackArgs);
}
return GPIO_TYPE_FAILURE;
}
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegular* regularGpio,
unsigned int logicLevel) {
if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
int result = gpiod_line_set_value(regularGpio->lineHandle, logicLevel);
if (result < 0) {
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId
<< " to logic level " << logicLevel << std::endl;
return DRIVE_GPIO_FAILURE;
}
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl;
return UNKNOWN_GPIO_ID;
}
if (gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
} else {
}
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd) {
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (auto& gpioConfig : mapToAdd) {
switch (gpioConfig.second->gpioType) {
case (gpio::GpioTypes::GPIOD_REGULAR): {
auto regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
/* Check for conflicts and remove duplicates if necessary */
result = checkForConflictsRegularGpio(gpioConfig.first, regularGpio, mapToAdd);
if (result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
break;
}
case (gpio::GpioTypes::CALLBACK): {
auto callbackGpio = dynamic_cast<GpioCallback*>(gpioConfig.second);
if (callbackGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
/* Check for conflicts and remove duplicates if necessary */
result = checkForConflictsCallbackGpio(gpioConfig.first, callbackGpio, mapToAdd);
if (result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
break;
}
default: {
}
}
}
return status;
}
ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck,
GpiodRegular* gpioToCheck,
GpioMap& mapToAdd) {
/* Cross check with private map */
gpioMapIter = gpioMap.find(gpioIdToCheck);
if (gpioMapIter != gpioMap.end()) {
if (gpioMapIter->second->gpioType != gpio::GpioTypes::GPIOD_REGULAR) {
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
"GPIO type"
<< gpioIdToCheck << ". Removing duplicate." << std::endl;
mapToAdd.erase(gpioIdToCheck);
return HasReturnvaluesIF::RETURN_OK;
}
auto ownRegularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
if (ownRegularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
/* Remove element from map to add because a entry for this GPIO
already exists */
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
<< " detected. Duplicate will be removed from map to add." << std::endl;
mapToAdd.erase(gpioIdToCheck);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToCheck,
GpioCallback* callbackGpio,
GpioMap& mapToAdd) {
/* Cross check with private map */
gpioMapIter = gpioMap.find(gpioIdToCheck);
if (gpioMapIter != gpioMap.end()) {
if (gpioMapIter->second->gpioType != gpio::GpioTypes::CALLBACK) {
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
"GPIO type"
<< gpioIdToCheck << ". Removing duplicate." << std::endl;
mapToAdd.erase(gpioIdToCheck);
return HasReturnvaluesIF::RETURN_OK;
}
/* Remove element from map to add because a entry for this GPIO
already exists */
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
<< " detected. Duplicate will be removed from map to add." << std::endl;
mapToAdd.erase(gpioIdToCheck);
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,75 +0,0 @@
#ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_
#define LINUX_GPIO_LINUXLIBGPIOIF_H_
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfwconfig/returnvalues/classIds.h>
#include <linux/gpio/GpioIF.h>
class GpioCookie;
/**
* @brief This class implements the GpioIF for a linux based system. The
* implementation is based on the libgpiod lib which requires linux 4.8
* or higher.
* @note The Petalinux SDK from Xilinx supports libgpiod since Petalinux
* 2019.1.
*/
class LinuxLibgpioIF : public GpioIF, public SystemObject {
public:
static const uint8_t gpioRetvalId = CLASS_ID::LINUX_LIBGPIO_IF;
static constexpr ReturnValue_t UNKNOWN_GPIO_ID =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 1);
static constexpr ReturnValue_t DRIVE_GPIO_FAILURE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 2);
static constexpr ReturnValue_t GPIO_TYPE_FAILURE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3);
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF();
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
ReturnValue_t pullHigh(gpioId_t gpioId) override;
ReturnValue_t pullLow(gpioId_t gpioId) override;
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
private:
/* Holds the information and configuration of all used GPIOs */
GpioMap gpioMap;
GpioMapIter gpioMapIter;
/**
* @brief This functions drives line of a GPIO specified by the GPIO ID.
*
* @param gpioId The GPIO ID of the GPIO to drive.
* @param logiclevel The logic level to set. O or 1.
*/
ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio, unsigned int logiclevel);
ReturnValue_t configureRegularGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio);
/**
* @brief This function checks if GPIOs are already registered and whether
* there exists a conflict in the GPIO configuration. E.g. the
* direction.
*
* @param mapToAdd The GPIOs which shall be added to the gpioMap.
*
* @return RETURN_OK if successful, otherwise RETURN_FAILED
*/
ReturnValue_t checkForConflicts(GpioMap& mapToAdd);
ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegular* regularGpio,
GpioMap& mapToAdd);
ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio,
GpioMap& mapToAdd);
/**
* @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd.
*/
ReturnValue_t configureGpios(GpioMap& mapToAdd);
};
#endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */

View File

@ -1,83 +0,0 @@
#ifndef LINUX_GPIO_GPIODEFINITIONS_H_
#define LINUX_GPIO_GPIODEFINITIONS_H_
#include <string>
#include <unordered_map>
using gpioId_t = uint16_t;
namespace gpio {
enum Levels { LOW = 0, HIGH = 1 };
enum Direction { IN = 0, OUT = 1 };
enum GpioOperation { READ, WRITE };
enum GpioTypes { NONE, GPIOD_REGULAR, CALLBACK };
static constexpr gpioId_t NO_GPIO = -1;
} // namespace gpio
/**
* @brief Struct containing information about the GPIO to use. This is
* required by the libgpiod to access and drive a GPIO.
* @param chipname String of the chipname specifying the group which contains the GPIO to
* access. E.g. gpiochip0. To detect names of GPIO groups run gpiodetect on
* the linux command line.
* @param lineNum The offset of the GPIO within the GPIO group.
* @param consumer Name of the consumer. Simply a description of the GPIO configuration.
* @param direction Specifies whether the GPIO should be used as in- or output.
* @param initValue Defines the initial state of the GPIO when configured as output.
* Only required for output GPIOs.
* @param lineHandle The handle returned by gpiod_chip_get_line will be later written to this
* pointer.
*/
class GpioBase {
public:
GpioBase() = default;
GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, int initValue)
: gpioType(gpioType), consumer(consumer), direction(direction), initValue(initValue) {}
virtual ~GpioBase(){};
/* Can be used to cast GpioBase to a concrete child implementation */
gpio::GpioTypes gpioType = gpio::GpioTypes::NONE;
std::string consumer;
gpio::Direction direction = gpio::Direction::IN;
int initValue = 0;
};
class GpiodRegular : public GpioBase {
public:
GpiodRegular()
: GpioBase(gpio::GpioTypes::GPIOD_REGULAR, std::string(), gpio::Direction::IN, 0){};
GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_)
: GpioBase(gpio::GpioTypes::GPIOD_REGULAR, consumer_, direction_, initValue_),
chipname(chipname_),
lineNum(lineNum_) {}
std::string chipname;
int lineNum = 0;
struct gpiod_line* lineHandle = nullptr;
};
class GpioCallback : public GpioBase {
public:
GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_,
void (*callback)(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args),
void* callbackArgs)
: GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_),
callback(callback),
callbackArgs(callbackArgs) {}
void (*callback)(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args) = nullptr;
void* callbackArgs = nullptr;
};
using GpioMap = std::unordered_map<gpioId_t, GpioBase*>;
using GpioMapIter = GpioMap::iterator;
#endif /* LINUX_GPIO_GPIODEFINITIONS_H_ */

View File

@ -1,128 +0,0 @@
#include <fcntl.h>
#include <linux/obc/Ptme.h>
#include <sys/mman.h>
CCSDSIPCoreBridge::CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
LinuxLibgpioIF* gpioComIF, std::string uioPtme,
gpioId_t papbBusyId, gpioId_t papbEmptyId)
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId),
gpioComIF(gpioComIF),
uioPtme(uioPtme),
papbBusyId(papbBusyId),
papbEmptyId(papbEmptyId) {}
CCSDSIPCoreBridge::~CCSDSIPCoreBridge() {}
ReturnValue_t CCSDSIPCoreBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize();
fd = open("/dev/uio0", O_RDWR);
if (fd < 1) {
sif::debug << "CCSDSIPCoreBridge::initialize: Invalid UIO device file" << std::endl;
return RETURN_FAILED;
}
/**
* Map uio device in virtual address space
* PROT_WRITE: Map uio device in writable only mode
*/
ptmeBaseAddress =
static_cast<uint32_t*>(mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
if (ptmeBaseAddress == MAP_FAILED) {
sif::error << "CCSDSIPCoreBridge::initialize: Failed to map uio address" << std::endl;
return RETURN_FAILED;
}
return result;
}
ReturnValue_t CCSDSIPCoreBridge::handleTm() {
#if OBSW_TEST_CCSDS_PTME == 1
return sendTestFrame();
#else
return TmTcBridge::handleTm();
#endif
}
ReturnValue_t CCSDSIPCoreBridge::sendTm(const uint8_t* data, size_t dataLen) {
if (pollPapbBusySignal() == RETURN_OK) {
startPacketTransfer();
}
for (size_t idx = 0; idx < dataLen; idx++) {
if (pollPapbBusySignal() == RETURN_OK) {
*(ptmeBaseAddress + PTME_DATA_REG_OFFSET) = static_cast<uint32_t>(*(data + idx));
} else {
sif::debug << "CCSDSIPCoreBridge::sendTm: Only written " << idx - 1 << " of " << dataLen
<< " data" << std::endl;
return RETURN_FAILED;
}
}
if (pollPapbBusySignal() == RETURN_OK) {
endPacketTransfer();
}
return RETURN_OK;
}
void CCSDSIPCoreBridge::startPacketTransfer() { *ptmeBaseAddress = PTME_CONFIG_START; }
void CCSDSIPCoreBridge::endPacketTransfer() { *ptmeBaseAddress = PTME_CONFIG_END; }
ReturnValue_t CCSDSIPCoreBridge::pollPapbBusySignal() {
int papbBusyState = 0;
ReturnValue_t result = RETURN_OK;
/** Check if PAPB interface is ready to receive data */
result = gpioComIF->readGpio(papbBusyId, &papbBusyState);
if (result != RETURN_OK) {
sif::debug << "CCSDSIPCoreBridge::pollPapbBusySignal: Failed to read papb busy signal"
<< std::endl;
return RETURN_FAILED;
}
if (!papbBusyState) {
sif::debug << "CCSDSIPCoreBridge::pollPapbBusySignal: PAPB busy" << std::endl;
return PAPB_BUSY;
}
return RETURN_OK;
}
void CCSDSIPCoreBridge::isPtmeBufferEmpty() {
ReturnValue_t result = RETURN_OK;
int papbEmptyState = 1;
result = gpioComIF->readGpio(papbEmptyId, &papbEmptyState);
if (result != RETURN_OK) {
sif::debug << "CCSDSIPCoreBridge::isPtmeBufferEmpty: Failed to read papb empty signal"
<< std::endl;
return;
}
if (papbEmptyState == 1) {
sif::debug << "CCSDSIPCoreBridge::isPtmeBufferEmpty: Buffer is empty" << std::endl;
} else {
sif::debug << "CCSDSIPCoreBridge::isPtmeBufferEmpty: Buffer is not empty" << std::endl;
}
return;
}
ReturnValue_t CCSDSIPCoreBridge::sendTestFrame() {
/** Size of one complete transfer frame data field amounts to 1105 bytes */
uint8_t testPacket[1105];
/** Fill one test packet */
for (int idx = 0; idx < 1105; idx++) {
testPacket[idx] = static_cast<uint8_t>(idx & 0xFF);
}
ReturnValue_t result = sendTm(testPacket, 1105);
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}

View File

@ -1,129 +0,0 @@
#ifndef MISSION_OBC_CCSDSIPCOREBRIDGE_H_
#define MISSION_OBC_CCSDSIPCOREBRIDGE_H_
#include <fsfw/tmtcservices/TmTcBridge.h>
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include <cstring>
#include "OBSWConfig.h"
/**
* @brief This class handles the interfacing to the telemetry (PTME) and telecommand (PDEC) IP
* cores responsible for the CCSDS encoding and decoding. The IP cores are implemented
* on the programmable logic and are accessible through the linux UIO driver.
*/
class CCSDSIPCoreBridge : public TmTcBridge {
public:
/**
* @brief Constructor
*
* @param objectId
* @param tcDestination
* @param tmStoreId
* @param tcStoreId
* @param uioPtme Name of the uio device file which provides access to the PTME IP Core.
* @param papbBusyId The ID of the GPIO which is connected to the PAPBBusy_N signal of the
* PTME IP Core. A low logic level indicates the PTME is not ready to
* receive more data.
* @param papbEmptyId The ID of the GPIO which is connected to the PAPBEmpty signal of the
* PTME IP Core. The signal is high when there are no packets in the
* external buffer memory (BRAM).
*/
CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF, std::string uioPtme,
gpioId_t papbBusyId, gpioId_t papbEmptyId);
virtual ~CCSDSIPCoreBridge();
ReturnValue_t initialize() override;
protected:
/**
* Overwriting this function to provide the capability of testing the PTME IP Core
* implementation.
*/
virtual ReturnValue_t handleTm() override;
virtual ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE;
static const ReturnValue_t PAPB_BUSY = MAKE_RETURN_CODE(0xA0);
/** Size of mapped address space. 4k (minimal size of pl device) */
// static const int MAP_SIZE = 0xFA0;
static const int MAP_SIZE = 0x1000;
/**
* Configuration bits:
* bit[1:0]: Size of data (1,2,3 or 4 bytes). 1 Byte <=> b00
* bit[2]: Set this bit to 1 to abort a transfered packet
* bit[3]: Signals to PTME the start of a new telemetry packet
*/
static const uint32_t PTME_CONFIG_START = 0x8;
/**
* Writing this word to the ptme base address signals to the PTME that a complete tm packet has
* been transferred.
*/
static const uint32_t PTME_CONFIG_END = 0x0;
/**
* Writing to this offset within the PTME memory space will insert data for encoding to the
* PTME IP core.
* The address offset is 0x400 (= 4 * 256)
*/
static const int PTME_DATA_REG_OFFSET = 256;
LinuxLibgpioIF* gpioComIF = nullptr;
/** The uio device file related to the PTME IP Core */
std::string uioPtme;
/** Pulled to low when PTME not ready to receive data */
gpioId_t papbBusyId = gpio::NO_GPIO;
/** High when externally buffer memory of PTME is empty */
gpioId_t papbEmptyId = gpio::NO_GPIO;
/** The file descriptor of the UIO driver */
int fd;
uint32_t* ptmeBaseAddress = nullptr;
/**
* @brief This function sends the config byte to the PTME IP Core to initiate a packet
* transfer.
*/
void startPacketTransfer();
/**
* @brief This function sends the config byte to the PTME IP Core to signal the end of a
* packet transfer.
*/
void endPacketTransfer();
/**
* @brief This function reads the papb busy signal indicating whether the PAPB interface is
* ready to receive more data or not. PAPB is ready when PAPB_Busy_N == '1'.
*
* @return RETURN_OK when ready to receive data else PAPB_BUSY.
*/
ReturnValue_t pollPapbBusySignal();
/**
* @brief This function can be used for debugging to check wheter there are packets in
* the packet buffer of the PTME or not.
*/
void isPtmeBufferEmpty();
/**
* @brief This function sends a complete telemetry transfer frame data field (1105 bytes)
* to the input of the PTME IP Core. Can be used to test the implementation.
*/
ReturnValue_t sendTestFrame();
};
#endif /* MISSION_OBC_CCSDSIPCOREBRIDGE_H_ */