Merge remote-tracking branch 'origin/develop' into mueller/acs-ss-init
Some checks failed
EIVE/eive-obsw/pipeline/pr-develop There was a failure building this commit

This commit is contained in:
2022-10-10 17:39:47 +02:00
59 changed files with 1562 additions and 171 deletions

View File

@ -2,7 +2,9 @@ if(EIVE_BUILD_GPSD_GPS_HANDLER)
target_sources(${OBSW_NAME} PRIVATE GPSHyperionLinuxController.cpp)
endif()
target_sources(${OBSW_NAME} PRIVATE Max31865RtdLowlevelHandler.cpp)
target_sources(
${OBSW_NAME} PRIVATE Max31865RtdLowlevelHandler.cpp ScexUartReader.cpp
ScexDleParser.cpp ScexHelper.cpp)
add_subdirectory(ploc)
add_subdirectory(startracker)

View File

@ -0,0 +1,7 @@
#include "ScexDleParser.h"
ScexDleParser::ScexDleParser(SimpleRingBuffer &decodeRingBuf, DleEncoder &decoder,
BufPair encodedBuf, BufPair decodedBuf)
: DleParser(decodeRingBuf, decoder, encodedBuf, decodedBuf){};
ScexDleParser::~ScexDleParser(){};

View File

@ -0,0 +1,13 @@
#pragma once
#include <fsfw/globalfunctions/DleParser.h>
class ScexDleParser : public DleParser {
public:
ScexDleParser(SimpleRingBuffer &decodeRingBuf, DleEncoder &decoder, BufPair encodedBuf,
BufPair decodedBuf);
virtual ~ScexDleParser();
private:
};

View File

@ -0,0 +1,86 @@
#include "ScexHelper.h"
#include <fsfw/globalfunctions/CRC.h>
#include "fsfw/serviceinterface.h"
using namespace returnvalue;
ScexHelper::ScexHelper() {}
ReturnValue_t ScexHelper::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
return FAILED;
}
size_t ScexHelper::getSerializedSize() const { return totalPacketLen; }
ReturnValue_t ScexHelper::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
if (buffer == nullptr or size == nullptr) {
return FAILED;
}
if (*size < 7) {
return STREAM_TOO_SHORT;
}
start = *buffer;
cmdByteRaw = **buffer;
cmd = static_cast<scex::Cmds>((cmdByteRaw >> 1) & 0b11111);
*buffer += 1;
packetCounter = **buffer;
*buffer += 1;
totalPacketCounter = **buffer;
*buffer += 1;
payloadLen = (**buffer << 8) | *(*buffer + 1);
*buffer += 2;
payloadStart = *buffer;
totalPacketLen = payloadLen + scex::HEADER_LEN + scex::CRC_LEN;
if (totalPacketLen >= *size) {
return STREAM_TOO_SHORT;
}
*buffer += payloadLen;
crc = (**buffer << 8) | *(*buffer + 1);
if (CRC::crc16ccitt(start, totalPacketLen) != 0) {
return INVALID_CRC;
}
return OK;
}
scex::Cmds ScexHelper::getCmd() const { return cmd; }
uint8_t ScexHelper::getCmdByteRaw() const { return cmdByteRaw; }
uint16_t ScexHelper::getCrc() const { return crc; }
size_t ScexHelper::getExpectedPacketLen() const { return totalPacketLen; }
uint8_t ScexHelper::getPacketCounter() const { return packetCounter; }
uint16_t ScexHelper::getPayloadLen() const { return payloadLen; }
const uint8_t* ScexHelper::getStart() const { return start; }
uint8_t ScexHelper::getTotalPacketCounter() const { return totalPacketCounter; }
std::ostream& operator<<(std::ostream& os, const ScexHelper& h) {
using namespace std;
sif::info << "Command Byte Raw: 0x" << std::setw(2) << std::setfill('0') << std::hex
<< (int)h.cmdByteRaw << " | Command: 0x" << std::setw(2) << std::setfill('0')
<< std::hex << static_cast<int>(h.cmd) << std::dec << std::endl;
sif::info << "PacketCounter: " << h.packetCounter << endl;
sif::info << "TotalPacketCount: " << h.totalPacketCounter << endl;
sif::info << "PayloadLength: " << h.payloadLen << endl;
sif::info << "TotalPacketLength: " << h.totalPacketLen;
return os;
}
std::ofstream& operator<<(std::ofstream& of, const ScexHelper& h) {
of.write(reinterpret_cast<const char*>(h.start), h.getSerializedSize());
return of;
}

