Compare commits

...

25 Commits

Author SHA1 Message Date
07e8f95a31 of course something else was missing
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good
2023-04-16 12:05:41 +02:00
babea226ab thats an annoying patch release
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good
2023-04-16 11:54:27 +02:00
8c24a7310d Merge pull request 'update CHANGELOG and CMakeLists.txt' (#606) from prep_final_v2.0.0 into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good
Reviewed-on: #606
2023-04-16 11:49:05 +02:00
8f5982fd72 added additional note
Some checks are pending
EIVE/eive-obsw/pipeline/pr-develop Build queued...
2023-04-16 11:48:24 +02:00
611a2c0b45 update CHANGELOG and CMakeLists.txt
Some checks are pending
EIVE/eive-obsw/pipeline/head Build started...
EIVE/eive-obsw/pipeline/pr-develop Build started...
2023-04-16 11:41:30 +02:00
61e6b09704 Merge pull request 'Update sagittactl to v10.7' (#605) from update_sagittactl_v10.7 into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good
Reviewed-on: #605
2023-04-16 11:25:38 +02:00
a9a0266a84 Merge branch 'develop' into update_sagittactl_v10.7
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-16 11:01:19 +02:00
b7e6315be7 bump sagittactl to concrete version
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-16 10:58:25 +02:00
740275f57a normal mode now works as well
Some checks failed
EIVE/eive-obsw/pipeline/pr-develop There was a failure building this commit
2023-04-16 04:04:57 +02:00
58dd53def8 bump sagittactl 2023-04-16 03:54:10 +02:00
ddbe30f832 afmt 2023-04-16 03:52:45 +02:00
680d496b28 STR seems to work well now 2023-04-16 03:52:10 +02:00
9c163419b2 Merge pull request 'FS helpers' (#604) from core_ctrl_fs_helpers into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good
Reviewed-on: #604
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-04-16 02:57:16 +02:00
f4fedd20c9 added more bugfixes for list dir dump
Some checks are pending
EIVE/eive-obsw/pipeline/pr-develop Build started...
2023-04-16 02:56:46 +02:00
016fab105e bump tmtc
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 23:13:04 +02:00
767a0eda30 hopefully last bugfix
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 23:11:00 +02:00
f2c71d962a done soon
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 23:00:34 +02:00
7bf880a29f use gzip directly
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 22:17:50 +02:00
0185691dba add more context info for dumped dir listing
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 20:51:46 +02:00
9997aa5470 bump sagittactl 2023-04-15 20:16:32 +02:00
c1ccfe66eb this compiles with warnings
Some checks are pending
EIVE/eive-obsw/pipeline/head Build started...
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 15:17:22 +02:00
ae9f43c707 adaptions for new sagittalib
Some checks failed
EIVE/eive-obsw/pipeline/head There was a failure building this commit
2023-04-15 15:15:06 +02:00
143002de48 some improvements
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 13:06:16 +02:00
d439aedee7 bugfix
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 13:03:44 +02:00
b8d010cd39 CHANGELOG + FS helpers
Some checks are pending
EIVE/eive-obsw/pipeline/head Build queued...
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
2023-04-15 13:01:41 +02:00
12 changed files with 511 additions and 94 deletions

View File

@ -16,6 +16,36 @@ will consitute of a breaking change warranting a new major release:
# [unreleased] # [unreleased]
# [v2.0.2] 2023-04-16
- Bump patch version to 2.
# [v2.0.1] 2023-04-16
- eive-tmtc: v3.1.0
# [v2.0.0] 2023-04-16
This is the version which will fly on the satellite for the initial launch phase.
- q7s-package: v2.5.0
- eive-tmtc: v3.0.0
- `wire` library is now on version v10.7 as well.
## Added
- Added `mv`, `cp` and `rm` action helpers for the core controller for common filesystem operations.
- Extended directory listing helpers. There is now a directory listing helper which dumps the
directory listing as an action data reply immediately. For smaller directory listings, this
allows a listing without requiring a separate file downlink (which also has not been implemented
yet)
## Changed
- The directory listing action commands now allow compressing of either the target output file
for the directory listing into file action command, or compression in the helper which dumps
the directory listing directly.
# [v1.45.0] 2023-04-14 # [v1.45.0] 2023-04-14
- q7s-package: v2.5.0 - q7s-package: v2.5.0

View File

@ -9,9 +9,9 @@
# ############################################################################## # ##############################################################################
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(OBSW_VERSION_MAJOR 1) set(OBSW_VERSION_MAJOR 2)
set(OBSW_VERSION_MINOR 45) set(OBSW_VERSION_MINOR 0)
set(OBSW_VERSION_REVISION 0) set(OBSW_VERSION_REVISION 2)
# set(CMAKE_VERBOSE TRUE) # set(CMAKE_VERBOSE TRUE)

View File

@ -233,6 +233,84 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_
case (LIST_DIRECTORY_INTO_FILE): { case (LIST_DIRECTORY_INTO_FILE): {
return actionListDirectoryIntoFile(actionId, commandedBy, data, size); return actionListDirectoryIntoFile(actionId, commandedBy, data, size);
} }
case (LIST_DIRECTORY_DUMP_DIRECTLY): {
return actionListDirectoryDumpDirectly(actionId, commandedBy, data, size);
}
case (CP_HELPER): {
CpHelperParser parser(data, size);
ReturnValue_t result = parser.parse();
if (result != returnvalue::OK) {
return result;
}
std::ostringstream oss("cp ", std::ostringstream::ate);
if (parser.isRecursiveOptSet()) {
oss << "-r ";
}
auto &sourceTgt = parser.destTgtPair();
oss << sourceTgt.sourceName << " " << sourceTgt.targetName;
sif::info << "CoreController: Performing copy command: " << oss.str() << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
return returnvalue::FAILED;
}
return EXECUTION_FINISHED;
}
case (MV_HELPER): {
MvHelperParser parser(data, size);
ReturnValue_t result = parser.parse();
if (result != returnvalue::OK) {
return result;
}
std::ostringstream oss("mv ", std::ostringstream::ate);
auto &sourceTgt = parser.destTgtPair();
oss << sourceTgt.sourceName << " " << sourceTgt.targetName;
sif::info << "CoreController: Performing move command: " << oss.str() << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
return returnvalue::FAILED;
}
return EXECUTION_FINISHED;
}
case (RM_HELPER): {
RmHelperParser parser(data, size);
ReturnValue_t result = parser.parse();
if (result != returnvalue::OK) {
return result;
}
std::ostringstream oss("rm ", std::ostringstream::ate);
if (parser.isRecursiveOptSet() or parser.isForceOptSet()) {
oss << "-";
}
if (parser.isRecursiveOptSet()) {
oss << "r";
}
if (parser.isForceOptSet()) {
oss << "f";
}
size_t removeTargetSize = 0;
const char *removeTgt = parser.getRemoveTarget(removeTargetSize);
oss << " " << removeTgt;
sif::info << "CoreController: Performing remove command: " << oss.str() << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
return returnvalue::FAILED;
}
return EXECUTION_FINISHED;
}
case (MKDIR_HELPER): {
if (size < 1) {
return HasActionsIF::INVALID_PARAMETERS;
}
std::string createdDir = std::string(reinterpret_cast<const char *>(data), size);
std::ostringstream oss("mkdir ", std::ostringstream::ate);
oss << createdDir;
sif::info << "CoreController: Performing directory creation: " << oss.str() << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
return returnvalue::FAILED;
}
return EXECUTION_FINISHED;
}
case (SWITCH_REBOOT_FILE_HANDLING): { case (SWITCH_REBOOT_FILE_HANDLING): {
if (size < 1) { if (size < 1) {
return HasActionsIF::INVALID_PARAMETERS; return HasActionsIF::INVALID_PARAMETERS;
@ -911,59 +989,144 @@ ReturnValue_t CoreController::initVersionFile() {
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId, ReturnValue_t CoreController::actionListDirectoryDumpDirectly(ActionId_t actionId,
MessageQueueId_t commandedBy, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) { const uint8_t *data, size_t size) {
// TODO: Packet definition for clean deserialization core::ListDirectoryCmdBase parser(data, size);
// 2 bytes for a and R flag, at least 5 bytes for minimum valid path /tmp with ReturnValue_t result = parser.parse();
// null termination, at least 7 bytes for minimum target file name /tmp/a with if (result != returnvalue::OK) {
// null termination. return result;
if (size < 14) {
return HasActionsIF::INVALID_PARAMETERS;
} }
// We could also make -l optional, but I can't think of a reason why to not use -l..
// This flag specifies to run ls with -a std::ostringstream oss("ls -l", std::ostringstream::ate);
bool aFlag = data[0]; if (parser.aFlagSet()) {
data += 1;
// This flag specifies to run ls with -R
bool RFlag = data[1];
data += 1;
size_t remainingSize = size - 2;
// One larger for null termination, which prevents undefined behaviour if the sent
// strings are not 0 terminated properly
std::vector<uint8_t> repoAndTargetFileBuffer(remainingSize + 1, 0);
std::memcpy(repoAndTargetFileBuffer.data(), data, remainingSize);
const char *currentCharPtr = reinterpret_cast<const char *>(repoAndTargetFileBuffer.data());
// Full target file name
std::string repoName(currentCharPtr);
size_t repoLength = repoName.length();
// The other string needs to be at least one letter plus NULL termination to be valid at all
// The first string also needs to be NULL terminated, but the termination is not included
// in the string length, so this is subtracted from the remaining size as well
if (repoLength > remainingSize - 3) {
return HasActionsIF::INVALID_PARAMETERS;
}
// The file length will not include the NULL termination, so we skip it
currentCharPtr += repoLength + 1;
std::string targetFileName(currentCharPtr);
std::ostringstream oss;
oss << "ls -l";
if (aFlag) {
oss << "a"; oss << "a";
} }
if (RFlag) { if (parser.rFlagSet()) {
oss << "R"; oss << "R";
} }
oss << " " << repoName << " > " << targetFileName; size_t repoNameLen = 0;
int result = std::system(oss.str().c_str()); const char *repoName = parser.getRepoName(repoNameLen);
if (result != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryIntoFile"); oss << " " << repoName << " > " << LIST_DIR_DUMP_WORK_FILE;
actionHelper.finish(false, commandedBy, actionId); sif::info << "Executing " << oss.str() << " for direct dump";
if (parser.compressionOptionSet()) {
sif::info << " with compression";
} }
return returnvalue::OK; sif::info << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryDumpDirectly");
return returnvalue::FAILED;
}
if (parser.compressionOptionSet()) {
std::string compressedName = LIST_DIR_DUMP_WORK_FILE + std::string(".gz");
oss.str("");
oss << "gzip " << LIST_DIR_DUMP_WORK_FILE;
ret = std::system(oss.str().c_str());
if (ret != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryDumpDirectly");
return returnvalue::FAILED;
}
oss.str("");
// Overwrite the work file with the compressed archive.
oss << "mv " << compressedName << " " << LIST_DIR_DUMP_WORK_FILE;
ret = std::system(oss.str().c_str());
if (ret != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryDumpDirectly");
return returnvalue::FAILED;
}
}
std::array<uint8_t, 1024> dirListingBuf{};
dirListingBuf[8] = parser.compressionOptionSet();
// First four bytes reserved for segment index. One byte for compression option information
std::strcpy(reinterpret_cast<char *>(dirListingBuf.data() + 2 * sizeof(uint32_t) + 1), repoName);
std::ifstream ifile(LIST_DIR_DUMP_WORK_FILE, std::ios::binary);
if (ifile.bad()) {
return returnvalue::FAILED;
}
std::error_code e;
size_t totalFileSize = std::filesystem::file_size(LIST_DIR_DUMP_WORK_FILE, e);
uint32_t segmentIdx = 0;
size_t dumpedBytes = 0;
size_t nextDumpLen = 0;
size_t dummy = 0;
size_t maxDumpLen = dirListingBuf.size() - 2 * sizeof(uint32_t) - 1 - repoNameLen - 1;
size_t listingDataOffset = 2 * sizeof(uint32_t) + 1 + repoNameLen + 1;
uint32_t chunks = totalFileSize / maxDumpLen;
if (totalFileSize % maxDumpLen != 0) {
chunks++;
}
SerializeAdapter::serialize(&chunks, dirListingBuf.data() + sizeof(uint32_t), &dummy,
dirListingBuf.size() - sizeof(uint32_t),
SerializeIF::Endianness::NETWORK);
while (dumpedBytes < totalFileSize) {
ifile.seekg(dumpedBytes, std::ios::beg);
nextDumpLen = maxDumpLen;
if (totalFileSize - dumpedBytes < maxDumpLen) {
nextDumpLen = totalFileSize - dumpedBytes;
}
SerializeAdapter::serialize(&segmentIdx, dirListingBuf.data(), &dummy, dirListingBuf.size(),
SerializeIF::Endianness::NETWORK);
ifile.read(reinterpret_cast<char *>(dirListingBuf.data() + listingDataOffset), nextDumpLen);
result = actionHelper.reportData(commandedBy, actionId, dirListingBuf.data(),
listingDataOffset + nextDumpLen);
if (result != returnvalue::OK) {
// Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
return result;
}
segmentIdx++;
dumpedBytes += nextDumpLen;
}
// Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
return EXECUTION_FINISHED;
}
ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId,
MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) {
core::ListDirectoryIntoFile parser(data, size);
ReturnValue_t result = parser.parse();
if (result != returnvalue::OK) {
return result;
}
std::ostringstream oss("ls -l", std::ostringstream::ate);
if (parser.aFlagSet()) {
oss << "a";
}
if (parser.rFlagSet()) {
oss << "R";
}
size_t repoNameLen = 0;
const char *repoName = parser.getRepoName(repoNameLen);
size_t targetFileNameLen = 0;
const char *targetFileName = parser.getTargetName(targetFileNameLen);
oss << " " << repoName << " > " << targetFileName;
sif::info << "Executing list directory request, command: " << oss.str() << std::endl;
int ret = std::system(oss.str().c_str());
if (ret != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryIntoFile");
return returnvalue::FAILED;
}
// Compression will add a .gz ending. I don't have any issue with this, it makes it explicit
// that this is a compressed file.
if (parser.compressionOptionSet()) {
oss.str("");
oss << "gzip " << targetFileName;
sif::info << "Compressing directory listing: " << oss.str() << std::endl;
ret = std::system(oss.str().c_str());
if (ret != 0) {
utility::handleSystemError(result, "CoreController::actionListDirectoryIntoFile");
return returnvalue::FAILED;
}
}
return EXECUTION_FINISHED;
} }
ReturnValue_t CoreController::initBootCopyFile() { ReturnValue_t CoreController::initBootCopyFile() {
@ -2049,6 +2212,8 @@ ReturnValue_t CoreController::executeSwUpdate(SwUpdateSources sourceDir, const u
if (not exists(archivePath, e)) { if (not exists(archivePath, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST; return HasFileSystemIF::FILE_DOES_NOT_EXIST;
} }
// TODO: Decompressing without limiting memory usage with xz is actually a bit risky..
// But has not been an issue so far.
ostringstream cmd("tar -xJf", ios::app); ostringstream cmd("tar -xJf", ios::app);
cmd << " " << archivePath << " -C " << prefixPath; cmd << " " << archivePath << " -C " << prefixPath;
int result = system(cmd.str().c_str()); int result = system(cmd.str().c_str());

View File

@ -66,6 +66,7 @@ class CoreController : public ExtendedControllerBase, public ReceivesParameterMe
static constexpr char CHIP_0_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-gold-rootfs"; static constexpr char CHIP_0_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-gold-rootfs";
static constexpr char CHIP_1_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-nom-rootfs"; static constexpr char CHIP_1_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-nom-rootfs";
static constexpr char CHIP_1_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-gold-rootfs"; static constexpr char CHIP_1_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-gold-rootfs";
static constexpr char LIST_DIR_DUMP_WORK_FILE[] = "/tmp/dir_listing.tmp";
static constexpr dur_millis_t INIT_SD_CARD_CHECK_TIMEOUT = 5000; static constexpr dur_millis_t INIT_SD_CARD_CHECK_TIMEOUT = 5000;
static constexpr dur_millis_t DEFAULT_SD_CARD_CHECK_TIMEOUT = 60000; static constexpr dur_millis_t DEFAULT_SD_CARD_CHECK_TIMEOUT = 60000;
@ -250,6 +251,12 @@ class CoreController : public ExtendedControllerBase, public ReceivesParameterMe
ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size); const uint8_t* data, size_t size);
ReturnValue_t actionListDirectoryDumpDirectly(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size);
ReturnValue_t actionListDirectoryCommonCommandCreator(const uint8_t* data, size_t size,
std::ostringstream& oss);
ReturnValue_t actionXscReboot(const uint8_t* data, size_t size); ReturnValue_t actionXscReboot(const uint8_t* data, size_t size);
ReturnValue_t actionReboot(const uint8_t* data, size_t size); ReturnValue_t actionReboot(const uint8_t* data, size_t size);

View File

@ -1,10 +1,11 @@
#include "ArcsecDatalinkLayer.h" #include "ArcsecDatalinkLayer.h"
extern "C" { extern "C" {
#include <wire/common/SLIP.h>
#include <wire/common/misc.h> #include <wire/common/misc.h>
} }
ArcsecDatalinkLayer::ArcsecDatalinkLayer() : decodeRingBuf(BUFFER_LENGTHS, true) { slipInit(); } ArcsecDatalinkLayer::ArcsecDatalinkLayer() : decodeRingBuf(BUFFER_LENGTHS, true) {}
ArcsecDatalinkLayer::~ArcsecDatalinkLayer() {} ArcsecDatalinkLayer::~ArcsecDatalinkLayer() {}
@ -15,35 +16,50 @@ ReturnValue_t ArcsecDatalinkLayer::checkRingBufForFrame(const uint8_t** decodedF
return DEC_IN_PROGRESS; return DEC_IN_PROGRESS;
} }
decodeRingBuf.readData(rxAnalysisBuffer, currentLen); decodeRingBuf.readData(rxAnalysisBuffer, currentLen);
bool startFound = false;
size_t startIdx = 0;
for (size_t idx = 0; idx < currentLen; idx++) { for (size_t idx = 0; idx < currentLen; idx++) {
enum arc_dec_result decResult = if (rxAnalysisBuffer[idx] != SLIP_START_AND_END) {
arc_transport_decode_body(rxAnalysisBuffer[idx], &slipInfo, decodedRxFrame, &rxFrameSize); continue;
switch (decResult) { }
case ARC_DEC_INPROGRESS: { if (not startFound) {
break; startFound = true;
} startIdx = idx;
case ARC_DEC_ERROR: { continue;
decodeRingBuf.deleteData(idx); }
return returnvalue::FAILED; // Now we can try decoding the whole frame.
} size_t encodedDataSize = 0;
case ARC_DEC_ASYNC: slip_error_t slipError =
case ARC_DEC_SYNC: { slip_decode_frame(decodedRxFrame, &rxFrameSize, rxAnalysisBuffer + startIdx,
// Reset length of SLIP struct for next frame idx - startIdx + 1, &encodedDataSize, ARC_DEF_SAGITTA_SLIP_ID);
slipInfo.length = 0; decodeRingBuf.deleteData(idx + 1);
switch (slipError) {
case (SLIP_OK): {
if (decodedFrame != nullptr) { if (decodedFrame != nullptr) {
*decodedFrame = decodedRxFrame; *decodedFrame = decodedRxFrame;
} }
frameLen = rxFrameSize; frameLen = rxFrameSize;
decodeRingBuf.deleteData(idx);
return returnvalue::OK; return returnvalue::OK;
} }
default: case (SLIP_BAD_CRC): {
sif::debug << "ArcsecDatalinkLayer::decodeFrame: Unknown result code" << std::endl; return CRC_FAILURE;
break; }
case (SLIP_OVERFLOW): {
return SLIP_OVERFLOW_RETVAL;
}
// Should not happen, we searched for start and end marker..
case (SLIP_NO_END): {
return returnvalue::FAILED; return returnvalue::FAILED;
}
case (SLIP_ID_MISMATCH): {
return SLIP_ID_MISSMATCH_RETVAL;
}
default: {
return returnvalue::FAILED;
}
} }
} }
decodeRingBuf.deleteData(currentLen);
return DEC_IN_PROGRESS; return DEC_IN_PROGRESS;
} }
@ -56,18 +72,11 @@ ReturnValue_t ArcsecDatalinkLayer::feedData(const uint8_t* rawData, size_t rawDa
return decodeRingBuf.writeData(rawData, rawDataLen); return decodeRingBuf.writeData(rawData, rawDataLen);
} }
void ArcsecDatalinkLayer::reset() { void ArcsecDatalinkLayer::reset() { decodeRingBuf.clear(); }
slipInit();
decodeRingBuf.clear();
}
void ArcsecDatalinkLayer::slipInit() {
slip_decode_init(rxBufferArc, sizeof(rxBufferArc), &slipInfo);
}
void ArcsecDatalinkLayer::encodeFrame(const uint8_t* data, size_t length, const uint8_t** txFrame, void ArcsecDatalinkLayer::encodeFrame(const uint8_t* data, size_t length, const uint8_t** txFrame,
size_t& size) { size_t& size) {
arc_transport_encode_body(data, length, txEncoded, &size); slip_encode_frame(data, length, txEncoded, &size, ARC_DEF_SAGITTA_SLIP_ID);
if (txFrame != nullptr) { if (txFrame != nullptr) {
*txFrame = txEncoded; *txFrame = txEncoded;
} }

View File

@ -25,6 +25,8 @@ class ArcsecDatalinkLayer {
static const ReturnValue_t REPLY_TOO_SHORT = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t REPLY_TOO_SHORT = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Detected CRC failure in received frame //! [EXPORT] : [COMMENT] Detected CRC failure in received frame
static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA2); static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA2);
static const ReturnValue_t SLIP_OVERFLOW_RETVAL = MAKE_RETURN_CODE(0xA3);
static const ReturnValue_t SLIP_ID_MISSMATCH_RETVAL = MAKE_RETURN_CODE(0xA4);
static const uint8_t STATUS_OK = 0; static const uint8_t STATUS_OK = 0;
@ -77,7 +79,7 @@ class ArcsecDatalinkLayer {
// Decoded frame will be copied to this buffer // Decoded frame will be copied to this buffer
uint8_t decodedRxFrame[startracker::MAX_FRAME_SIZE]; uint8_t decodedRxFrame[startracker::MAX_FRAME_SIZE];
// Size of decoded frame // Size of decoded frame
uint32_t rxFrameSize = 0; size_t rxFrameSize = 0;
// Buffer where encoded frames will be stored. First byte of encoded frame represents type of // Buffer where encoded frames will be stored. First byte of encoded frame represents type of
// reply // reply
@ -85,7 +87,7 @@ class ArcsecDatalinkLayer {
// Size of encoded frame // Size of encoded frame
uint32_t txFrameSize = 0; uint32_t txFrameSize = 0;
slip_decode_state slipInfo; // slip_decode_state slipInfo;
void slipInit(); void slipInit();
}; };

View File

@ -5,7 +5,11 @@
#include <mission/acs/str/strJsonCommands.h> #include <mission/acs/str/strJsonCommands.h>
extern "C" { extern "C" {
#include <sagitta/client/arc_client.h> #include <sagitta/client/actionreq.h>
#include <sagitta/client/client_tm_structs.h>
#include <sagitta/client/parameter.h>
#include <sagitta/client/telemetry.h>
#include <wire/common/genericstructs.h>
} }
#include <atomic> #include <atomic>
@ -880,7 +884,7 @@ ReturnValue_t StarTrackerHandler::interpretDeviceReply(DeviceCommandId_t id,
switch (id) { switch (id) {
case (startracker::REQ_TIME): { case (startracker::REQ_TIME): {
result = handleTm(packet, timeSet, startracker::TimeSet::SIZE); result = handleTm(packet, timeSet, startracker::TimeSet::SIZE, "REQ_TIME");
break; break;
} }
case (startracker::PING_REQUEST): { case (startracker::PING_REQUEST): {
@ -895,7 +899,7 @@ ReturnValue_t StarTrackerHandler::interpretDeviceReply(DeviceCommandId_t id,
break; break;
} }
case (startracker::REQ_VERSION): { case (startracker::REQ_VERSION): {
result = handleTm(packet, versionSet, startracker::VersionSet::SIZE); result = handleTm(packet, versionSet, startracker::VersionSet::SIZE, "REQ_VERSION");
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
@ -906,23 +910,23 @@ ReturnValue_t StarTrackerHandler::interpretDeviceReply(DeviceCommandId_t id,
break; break;
} }
case (startracker::REQ_INTERFACE): { case (startracker::REQ_INTERFACE): {
result = handleTm(packet, interfaceSet, startracker::InterfaceSet::SIZE); result = handleTm(packet, interfaceSet, startracker::InterfaceSet::SIZE, "REQ_INTERFACE");
break; break;
} }
case (startracker::REQ_POWER): { case (startracker::REQ_POWER): {
result = handleTm(packet, powerSet, startracker::PowerSet::SIZE); result = handleTm(packet, powerSet, startracker::PowerSet::SIZE, "REQ_POWER");
break; break;
} }
case (startracker::REQ_SOLUTION): { case (startracker::REQ_SOLUTION): {
result = handleTm(packet, solutionSet, startracker::SolutionSet::SIZE); result = handleTm(packet, solutionSet, startracker::SolutionSet::SIZE, "REQ_SOLUTION");
break; break;
} }
case (startracker::REQ_TEMPERATURE): { case (startracker::REQ_TEMPERATURE): {
result = handleTm(packet, temperatureSet, startracker::TemperatureSet::SIZE); result = handleTm(packet, temperatureSet, startracker::TemperatureSet::SIZE, "REQ_TEMP");
break; break;
} }
case (startracker::REQ_HISTOGRAM): { case (startracker::REQ_HISTOGRAM): {
result = handleTm(packet, histogramSet, startracker::HistogramSet::SIZE); result = handleTm(packet, histogramSet, startracker::HistogramSet::SIZE, "REQ_HISTO");
break; break;
} }
case (startracker::SUBSCRIPTION): case (startracker::SUBSCRIPTION):
@ -1972,7 +1976,7 @@ ReturnValue_t StarTrackerHandler::checkProgram() {
} }
ReturnValue_t StarTrackerHandler::handleTm(const uint8_t* rawFrame, LocalPoolDataSetBase& dataset, ReturnValue_t StarTrackerHandler::handleTm(const uint8_t* rawFrame, LocalPoolDataSetBase& dataset,
size_t size) { size_t size, const char* context) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
uint8_t status = startracker::getStatusField(rawFrame); uint8_t status = startracker::getStatusField(rawFrame);
if (status != startracker::STATUS_OK) { if (status != startracker::STATUS_OK) {
@ -1988,7 +1992,8 @@ ReturnValue_t StarTrackerHandler::handleTm(const uint8_t* rawFrame, LocalPoolDat
dataset.setValidityBufferGeneration(false); dataset.setValidityBufferGeneration(false);
result = dataset.deSerialize(&reply, &size, SerializeIF::Endianness::LITTLE); result = dataset.deSerialize(&reply, &size, SerializeIF::Endianness::LITTLE);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
sif::warning << "StarTrackerHandler::handleTm: Deserialization failed" << std::endl; sif::warning << "StarTrackerHandler::handleTm: Deserialization failed for " << context
<< std::endl;
} }
dataset.setValidityBufferGeneration(true); dataset.setValidityBufferGeneration(true);
dataset.setValidity(true, true); dataset.setValidity(true, true);

View File

@ -481,7 +481,8 @@ class StarTrackerHandler : public DeviceHandlerBase {
* *
* @return returnvalue::OK if successful, otherwise error return value * @return returnvalue::OK if successful, otherwise error return value
*/ */
ReturnValue_t handleTm(const uint8_t* rawFrame, LocalPoolDataSetBase& dataset, size_t size); ReturnValue_t handleTm(const uint8_t* rawFrame, LocalPoolDataSetBase& dataset, size_t size,
const char* context);
/** /**
* @brief Checks if star tracker is in valid mode for executing the received command. * @brief Checks if star tracker is in valid mode for executing the received command.

View File

@ -641,7 +641,7 @@ class TimeSet : public StaticLocalDataSet<TIME_SET_ENTRIES> {
*/ */
class SolutionSet : public StaticLocalDataSet<SOLUTION_SET_ENTRIES> { class SolutionSet : public StaticLocalDataSet<SOLUTION_SET_ENTRIES> {
public: public:
static const size_t SIZE = 78; static const size_t SIZE = 79;
SolutionSet(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, SOLUTION_SET_ID) {} SolutionSet(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, SOLUTION_SET_ID) {}

View File

@ -32,7 +32,6 @@ static constexpr char VERSION_FILE_NAME[] = "version.txt";
static constexpr char REBOOT_FILE_NAME[] = "reboot.txt"; static constexpr char REBOOT_FILE_NAME[] = "reboot.txt";
static constexpr char TIME_FILE_NAME[] = "time_backup.txt"; static constexpr char TIME_FILE_NAME[] = "time_backup.txt";
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0;
static constexpr ActionId_t ANNOUNCE_VERSION = 1; static constexpr ActionId_t ANNOUNCE_VERSION = 1;
static constexpr ActionId_t ANNOUNCE_CURRENT_IMAGE = 2; static constexpr ActionId_t ANNOUNCE_CURRENT_IMAGE = 2;
static constexpr ActionId_t ANNOUNCE_BOOT_COUNTS = 3; static constexpr ActionId_t ANNOUNCE_BOOT_COUNTS = 3;
@ -59,6 +58,13 @@ static constexpr ActionId_t EXECUTE_SHELL_CMD_BLOCKING = 40;
static constexpr ActionId_t EXECUTE_SHELL_CMD_NON_BLOCKING = 41; static constexpr ActionId_t EXECUTE_SHELL_CMD_NON_BLOCKING = 41;
static constexpr ActionId_t SYSTEMCTL_CMD_EXECUTOR = 42; static constexpr ActionId_t SYSTEMCTL_CMD_EXECUTOR = 42;
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 50;
static constexpr ActionId_t LIST_DIRECTORY_DUMP_DIRECTLY = 51;
static constexpr ActionId_t CP_HELPER = 52;
static constexpr ActionId_t MV_HELPER = 53;
static constexpr ActionId_t RM_HELPER = 54;
static constexpr ActionId_t MKDIR_HELPER = 55;
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE;
static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
@ -96,6 +102,198 @@ static constexpr Event I2C_REBOOT = event::makeEvent(SUBSYSTEM_ID, 11, severity:
//! [EXPORT] : [COMMENT] PDEC recovery through reset was not possible, performing full reboot. //! [EXPORT] : [COMMENT] PDEC recovery through reset was not possible, performing full reboot.
static constexpr Event PDEC_REBOOT = event::makeEvent(SUBSYSTEM_ID, 12, severity::HIGH); static constexpr Event PDEC_REBOOT = event::makeEvent(SUBSYSTEM_ID, 12, severity::HIGH);
class ListDirectoryCmdBase {
public: // TODO: Packet definition for clean deserialization
// 3 bytes for a and R flag, at least 5 bytes for minimum valid path /tmp with
// null termination
static constexpr size_t MIN_DATA_LEN = 8;
ListDirectoryCmdBase(const uint8_t* data, size_t maxSize) : data(data), maxSize(maxSize) {}
virtual ~ListDirectoryCmdBase() = default;
virtual ReturnValue_t parse() {
if (maxSize < MIN_DATA_LEN) {
return SerializeIF::STREAM_TOO_SHORT;
}
aFlag = data[0];
rFlag = data[1];
compressOption = data[2];
repoNameLen = strnlen(reinterpret_cast<const char*>(data + 3), maxSize - 3);
// Last byte MUST be null terminated!
if (repoNameLen >= maxSize - 3) {
return HasActionsIF::INVALID_PARAMETERS;
}
repoName = reinterpret_cast<const char*>(data + 3);
return returnvalue::OK;
}
bool aFlagSet() const { return this->aFlag; }
bool rFlagSet() const { return this->rFlag; }
bool compressionOptionSet() const { return this->compressOption; }
const char* getRepoName(size_t& repoNameLen) const {
repoNameLen = this->repoNameLen;
return this->repoName;
}
size_t getBaseSize() {
// Include NULL termination
if (repoName != nullptr) {
return 3 + repoNameLen + 1;
}
return 0;
}
protected:
const uint8_t* data;
size_t maxSize;
bool aFlag = false;
bool rFlag = false;
bool compressOption = false;
const char* repoName = nullptr;
size_t repoNameLen = 0;
};
class ListDirectoryIntoFile : public ListDirectoryCmdBase {
public:
// TODO: Packet definition for clean deserialization
// 3 bytes for a and R flag, at least 5 bytes for minimum valid path /tmp with
// null termination, at least 7 bytes for minimum target file name /tmp/a with
// null termination.
static constexpr size_t MIN_DATA_LEN = 15;
ListDirectoryIntoFile(const uint8_t* data, size_t maxSize)
: ListDirectoryCmdBase(data, maxSize) {}
ReturnValue_t parse() override {
if (maxSize < MIN_DATA_LEN) {
return SerializeIF::STREAM_TOO_SHORT;
}
ReturnValue_t result = ListDirectoryCmdBase::parse();
if (result != returnvalue::OK) {
return result;
}
targetNameLen =
strnlen(reinterpret_cast<const char*>(data + getBaseSize()), maxSize - getBaseSize());
if (targetNameLen >= maxSize - getBaseSize()) {
// Again: String MUST be null terminated.
return HasActionsIF::INVALID_PARAMETERS;
}
targetName = reinterpret_cast<const char*>(data + getBaseSize());
return result;
}
const char* getTargetName(size_t& targetNameLen) const {
targetNameLen = this->targetNameLen;
return this->targetName;
}
private:
const char* targetName = nullptr;
size_t targetNameLen = 0;
};
struct SourceTargetPair {
const char* sourceName = nullptr;
size_t sourceNameSize = 0;
const char* targetName = nullptr;
size_t targetNameSize = 0;
};
static ReturnValue_t parseDestTargetString(const uint8_t* data, size_t maxLen,
SourceTargetPair& destTgt) {
if (maxLen < 4) {
return SerializeIF::STREAM_TOO_SHORT;
}
destTgt.sourceNameSize = strnlen(reinterpret_cast<const char*>(data), maxLen);
if (destTgt.sourceNameSize >= maxLen) {
return HasActionsIF::INVALID_PARAMETERS;
}
destTgt.sourceName = reinterpret_cast<const char*>(data);
size_t remainingLen = maxLen - destTgt.sourceNameSize - 1;
if (remainingLen == 0) {
return HasActionsIF::INVALID_PARAMETERS;
}
destTgt.targetNameSize =
strnlen(reinterpret_cast<const char*>(data + destTgt.sourceNameSize + 1), remainingLen);
if (destTgt.targetNameSize >= remainingLen) {
return HasActionsIF::INVALID_PARAMETERS;
}
destTgt.targetName = reinterpret_cast<const char*>(data + destTgt.sourceNameSize + 1);
return returnvalue::OK;
}
class CpHelperParser {
public:
CpHelperParser(const uint8_t* data, size_t maxLen) : data(data), maxLen(maxLen) {}
ReturnValue_t parse() {
if (maxLen < 1) {
return SerializeIF::STREAM_TOO_SHORT;
}
recursiveOpt = data[0];
return parseDestTargetString(data + 1, maxLen - 1, destTgt);
}
const SourceTargetPair& destTgtPair() const { return destTgt; }
bool isRecursiveOptSet() const { return recursiveOpt; }
private:
const uint8_t* data;
size_t maxLen;
bool recursiveOpt = false;
SourceTargetPair destTgt;
};
class MvHelperParser {
public:
MvHelperParser(const uint8_t* data, size_t maxLen) : data(data), maxLen(maxLen) {}
ReturnValue_t parse() { return parseDestTargetString(data, maxLen, destTgt); }
const SourceTargetPair& destTgtPair() const { return destTgt; }
private:
const uint8_t* data;
size_t maxLen;
SourceTargetPair destTgt;
};
class RmHelperParser {
public:
RmHelperParser(const uint8_t* data, size_t maxLen) : data(data), maxLen(maxLen) {}
ReturnValue_t parse() {
if (maxLen < 2) {
return SerializeIF::STREAM_TOO_SHORT;
}
recursiveOpt = data[0];
forceOpt = data[1];
removeTargetSize = strnlen(reinterpret_cast<const char*>(data + 2), maxLen - 2);
// Must be null-terminated
if (removeTargetSize >= maxLen - 2) {
return HasActionsIF::INVALID_PARAMETERS;
}
removeTarget = reinterpret_cast<const char*>(data + 2);
return returnvalue::OK;
}
bool isRecursiveOptSet() const { return recursiveOpt; }
bool isForceOptSet() const { return forceOpt; }
const char* getRemoveTarget(size_t& removeTargetSize) {
removeTargetSize = this->removeTargetSize;
return removeTarget;
}
private:
const uint8_t* data;
size_t maxLen;
bool recursiveOpt = false;
bool forceOpt = false;
const char* removeTarget = nullptr;
size_t removeTargetSize = 0;
};
} // namespace core } // namespace core
#endif /* MISSION_SYSDEFS_H_ */ #endif /* MISSION_SYSDEFS_H_ */

2
tmtc

Submodule tmtc updated: d00e4247f6...3bb0a08e95