Merge branch 'develop' into mohr/cmake
Some checks are pending
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
EIVE/eive-obsw/pipeline/head Build queued...

This commit is contained in:
2022-02-10 16:22:28 +01:00
45 changed files with 1898 additions and 780 deletions

View File

@ -1,5 +1,101 @@
#include <linux/boardtest/I2cTestClass.h>
#include "I2cTestClass.h"
I2cTestClass::I2cTestClass(object_id_t objectId) : TestTask(objectId) {}
#include <errno.h>
#include <fsfw_hal/linux/UnixFileGuard.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
ReturnValue_t I2cTestClass::performPeriodicAction() { return HasReturnvaluesIF::RETURN_OK; }
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serviceinterface.h"
I2cTestClass::I2cTestClass(object_id_t objectId, std::string i2cdev)
: TestTask(objectId), i2cdev(i2cdev) {
mode = TestModes::BPX_BATTERY;
}
ReturnValue_t I2cTestClass::initialize() {
if (mode == TestModes::BPX_BATTERY) {
battInit();
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cTestClass::performPeriodicAction() {
if (mode == TestModes::BPX_BATTERY) {
battPeriodic();
}
return HasReturnvaluesIF::RETURN_OK;
}
void I2cTestClass::battInit() {
sif::info << "I2cTestClass: BPX Initialization" << std::endl;
UnixFileGuard fileHelper(i2cdev, &bpxInfo.fd, O_RDWR, "I2cTestClass::sendMessage");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Opening I2C device" << i2cdev << " failed" << std::endl;
return;
}
if (ioctl(bpxInfo.fd, I2C_SLAVE, bpxInfo.addr) < 0) {
sif::error << "Failed to acquire bus access and/or talk to slave" << std::endl;
}
cmdBuf[0] = BpxBattery::PORT_PING;
cmdBuf[1] = 0x42;
sendLen = 2;
ReturnValue_t result = i2cWrite(bpxInfo.fd, cmdBuf.data(), sendLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return;
}
// Receive back port, error byte and ping reply
recvLen = 3;
result = i2cRead(bpxInfo.fd, replyBuf.data(), recvLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return;
}
sif::info << "Ping reply:" << std::endl;
arrayprinter::print(replyBuf.data(), recvLen);
if (replyBuf[2] != 0x42) {
sif::warning << "Received ping reply not expected value 0x42" << std::endl;
}
}
void I2cTestClass::battPeriodic() {
UnixFileGuard fileHelper(i2cdev, &bpxInfo.fd, O_RDWR, "I2cTestClass::sendMessage");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Opening I2C device" << i2cdev << " failed" << std::endl;
return;
}
if (ioctl(bpxInfo.fd, I2C_SLAVE, bpxInfo.addr) < 0) {
sif::error << "Failed to acquire bus access and/or talk to slave" << std::endl;
}
cmdBuf[0] = BpxBattery::PORT_GET_HK;
sendLen = 1;
ReturnValue_t result = i2cWrite(bpxInfo.fd, cmdBuf.data(), sendLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return;
}
// Receive back HK set
recvLen = 23;
result = i2cRead(bpxInfo.fd, replyBuf.data(), recvLen);
if (result != HasReturnvaluesIF::RETURN_OK) {
return;
}
sif::info << "HK reply:" << std::endl;
arrayprinter::print(replyBuf.data(), recvLen);
}
ReturnValue_t I2cTestClass::i2cWrite(int fd, uint8_t* data, size_t len) {
if (write(fd, data, len) != static_cast<ssize_t>(len)) {
sif::error << "Failed to write to I2C bus" << std::endl;
sif::error << "Error " << errno << ": " << strerror(errno) << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cTestClass::i2cRead(int fd, uint8_t* data, size_t len) {
if (read(fd, data, len) != static_cast<ssize_t>(len)) {
sif::error << "Failed to read from I2C bus" << std::endl;
sif::error << "Error " << errno << ": " << strerror(errno) << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -3,13 +3,38 @@
#include <test/testtasks/TestTask.h>
#include <array>
#include <string>
#include "mission/devices/devicedefinitions/BpxBatteryDefinitions.h"
class I2cTestClass : public TestTask {
public:
I2cTestClass(object_id_t objectId);
I2cTestClass(object_id_t objectId, std::string i2cdev);
ReturnValue_t initialize() override;
ReturnValue_t performPeriodicAction() override;
private:
enum TestModes { NONE, BPX_BATTERY };
struct I2cInfo {
int addr = 0;
int fd = 0;
};
TestModes mode = TestModes::NONE;
void battInit();
void battPeriodic();
I2cInfo bpxInfo = {.addr = 0x07, .fd = 0};
std::string i2cdev;
size_t sendLen = 0;
size_t recvLen = 0;
std::array<uint8_t, 64> cmdBuf = {};
std::array<uint8_t, 64> replyBuf = {};
ReturnValue_t i2cWrite(int fd, uint8_t* data, size_t len);
ReturnValue_t i2cRead(int fd, uint8_t* data, size_t len);
};
#endif /* LINUX_BOARDTEST_I2CTESTCLASS_H_ */

View File

@ -1,4 +1,6 @@
#include "UartTestClass.h"
#include <fsfw/tasks/TaskFactory.h>
#if defined(RASPBERRY_PI)
#include "rpiConfig.h"
#elif defined(XIPHOS_Q7S)
@ -9,14 +11,37 @@
#include <fcntl.h> // Contains file controls like O_RDWR
#include <unistd.h> // write(), read(), close()
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "lwgps/lwgps.h"
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/globalfunctions/DleEncoder.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serviceinterface.h"
#include "mission/devices/devicedefinitions/SCEXDefinitions.h"
#define GPS_REPLY_WIRETAPPING 0
UartTestClass::UartTestClass(object_id_t objectId) : TestTask(objectId) {}
UartTestClass::UartTestClass(object_id_t objectId) : TestTask(objectId) { mode = TestModes::SCEX; }
ReturnValue_t UartTestClass::initialize() {
if (mode == TestModes::GPS) {
gpsInit();
} else if (mode == TestModes::SCEX) {
scexInit();
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UartTestClass::performOneShotAction() { return HasReturnvaluesIF::RETURN_OK; }
ReturnValue_t UartTestClass::performPeriodicAction() {
if (mode == TestModes::GPS) {
gpsPeriodic();
} else if (mode == TestModes::SCEX) {
scexPeriodic();
}
return HasReturnvaluesIF::RETURN_OK;
}
void UartTestClass::gpsInit() {
#if RPI_TEST_GPS_DEVICE == 1
int result = lwgps_init(&gpsData);
if (result == 0) {
@ -62,16 +87,9 @@ ReturnValue_t UartTestClass::initialize() {
// Flush received and unread data. Those are old NMEA strings which are not relevant anymore
tcflush(serialPort, TCIFLUSH);
#endif
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UartTestClass::performOneShotAction() {
#if RPI_TEST_GPS_DEVICE == 1
#endif
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UartTestClass::performPeriodicAction() {
void UartTestClass::gpsPeriodic() {
#if RPI_TEST_GPS_DEVICE == 1
int bytesRead = 0;
do {
@ -107,5 +125,97 @@ ReturnValue_t UartTestClass::performPeriodicAction() {
}
} while (bytesRead > 0);
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void UartTestClass::scexInit() {
#if defined(RASPBERRY_PI)
std::string devname = "/dev/ttyUSB1";
#else
std::string devname = "/dev/ul-scex";
#endif
/* Get file descriptor */
serialPort = open(devname.c_str(), O_RDWR);
if (serialPort < 0) {
sif::warning << "open call failed with error [" << errno << ", " << strerror(errno)
<< std::endl;
return;
}
// Setting up UART parameters
tty.c_cflag &= ~PARENB; // Clear parity bit
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
tty.c_cflag &= ~CSIZE; // Clear all the size bits
tty.c_cflag |= CS8; // 8 bits per byte
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
// Use non-canonical mode and clear echo flag
tty.c_lflag &= ~(ICANON | ECHO);
// Non-blocking mode, read until either line is 0.1 second idle or maximum of 255 bytes are
// received in one go
tty.c_cc[VTIME] = 1; // In units of 0.1 seconds
tty.c_cc[VMIN] = 255; // Read up to 255 bytes
if (tcsetattr(serialPort, TCSANOW, &tty) != 0) {
sif::warning << "tcsetattr call failed with error [" << errno << ", " << strerror(errno)
<< std::endl;
}
// Flush received and unread data
tcflush(serialPort, TCIFLUSH);
}
void UartTestClass::scexPeriodic() {
auto dleEncoder = DleEncoder();
std::array<uint8_t, 128> tmpCmdBuf = {};
// Send ping command
tmpCmdBuf[0] = scex::CMD_PING;
// These two fields are the packet counter and the total packet count. Those are 1 and 1 for each
// telecommand so far
tmpCmdBuf[1] = 1;
tmpCmdBuf[2] = 1;
uint16_t userDataLen = 0;
tmpCmdBuf[3] = (userDataLen >> 8) & 0xff;
tmpCmdBuf[4] = userDataLen & 0xff;
uint16_t crc = CRC::crc16ccitt(tmpCmdBuf.data(), 5);
tmpCmdBuf[5] = (crc >> 8) & 0xff;
tmpCmdBuf[6] = crc & 0xff;
size_t encodedLen = 0;
ReturnValue_t result =
dleEncoder.encode(tmpCmdBuf.data(), 7, cmdBuf.data(), cmdBuf.size(), &encodedLen, true);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "UartTestClass::scexInit: Encoding failed" << std::endl;
return;
}
arrayprinter::print(cmdBuf.data(), 9);
size_t bytesWritten = write(serialPort, cmdBuf.data(), encodedLen);
if (bytesWritten != encodedLen) {
sif::warning << "Sending ping command to solar experiment failed" << std::endl;
}
TaskFactory::delayTask(20);
bytesWritten = write(serialPort, cmdBuf.data(), encodedLen);
if (bytesWritten != encodedLen) {
sif::warning << "Sending ping command to solar experiment failed" << std::endl;
}
// Read back reply immediately
int bytesRead = 0;
do {
bytesRead = read(serialPort, reinterpret_cast<void*>(recBuf.data()),
static_cast<unsigned int>(recBuf.size()));
if (bytesRead < 0) {
sif::warning << "UartTestClass::performPeriodicAction: read call failed with error [" << errno
<< ", " << strerror(errno) << "]" << std::endl;
break;
} else if (bytesRead >= static_cast<int>(recBuf.size())) {
sif::debug << "UartTestClass::performPeriodicAction: "
"recv buffer might not be large enough"
<< std::endl;
} else if (bytesRead > 0) {
sif::info << "Received " << bytesRead << " from the Solar Cell Experiment:" << std::endl;
arrayprinter::print(recBuf.data(), bytesRead);
}
} while (bytesRead > 0);
}

View File

@ -17,10 +17,23 @@ class UartTestClass : public TestTask {
ReturnValue_t performPeriodicAction() override;
private:
enum TestModes {
GPS,
// Solar Cell Experiment
SCEX
};
void gpsInit();
void gpsPeriodic();
void scexInit();
void scexPeriodic();
TestModes mode = TestModes::GPS;
lwgps_t gpsData = {};
struct termios tty = {};
int serialPort = 0;
std::array<uint8_t, 512> recBuf;
std::array<uint8_t, 64> cmdBuf = {};
std::array<uint8_t, 4096> recBuf = {};
uint8_t recvCnt = 0;
};

View File

@ -73,6 +73,7 @@ static constexpr size_t FSFW_MAX_TM_PACKET_SIZE = 2048;
}
#define FSFW_HAL_SPI_WIRETAPPING 0
#define FSFW_HAL_I2C_WIRETAPPING 0
#define FSFW_DEV_HYPERION_GPS_CREATE_NMEA_CSV 0
#define FSFW_HAL_L3GD20_GYRO_DEBUG 0

View File

@ -41,6 +41,7 @@ debugging. */
#define OBSW_ENABLE_TIMERS 1
#define OBSW_ADD_MGT 1
#define OBSW_ADD_BPX_BATTERY_HANDLER 1
#define OBSW_ADD_STAR_TRACKER 0
#define OBSW_ADD_PLOC_SUPERVISOR 0
#define OBSW_ADD_PLOC_MPSOC 0
@ -53,6 +54,7 @@ debugging. */
#define OBSW_ADD_RAD_SENSORS 0
#define OBSW_ADD_SYRLINKS 0
#define OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT 0
#define OBSW_ENABLE_PERIODIC_HK 0
#endif
@ -64,15 +66,21 @@ debugging. */
#define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 1
#define OBSW_PRINT_MISSED_DEADLINES 1
// If this is enabled, all other SPI code should be disabled
#define OBSW_SYRLINKS_SIMULATED 1
#define OBSW_ADD_TEST_CODE 0
#define OBSW_ADD_SPI_TEST_CODE 0
#define OBSW_ADD_TEST_PST 0
#define OBSW_ADD_TEST_TASK 0
#define OBSW_ADD_TEST_PST 0
// If this is enabled, all other SPI code should be disabled
#define OBSW_ADD_SPI_TEST_CODE 0
// If this is enabled, all other I2C code should be disabled
#define OBSW_ADD_I2C_TEST_CODE 0
#define OBSW_ADD_UART_TEST_CODE 0
#define OBSW_TEST_LIBGPIOD 0
#define OBSW_TEST_RADIATION_SENSOR_HANDLER 0
#define OBSW_TEST_SUS_HANDLER 0
#define OBSW_TEST_PLOC_HANDLER 0
#define OBSW_TEST_BPX_BATT 0
#define OBSW_TEST_CCSDS_BRIDGE 0
#define OBSW_TEST_CCSDS_PTME 0
#define OBSW_TEST_TE7020_HEATER 0
@ -80,6 +88,7 @@ debugging. */
#define OBSW_TEST_GPIO_OPEN_BY_LINE_NAME 0
#define OBSW_DEBUG_P60DOCK 0
#define OBSW_DEBUG_BPX_BATT 0
#define OBSW_DEBUG_PDU1 0
#define OBSW_DEBUG_PDU2 0
#define OBSW_DEBUG_GPS 0

View File

@ -29,6 +29,7 @@ enum gpioId_t {
GNSS_1_NRESET,
GNSS_0_ENABLE,
GNSS_1_ENABLE,
GNSS_SELECT,
GYRO_0_ENABLE,
GYRO_2_ENABLE,

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 140 translations.
* @details
* Generated on: 2022-01-17 15:35:58
* Generated on: 2022-02-03 17:30:40
*/
#include "translateEvents.h"
@ -34,6 +34,7 @@ const char *DEVICE_UNREQUESTED_REPLY_STRING = "DEVICE_UNREQUESTED_REPLY";
const char *INVALID_DEVICE_COMMAND_STRING = "INVALID_DEVICE_COMMAND";
const char *MONITORING_LIMIT_EXCEEDED_STRING = "MONITORING_LIMIT_EXCEEDED";
const char *MONITORING_AMBIGUOUS_STRING = "MONITORING_AMBIGUOUS";
const char *DEVICE_WANTS_HARD_REBOOT_STRING = "DEVICE_WANTS_HARD_REBOOT";
const char *FUSE_CURRENT_HIGH_STRING = "FUSE_CURRENT_HIGH";
const char *FUSE_WENT_OFF_STRING = "FUSE_WENT_OFF";
const char *POWER_ABOVE_HIGH_LIMIT_STRING = "POWER_ABOVE_HIGH_LIMIT";
@ -59,7 +60,6 @@ const char *MONITOR_CHANGED_STATE_STRING = "MONITOR_CHANGED_STATE";
const char *VALUE_BELOW_LOW_LIMIT_STRING = "VALUE_BELOW_LOW_LIMIT";
const char *VALUE_ABOVE_HIGH_LIMIT_STRING = "VALUE_ABOVE_HIGH_LIMIT";
const char *VALUE_OUT_OF_RANGE_STRING = "VALUE_OUT_OF_RANGE";
const char *SWITCHING_TM_FAILED_STRING = "SWITCHING_TM_FAILED";
const char *CHANGING_MODE_STRING = "CHANGING_MODE";
const char *MODE_INFO_STRING = "MODE_INFO";
const char *FALLBACK_FAILED_STRING = "FALLBACK_FAILED";
@ -206,6 +206,8 @@ const char *translateEvents(Event event) {
return MONITORING_LIMIT_EXCEEDED_STRING;
case (2810):
return MONITORING_AMBIGUOUS_STRING;
case (2811):
return DEVICE_WANTS_HARD_REBOOT_STRING;
case (4201):
return FUSE_CURRENT_HIGH_STRING;
case (4202):
@ -256,8 +258,6 @@ const char *translateEvents(Event event) {
return VALUE_ABOVE_HIGH_LIMIT_STRING;
case (7204):
return VALUE_OUT_OF_RANGE_STRING;
case (7301):
return SWITCHING_TM_FAILED_STRING;
case (7400):
return CHANGING_MODE_STRING;
case (7401):

View File

@ -62,6 +62,7 @@ enum sourceObjects : uint32_t {
LIBGPIOD_TEST = 0x54123456,
SPI_TEST = 0x54000010,
UART_TEST = 0x54000020,
I2C_TEST = 0x54000030,
DUMMY_INTERFACE = 0x5400CAFE,
DUMMY_HANDLER = 0x5400AFFE,
P60DOCK_TEST_TASK = 0x00005060,

View File

@ -1,8 +1,8 @@
/**
* @brief Auto-generated object translation file.
* @details
* Contains 113 translations.
* Generated on: 2022-01-17 15:36:10
* Contains 110 translations.
* Generated on: 2022-02-03 12:01:36
*/
#include "translateObjects.h"
@ -36,14 +36,14 @@ const char *MGM_3_RM3100_HANDLER_STRING = "MGM_3_RM3100_HANDLER";
const char *GYRO_3_L3G_HANDLER_STRING = "GYRO_3_L3G_HANDLER";
const char *RW4_STRING = "RW4";
const char *STAR_TRACKER_STRING = "STAR_TRACKER";
const char *GPS0_HANDLER_STRING = "GPS0_HANDLER";
const char *GPS1_HANDLER_STRING = "GPS1_HANDLER";
const char *GPS_CONTROLLER_STRING = "GPS_CONTROLLER";
const char *IMTQ_HANDLER_STRING = "IMTQ_HANDLER";
const char *PCDU_HANDLER_STRING = "PCDU_HANDLER";
const char *P60DOCK_HANDLER_STRING = "P60DOCK_HANDLER";
const char *PDU1_HANDLER_STRING = "PDU1_HANDLER";
const char *PDU2_HANDLER_STRING = "PDU2_HANDLER";
const char *ACU_HANDLER_STRING = "ACU_HANDLER";
const char *BPX_BATT_HANDLER_STRING = "BPX_BATT_HANDLER";
const char *RAD_SENSOR_STRING = "RAD_SENSOR";
const char *PLOC_UPDATER_STRING = "PLOC_UPDATER";
const char *PLOC_MEMORY_DUMPER_STRING = "PLOC_MEMORY_DUMPER";
@ -83,10 +83,6 @@ const char *TMTC_BRIDGE_STRING = "TMTC_BRIDGE";
const char *TMTC_POLLING_TASK_STRING = "TMTC_POLLING_TASK";
const char *FILE_SYSTEM_HANDLER_STRING = "FILE_SYSTEM_HANDLER";
const char *PTME_STRING = "PTME";
const char *PAPB_VC0_STRING = "PAPB_VC0";
const char *PAPB_VC1_STRING = "PAPB_VC1";
const char *PAPB_VC2_STRING = "PAPB_VC2";
const char *PAPB_VC3_STRING = "PAPB_VC3";
const char *PDEC_HANDLER_STRING = "PDEC_HANDLER";
const char *CCSDS_HANDLER_STRING = "CCSDS_HANDLER";
const char *PUS_SERVICE_6_STRING = "PUS_SERVICE_6";
@ -101,6 +97,7 @@ const char *PUS_SERVICE_17_TEST_STRING = "PUS_SERVICE_17_TEST";
const char *PUS_SERVICE_20_PARAMETERS_STRING = "PUS_SERVICE_20_PARAMETERS";
const char *PUS_SERVICE_200_MODE_MGMT_STRING = "PUS_SERVICE_200_MODE_MGMT";
const char *PUS_SERVICE_201_HEALTH_STRING = "PUS_SERVICE_201_HEALTH";
const char *CFDP_PACKET_DISTRIBUTOR_STRING = "CFDP_PACKET_DISTRIBUTOR";
const char *HEALTH_TABLE_STRING = "HEALTH_TABLE";
const char *MODE_STORE_STRING = "MODE_STORE";
const char *EVENT_MANAGER_STRING = "EVENT_MANAGER";
@ -183,9 +180,7 @@ const char *translateObject(object_id_t object) {
case 0x44130001:
return STAR_TRACKER_STRING;
case 0x44130045:
return GPS0_HANDLER_STRING;
case 0x44130146:
return GPS1_HANDLER_STRING;
return GPS_CONTROLLER_STRING;
case 0x44140014:
return IMTQ_HANDLER_STRING;
case 0x442000A1:
@ -198,6 +193,8 @@ const char *translateObject(object_id_t object) {
return PDU2_HANDLER_STRING;
case 0x44250003:
return ACU_HANDLER_STRING;
case 0x44260000:
return BPX_BATT_HANDLER_STRING;
case 0x443200A5:
return RAD_SENSOR_STRING;
case 0x44330000:
@ -277,14 +274,6 @@ const char *translateObject(object_id_t object) {
case 0x50000600:
return PTME_STRING;
case 0x50000700:
return PAPB_VC0_STRING;
case 0x50000701:
return PAPB_VC1_STRING;
case 0x50000702:
return PAPB_VC2_STRING;
case 0x50000703:
return PAPB_VC3_STRING;
case 0x50000704:
return PDEC_HANDLER_STRING;
case 0x50000800:
return CCSDS_HANDLER_STRING;
@ -312,6 +301,8 @@ const char *translateObject(object_id_t object) {
return PUS_SERVICE_200_MODE_MGMT_STRING;
case 0x53000201:
return PUS_SERVICE_201_HEALTH_STRING;
case 0x53001000:
return CFDP_PACKET_DISTRIBUTOR_STRING;
case 0x53010000:
return HEALTH_TABLE_STRING;
case 0x53010100:

View File

@ -525,6 +525,13 @@ ReturnValue_t pst::pstI2c(FixedTimeslotTaskIF *thisSequence) {
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ);
#endif
#if OBSW_ADD_BPX_BATTERY_HANDLER == 1
thisSequence->addSlot(objects::BPX_BATT_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION);
thisSequence->addSlot(objects::BPX_BATT_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE);
thisSequence->addSlot(objects::BPX_BATT_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE);
thisSequence->addSlot(objects::BPX_BATT_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ);
thisSequence->addSlot(objects::BPX_BATT_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ);
#endif
if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) {
sif::error << "I2C PST initialization failed" << std::endl;

119
linux/obc/AxiPtmeConfig.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "AxiPtmeConfig.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw_hal/linux/uio/UioMapper.h"
AxiPtmeConfig::AxiPtmeConfig(object_id_t objectId, std::string axiUio, int mapNum)
: SystemObject(objectId), axiUio(axiUio), mapNum(mapNum) {
mutex = MutexFactory::instance()->createMutex();
if (mutex == nullptr) {
sif::warning << "Failed to create mutex" << std::endl;
}
}
AxiPtmeConfig::~AxiPtmeConfig() {}
ReturnValue_t AxiPtmeConfig::initialize() {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
UioMapper uioMapper(axiUio, mapNum);
result = uioMapper.getMappedAdress(&baseAddress, UioMapper::Permissions::READ_WRITE);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::writeCaduRateReg(uint8_t rateVal) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
result = mutex->lockMutex(timeoutType, mutexTimeout);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::writeCaduRateReg: Failed to lock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*(baseAddress + CADU_BITRATE_REG) = static_cast<uint32_t>(rateVal);
result = mutex->unlockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::writeCaduRateReg: Failed to unlock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::enableTxclockManipulator() {
ReturnValue_t result = writeBit(COMMON_CONFIG_REG, true, BitPos::EN_TX_CLK_MANIPULATOR);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::disableTxclockManipulator() {
ReturnValue_t result = writeBit(COMMON_CONFIG_REG, false, BitPos::EN_TX_CLK_MANIPULATOR);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::enableTxclockInversion() {
ReturnValue_t result = writeBit(COMMON_CONFIG_REG, true, BitPos::INVERT_CLOCK);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::disableTxclockInversion() {
ReturnValue_t result = writeBit(COMMON_CONFIG_REG, false, BitPos::INVERT_CLOCK);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::writeReg(uint32_t regOffset, uint32_t writeVal) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
result = mutex->lockMutex(timeoutType, mutexTimeout);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::readReg: Failed to lock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*(baseAddress + regOffset / ADRESS_DIVIDER) = writeVal;
result = mutex->unlockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::readReg: Failed to unlock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::readReg(uint32_t regOffset, uint32_t* readVal) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
result = mutex->lockMutex(timeoutType, mutexTimeout);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::readReg: Failed to lock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*readVal = *(baseAddress + regOffset / ADRESS_DIVIDER);
result = mutex->unlockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "AxiPtmeConfig::readReg: Failed to unlock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t AxiPtmeConfig::writeBit(uint32_t regOffset, bool bitVal, BitPos bitPos) {
uint32_t readVal = 0;
ReturnValue_t result = readReg(regOffset, &readVal);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
uint32_t writeVal =
(readVal & ~(1 << static_cast<uint32_t>(bitPos))) | bitVal << static_cast<uint32_t>(bitPos);
result = writeReg(regOffset, writeVal);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}

99
linux/obc/AxiPtmeConfig.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef LINUX_OBC_AXIPTMECONFIG_H_
#define LINUX_OBC_AXIPTMECONFIG_H_
#include <string>
#include "fsfw/ipc/MutexIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief Class providing low level access to the configuration interface of the PTME.
*
* @author J. Meier
*/
class AxiPtmeConfig : public SystemObject {
public:
/**
* @brief Constructor
* @param axiUio Device file of UIO belonging to the AXI configuration interface.
* @param mapNum Number of map belonging to axi configuration interface.
*/
AxiPtmeConfig(object_id_t objectId, std::string axiUio, int mapNum);
virtual ~AxiPtmeConfig();
virtual ReturnValue_t initialize() override;
/**
* @brief Will write to the bitrate configuration register. Actual generated rate depends on
* frequency of the clock connected to the bit clock input of PTME.
*/
ReturnValue_t writeCaduRateReg(uint8_t rateVal);
/**
* @brief Next to functions control the tx clock manipulator component
*
* @details If the tx clock manipulator is enabled the output clock of the PTME is manipulated
* in a way that both high and low periods in the clock signal have equal lengths.
* The default implementation of the PTME generates a clock where the high level is
* only one bit clock period long. This might be too short to match the setup and hold
* times of the S-and transceiver.
*/
ReturnValue_t enableTxclockManipulator();
ReturnValue_t disableTxclockManipulator();
/**
* @brief The next to functions control whether data will be updated on the rising or falling edge
* of the tx clock.
* Enable inversion will update data on falling edge (not the configuration required by the
* syrlinks)
* Disable clock inversion. Data updated on rising edge.
*/
ReturnValue_t enableTxclockInversion();
ReturnValue_t disableTxclockInversion();
private:
// Address of register storing the bitrate configuration parameter
static const uint32_t CADU_BITRATE_REG = 0x0;
// Address to register storing common configuration parameters
static const uint32_t COMMON_CONFIG_REG = 0x4;
static const uint32_t ADRESS_DIVIDER = 4;
enum class BitPos : uint32_t { EN_TX_CLK_MANIPULATOR, INVERT_CLOCK };
std::string axiUio;
std::string uioMap;
int mapNum = 0;
MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeout = 20;
uint32_t* baseAddress = nullptr;
/**
* @brief Function to write to configuration registers
*
* @param writeVal Value to write
*/
ReturnValue_t writeReg(uint32_t regOffset, uint32_t writeVal);
/**
* @brief Reads value from configuration register
*
* @param regOffset Offset of register from base address to read from
* Qparam readVal Pointer to variable where read value will be written to
*/
ReturnValue_t readReg(uint32_t regOffset, uint32_t* readVal);
/**
* @brief Sets one bit in a register
*
* @param regOffset Offset of the register where to set the bit
* @param bitVal The value of the bit to set (1 or 0)
* @param bitPos The position of the bit within the register to set
*
* @return RETURN_OK if successful, otherwise RETURN_FAILED
*/
ReturnValue_t writeBit(uint32_t regOffset, bool bitVal, BitPos bitPos);
};
#endif /* LINUX_OBC_AXIPTMECONFIG_H_ */

View File

@ -3,8 +3,8 @@ target_sources(${OBSW_NAME} PUBLIC
Ptme.cpp
PdecHandler.cpp
PdecConfig.cpp
PtmeRateSetter.cpp
PtmeAxiConfig.cpp
PtmeConfig.cpp
AxiPtmeConfig.cpp
)

View File

@ -1,40 +0,0 @@
#include "PtmeAxiConfig.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw_hal/linux/uio/UioMapper.h"
PtmeAxiConfig::PtmeAxiConfig(object_id_t objectId, std::string configAxiUio, int mapNum)
: SystemObject(objectId), configAxiUio(configAxiUio), mapNum(mapNum) {
mutex = MutexFactory::instance()->createMutex();
if (mutex == nullptr) {
sif::warning << "Failed to create mutex" << std::endl;
}
}
PtmeAxiConfig::~PtmeAxiConfig() {}
ReturnValue_t PtmeAxiConfig::initialize() {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
UioMapper uioMapper(configAxiUio, mapNum);
result = uioMapper.getMappedAdress(&baseAddress, UioMapper::Permissions::READ_WRITE);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PtmeAxiConfig::writeCaduRateReg(uint8_t rateVal) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
result = mutex->lockMutex(timeoutType, mutexTimeout);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "PtmeAxiConfig::writeCaduRateReg: Failed to lock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*(baseAddress + CADU_BITRATE_REG) = static_cast<uint32_t>(rateVal);
result = mutex->unlockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "PtmeAxiConfig::writeCaduRateReg: Failed to unlock mutex" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,42 +0,0 @@
#ifndef LINUX_OBC_PTMEAXICONFIG_H_
#define LINUX_OBC_PTMEAXICONFIG_H_
#include <string>
#include "fsfw/ipc/MutexIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief Class providing low level access to the configuration interface of the PTME.
*
* @author J. Meier
*/
class PtmeAxiConfig : public SystemObject {
public:
/**
* @brief Constructor
* @param configAxiUio Device file of UIO belonging to the AXI configuration interface.
* @param mapNum Number of map belonging to axi configuration interface.
*/
PtmeAxiConfig(object_id_t objectId, std::string configAxiUio, int mapNum);
virtual ~PtmeAxiConfig();
virtual ReturnValue_t initialize() override;
ReturnValue_t writeCaduRateReg(uint8_t rateVal);
private:
// Address of register storing the bitrate configuration parameter
static const uint32_t CADU_BITRATE_REG = 0x0;
std::string configAxiUio;
std::string uioMap;
int mapNum = 0;
MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeout = 20;
uint32_t* baseAddress = nullptr;
};
#endif /* LINUX_OBC_PTMEAXICONFIG_H_ */

50
linux/obc/PtmeConfig.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "PtmeConfig.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
PtmeConfig::PtmeConfig(object_id_t objectId, AxiPtmeConfig* axiPtmeConfig)
: SystemObject(objectId), axiPtmeConfig(axiPtmeConfig) {}
PtmeConfig::~PtmeConfig() {}
ReturnValue_t PtmeConfig::initialize() {
if (axiPtmeConfig == nullptr) {
sif::warning << "PtmeConfig::initialize: Invalid AxiPtmeConfig object" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t PtmeConfig::setRate(uint32_t bitRate) {
if (bitRate == 0) {
return BAD_BIT_RATE;
}
uint32_t rateVal = BIT_CLK_FREQ / bitRate - 1;
if (rateVal > 0xFF) {
return RATE_NOT_SUPPORTED;
}
return axiPtmeConfig->writeCaduRateReg(static_cast<uint8_t>(rateVal));
}
ReturnValue_t PtmeConfig::invertTxClock(bool invert) {
ReturnValue_t result = RETURN_OK;
if (invert) {
result = axiPtmeConfig->enableTxclockInversion();
} else {
result = axiPtmeConfig->disableTxclockInversion();
}
if (result != RETURN_OK) {
return CLK_INVERSION_FAILED;
}
return result;
}
ReturnValue_t PtmeConfig::configTxManipulator(bool enable) {
ReturnValue_t result = RETURN_OK;
if (enable) {
result = axiPtmeConfig->enableTxclockManipulator();
} else {
result = axiPtmeConfig->disableTxclockManipulator();
}
return result;
}

View File

@ -1,32 +1,76 @@
#ifndef LINUX_OBC_PTMECONFIG_H_
#define LINUX_OBC_PTMECONFIG_H_
#include <cstring>
#include "OBSWConfig.h"
#include "AxiPtmeConfig.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "linux/obc/PtmeConfig.h"
/**
* @brief PTME specific configuration parameters derived from FPGA design and device tree.
* @brief Class to configure donwlink specific parameters in the PTME IP core.
*
* @author J. Meier
*/
namespace PtmeConfig {
/**
* Offset of virtual channels mapped into address space
* 0x10000 = (0x4000 * 4)
*/
static const uint32_t VC0_OFFSETT = 0;
static const uint32_t VC1_OFFSETT = 0x4000;
static const uint32_t VC2_OFFSETT = 0x8000;
static const uint32_t VC3_OFFSETT = 0xC000;
#if BOARD_TE0720 == 0
static const char UIO_DEVICE_FILE[] = "/dev/uio1";
#else
static const char UIO_DEVICE_FILE[] = "/dev/uio1";
#endif
// Bit clock frequency of PMTE IP core in Hz
static const uint32_t BIT_CLK_FREQ = 20000000;
}; // namespace PtmeConfig
class PtmeConfig : public SystemObject, public HasReturnvaluesIF {
public:
/**
* @brief Constructor
*
* ptmeAxiConfig Pointer to object providing access to PTME configuration registers.
*/
PtmeConfig(object_id_t opbjectId, AxiPtmeConfig* axiPtmeConfig);
virtual ~PtmeConfig();
virtual ReturnValue_t initialize() override;
/**
* @brief Changes the input frequency to the S-Band transceiver and thus the downlink rate
*
* @details This is the bitrate of the CADU clock and not the downlink which has twice the bitrate
* of the CADU clock due to the convolutional code added by the s-Band transceiver.
*/
ReturnValue_t setRate(uint32_t bitRate);
/**
* @brief Will change the time the tx data signal is updated with respect to the tx clock
*
* @param invert True -> Data signal will be updated on the falling edge (not desired by the
* Syrlinks)
* False -> Data signal updated on rising edge (default configuration and desired
* by the syrlinks)
*
* @return REUTRN_OK if successful, otherwise error return value
*/
ReturnValue_t invertTxClock(bool invert);
/**
* @brief Controls the tx clock manipulator of the PTME wrapper component
*
* @param enable Manipulator will be enabled (this is also the default configuration)
* @param disable Manipulator will be disabled
*
* @return REUTRN_OK if successful, otherwise error return value
*/
ReturnValue_t configTxManipulator(bool enable);
private:
static const uint8_t INTERFACE_ID = CLASS_ID::RATE_SETTER;
//! [EXPORT] : [COMMENT] The commanded rate is not supported by the current FPGA design
static const ReturnValue_t RATE_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Bad bitrate has been commanded (e.g. 0)
static const ReturnValue_t BAD_BIT_RATE = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Failed to invert clock and thus change the time the data is updated with
//! respect to the tx clock
static const ReturnValue_t CLK_INVERSION_FAILED = MAKE_RETURN_CODE(0xA2);
//! [EXPORT] : [COMMENT] Failed to change configuration bit of tx clock manipulator
static const ReturnValue_t TX_MANIPULATOR_CONFIG_FAILED = MAKE_RETURN_CODE(0xA3);
// Bitrate register field is only 8 bit wide
static const uint32_t MAX_BITRATE = 0xFF;
// Bit clock frequency of PMTE IP core in Hz
static const uint32_t BIT_CLK_FREQ = 20000000;
AxiPtmeConfig* axiPtmeConfig = nullptr;
};
#endif /* LINUX_OBC_PTMECONFIG_H_ */

View File

@ -1,27 +0,0 @@
#include "PtmeRateSetter.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
PtmeRateSetter::PtmeRateSetter(object_id_t objectId, PtmeAxiConfig* ptmeAxiConfig)
: SystemObject(objectId), ptmeAxiConfig(ptmeAxiConfig) {}
PtmeRateSetter::~PtmeRateSetter() {}
ReturnValue_t PtmeRateSetter::initialize() {
if (ptmeAxiConfig == nullptr) {
sif::warning << "PtmeRateSetter::initialize: Invalid PtmeAxiConfig object" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PtmeRateSetter::setRate(uint32_t bitRate) {
if (bitRate == 0) {
return BAD_BIT_RATE;
}
uint32_t rateVal = PtmeConfig::BIT_CLK_FREQ / bitRate - 1;
if (rateVal > 0xFF) {
return RATE_NOT_SUPPORTED;
}
return ptmeAxiConfig->writeCaduRateReg(static_cast<uint8_t>(rateVal));
}

View File

@ -1,47 +0,0 @@
#ifndef LINUX_OBC_PTMERATESETTER_H_
#define LINUX_OBC_PTMERATESETTER_H_
#include "TxRateSetterIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "linux/obc/PtmeAxiConfig.h"
#include "linux/obc/PtmeConfig.h"
/**
* @brief Class to set the downlink bit rate by writing to the AXI configuration interface of the
* PTME IP core.
*
* @details This is the bitrate of the CADU clock and not the downlink which has twice the bitrate
* of the CADU clock due to the convolutional code added by the s-Band transceiver.
*
* @author J. Meier
*/
class PtmeRateSetter : public TxRateSetterIF, public SystemObject, public HasReturnvaluesIF {
public:
/**
* @brief Constructor
*
* objectId Object id of system object
* ptmeAxiConfig Pointer to object providing access to PTME configuration registers.
*/
PtmeRateSetter(object_id_t objectId, PtmeAxiConfig* ptmeAxiConfig);
virtual ~PtmeRateSetter();
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t setRate(uint32_t bitRate);
private:
static const uint8_t INTERFACE_ID = CLASS_ID::RATE_SETTER;
//! [EXPORT] : [COMMENT] The commanded rate is not supported by the current FPGA design
static const ReturnValue_t RATE_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Bad bitrate has been commanded (e.g. 0)
static const ReturnValue_t BAD_BIT_RATE = MAKE_RETURN_CODE(0xA1);
// Bitrate register field is only 8 bit wide
static const uint32_t MAX_BITRATE = 0xFF;
PtmeAxiConfig* ptmeAxiConfig = nullptr;
};
#endif /* LINUX_OBC_PTMERATESETTER_H_ */

View File

@ -1,20 +0,0 @@
#ifndef LINUX_OBC_TXRATESETTERIF_H_
#define LINUX_OBC_TXRATESETTERIF_H_
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief Abstract class for objects implementing the functionality to switch the
* downlink bit rate.
*
* @author J. Meier
*/
class TxRateSetterIF {
public:
TxRateSetterIF(){};
virtual ~TxRateSetterIF(){};
virtual ReturnValue_t setRate(uint32_t bitRate) = 0;
};
#endif /* LINUX_OBC_TXRATESETTERIF_H_ */