View File

@ -0,0 +1,46 @@
#ifndef LINUX_DEVICES_SCEXHELPER_H_
#define LINUX_DEVICES_SCEXHELPER_H_
#include <fsfw/serialize/SerializeIF.h>
#include <mission/devices/devicedefinitions/ScexDefinitions.h>
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
class ScexHelper : public SerializeIF {
public:
static const ReturnValue_t INVALID_CRC = returnvalue::makeCode(0, 2);
ScexHelper();
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness = Endianness::BIG) override;
friend std::ostream &operator<<(std::ostream &os, const ScexHelper &h);
friend std::ofstream &operator<<(std::ofstream &os, const ScexHelper &h);
scex::Cmds getCmd() const;
uint8_t getCmdByteRaw() const;
uint16_t getCrc() const;
size_t getExpectedPacketLen() const;
uint8_t getPacketCounter() const;
uint16_t getPayloadLen() const;
const uint8_t *getStart() const;
uint8_t getTotalPacketCounter() const;
private:
const uint8_t *start = nullptr;
uint16_t crc = 0;
uint8_t cmdByteRaw = 0;
scex::Cmds cmd = scex::Cmds::INVALID;
int packetCounter = 0;
int totalPacketCounter = 0;
uint16_t payloadLen = 0;
const uint8_t *payloadStart = 0;
size_t totalPacketLen = 0;
};
#endif /* LINUX_DEVICES_SCEXHELPER_H_ */

View File

