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
Some checks failed
EIVE/eive-obsw/pipeline/pr-develop There was a failure building this commit
This commit is contained in:
@ -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)
|
||||
|
7
linux/devices/ScexDleParser.cpp
Normal file
7
linux/devices/ScexDleParser.cpp
Normal 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(){};
|
13
linux/devices/ScexDleParser.h
Normal file
13
linux/devices/ScexDleParser.h
Normal 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:
|
||||
};
|
86
linux/devices/ScexHelper.cpp
Normal file
86
linux/devices/ScexHelper.cpp
Normal 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;
|
||||
}
|
46
linux/devices/ScexHelper.h
Normal file
46
linux/devices/ScexHelper.h
Normal 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_ */
|
236
linux/devices/ScexUartReader.cpp
Normal file
236
linux/devices/ScexUartReader.cpp
Normal 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;
|
||||
}
|
61
linux/devices/ScexUartReader.h
Normal file
61
linux/devices/ScexUartReader.h
Normal 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;
|
||||
};
|
Reference in New Issue
Block a user