@ -0,0 +1,236 @@
#include "ScexUartReader.h"
#include <fcntl.h> // Contains file controls like O_RDWR
#include <fsfw/globalfunctions/arrayprinter.h>
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/tasks/SemaphoreFactory.h>
#include <fsfw/tasks/TaskFactory.h>
#include <fsfw_hal/linux/uart/UartCookie.h>
#include <unistd.h> // write(), read(), close()
#include <cerrno> // Error integer and strerror() function
#include <iostream>
#include "OBSWConfig.h"
using namespace returnvalue;
ScexUartReader::ScexUartReader(object_id_t objectId)
: SystemObject(objectId),
decodeRingBuf(4096, true),
ipcRingBuf(200 * 2048, true),
ipcQueue(200),
dleParser(decodeRingBuf, dleEncoder, {encodedBuf.data(), encodedBuf.size()},
{decodedBuf.data(), decodedBuf.size()}) {
semaphore = SemaphoreFactory::instance()->createBinarySemaphore();
semaphore->acquire();
lock = MutexFactory::instance()->createMutex();
}
ReturnValue_t ScexUartReader::performOperation(uint8_t operationCode) {
lock->lockMutex();
state = States::IDLE;
lock->unlockMutex();
while (true) {
semaphore->acquire();
int bytesRead = 0;
// debugMode = true;
while (true) {
bytesRead = read(serialPort, reinterpret_cast<void *>(recBuf.data()),
static_cast<unsigned int>(recBuf.size()));
if (bytesRead == 0) {
{
MutexGuard mg(lock);
if (state == States::FINISH) {
dleParser.reset();
// Flush received and unread data
tcflush(serialPort, TCIOFLUSH);
state = States::IDLE;
break;
}
}
ReturnValue_t result = returnvalue::OK;
// Can be used to read frame, parity and overrun errors
// serial_icounter_struct icounter{};
// uart::readCountersAndErrors(serialPort, icounter);
while (result != DleParser::NO_PACKET_FOUND) {
result = tryDleParsing();
}
TaskFactory::delayTask(400);
} else if (bytesRead < 0) {
sif::warning << "ScexUartReader::performOperation: read call failed with error [" << errno
<< ", " << strerror(errno) << "]" << std::endl;
break;
} else if (bytesRead >= static_cast<int>(recBuf.size())) {
sif::error << "ScexUartReader::performOperation: Receive buffer too small for " << bytesRead
<< " bytes" << std::endl;
} else if (bytesRead > 0) {
if (debugMode) {
sif::info << "Received " << bytesRead
<< " bytes from the Solar Cell Experiment:" << std::endl;
}
ReturnValue_t result = dleParser.passData(recBuf.data(), bytesRead);
if (result != OK) {
sif::warning << "ScexUartReader::performOperation: Passing data to DLE parser failed"
<< std::endl;
}
result = tryDleParsing();
}
};
}
return OK;
}
ReturnValue_t ScexUartReader::initializeInterface(CookieIF *cookie) {
UartCookie *uartCookie = dynamic_cast<UartCookie *>(cookie);
if (uartCookie == nullptr) {
return FAILED;
}
std::string devname = uartCookie->getDeviceFile();
/* Get file descriptor */
serialPort = open(devname.c_str(), O_RDWR);
if (serialPort < 0) {
sif::warning << "ScexUartReader::initializeInterface: open call failed with error [" << errno
<< ", " << strerror(errno) << std::endl;
return FAILED;
}
// Setting up UART parameters
tty.c_cflag &= ~PARENB; // Clear parity bit
if (uartCookie->getStopBits() == StopBits::TWO_STOP_BITS) {
// Use two stop bits
tty.c_cflag |= CSTOPB;
} else {
// Clear stop field, only one stop bit used in communication
tty.c_cflag &= ~CSTOPB;
}
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, use polling
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 0;
// The SCEX experiment has a fixed baud rate.
if (cfsetispeed(&tty, B38400) != 0) {
sif::warning << "ScexUartReader::initializeInterface: Setting baud rate failed" << std::endl;
}
if (tcsetattr(serialPort, TCSANOW, &tty) != 0) {
sif::warning << "ScexUartReader::initializeInterface: tcsetattr call failed with error ["
<< errno << ", " << strerror(errno) << std::endl;
}
// Flush received and unread data
tcflush(serialPort, TCIOFLUSH);
return OK;
}
ReturnValue_t ScexUartReader::sendMessage(CookieIF *cookie, const uint8_t *sendData,
size_t sendLen) {
ReturnValue_t result;
if (sendData == nullptr or sendLen == 0) {
return FAILED;
}
lock->lockMutex();
if (state == States::NOT_READY or state == States::RUNNING) {
lock->unlockMutex();
return FAILED;
}
tcflush(serialPort, TCIFLUSH);
state = States::RUNNING;
lock->unlockMutex();
result = semaphore->release();
if (result != OK) {
std::cout << "ScexUartReader::sendMessage: Releasing semaphore failed" << std::endl;
}
size_t encodedLen = 0;
result = dleEncoder.encode(sendData, sendLen, cmdbuf.data(), cmdbuf.size(), &encodedLen, true);
if (result != OK) {
sif::warning << "ScexUartReader::sendMessage: Encoding failed" << std::endl;
return FAILED;
}
size_t bytesWritten = write(serialPort, cmdbuf.data(), encodedLen);
if (bytesWritten != encodedLen) {
sif::warning << "ScexUartReader::sendMessage: Sending ping command to solar experiment failed"
<< std::endl;
return FAILED;
}
return OK;
}
ReturnValue_t ScexUartReader::getSendSuccess(CookieIF *cookie) { return OK; }
ReturnValue_t ScexUartReader::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
return OK;
}
void ScexUartReader::setDebugMode(bool enable) { this->debugMode = enable; }
ReturnValue_t ScexUartReader::finish() {
MutexGuard mg(lock);
if (state == States::IDLE) {
return FAILED;
}
state = States::FINISH;
return OK;
}
void ScexUartReader::handleFoundDlePacket(uint8_t *packet, size_t len) {
MutexGuard mg(lock);
ReturnValue_t result = ipcQueue.insert(len);
if (result != OK) {
sif::warning << "ScexUartReader::handleFoundDlePacket: IPCQueue error" << std::endl;
}
result = ipcRingBuf.writeData(packet, len);
if (result != OK) {
sif::warning << "ScexUartReader::handleFoundDlePacket: IPCRingBuf error" << std::endl;
}
}
ReturnValue_t ScexUartReader::tryDleParsing() {
size_t bytesRead = 0;
ReturnValue_t result = dleParser.parseRingBuf(bytesRead);
if (result == returnvalue::OK) {
// Packet found, advance read pointer.
auto &decodedPacket = dleParser.getContext().decodedPacket;
handleFoundDlePacket(decodedPacket.first, decodedPacket.second);
dleParser.confirmBytesRead(bytesRead);
} else if (result != DleParser::NO_PACKET_FOUND) {
sif::warning << "ScexUartReader::performOperation: Possible packet loss" << std::endl;
// Markers found at wrong place
// which might be a hint for a possibly lost packet.
dleParser.defaultErrorHandler();
dleParser.confirmBytesRead(bytesRead);
}
return result;
}
void ScexUartReader::reset() {
lock->lockMutex();
state = States::FINISH;
lock->unlockMutex();
}
ReturnValue_t ScexUartReader::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
size_t *size) {
MutexGuard mg(lock);
if (ipcQueue.empty()) {
*size = 0;
return OK;
}
ipcQueue.retrieve(size);
*buffer = ipcBuffer.data();
ReturnValue_t result = ipcRingBuf.readData(ipcBuffer.data(), *size, true);
if (result != OK) {
sif::warning << "ScexUartReader::readReceivedMessage: Reading RingBuffer failed" << std::endl;
}
return OK;
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <fsfw/container/DynamicFIFO.h>
#include <fsfw/container/SimpleRingBuffer.h>
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
#include <fsfw/globalfunctions/DleEncoder.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <linux/devices/ScexDleParser.h>
#include <termios.h> // Contains POSIX terminal control definitions
class SemaphoreIF;
class MutexIF;
class ScexUartReader : public SystemObject,
public ExecutableObjectIF,
public DeviceCommunicationIF {
friend class UartTestClass;
public:
enum class States { NOT_READY, IDLE, RUNNING, FINISH };
ScexUartReader(object_id_t objectId);
void reset();
ReturnValue_t finish();
void setDebugMode(bool enable);
private:
SemaphoreIF *semaphore;
bool debugMode = false;
MutexIF *lock;
int serialPort = 0;
States state = States::IDLE;
struct termios tty = {};
bool doFinish = false;
DleEncoder dleEncoder = DleEncoder();
SimpleRingBuffer decodeRingBuf;
std::array<uint8_t, 256> cmdbuf = {};
std::array<uint8_t, 4096> recBuf = {};
std::array<uint8_t, 4096> encodedBuf = {};
std::array<uint8_t, 4096> decodedBuf = {};
std::array<uint8_t, 4096> ipcBuffer = {};
SimpleRingBuffer ipcRingBuf;
DynamicFIFO<size_t> ipcQueue;
ScexDleParser dleParser;
static void foundDlePacketHandler(const DleParser::Context &ctx);
void handleFoundDlePacket(uint8_t *packet, size_t len);
ReturnValue_t tryDleParsing();
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
// DeviceCommunicationIF implementation
ReturnValue_t initializeInterface(CookieIF *cookie) override;
ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) override;
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override;
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override;
};