Compare commits
1 Commits
cfdp-bugfi
...
mohr/relse
Author | SHA1 | Date | |
---|---|---|---|
b8d2fa530b |
122
CHANGELOG.md
122
CHANGELOG.md
@ -8,40 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
## Fixes
|
||||
|
||||
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
|
||||
number fields stored the actual length of the field instead of the length minus 1 like specified
|
||||
in the CFDP standard.
|
||||
- PUS Health Service: Size check for set health command.
|
||||
Perform operation completion for announce health command.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
|
||||
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
|
||||
- Small tweak for version getter
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
|
||||
|
||||
## Added
|
||||
|
||||
- add CFDP subsystem ID
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||
|
||||
## Changed
|
||||
- Bump ETL version to 20.35.14
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
|
||||
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Assert that `FixedArrayList` is larger than 0 at compile time.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
|
||||
|
||||
# [v6.0.0] 2023-02-10
|
||||
|
||||
## Fixes
|
||||
|
||||
- Mode Service: Add allowed subservice
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
|
||||
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
||||
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
||||
subservice not working properly.
|
||||
@ -77,36 +47,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
||||
CCSDS packets which were clumped together. This has been fixed now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||
- various fixes related to linux Unittests and memory leaks
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
|
||||
- small fix to allow teardown handling
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
|
||||
- fix compiler warning for fixed array list copy ctor
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
|
||||
- missing include
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
|
||||
- defaultconfig did not build anymore
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
|
||||
- hotfix
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
|
||||
- small fix for helper
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
|
||||
- missing retval conv
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
|
||||
- DHB Countdown Bug
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
|
||||
- doc corrections
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
|
||||
- better error printout
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
|
||||
- include correction
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
|
||||
- better warning for missing include paths
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
|
||||
- Service 11 regression
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
|
||||
|
||||
## Added
|
||||
|
||||
@ -123,32 +63,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||
- Add new `UnsignedByteField` class
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
||||
- publish documentation for development and master branch
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
|
||||
- Add Linux HAL options
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
|
||||
- Expand SerializeIF
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
|
||||
- PUS Service 11: Additional Safety Check
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
|
||||
- improvements for auto-formatter script
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
|
||||
- provide a weak print char impl
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
|
||||
|
||||
## Removed
|
||||
|
||||
- now that doc server is up, remove markdown files
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
|
||||
- remove bsp specific code
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
|
||||
|
||||
## Changes
|
||||
|
||||
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
||||
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
||||
`HealthServiceCfg` now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
||||
- Moved some container returnvalues to dedicated header and namespace
|
||||
@ -182,41 +99,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||
- Make functions `const` where it makes sense
|
||||
- Add `const char* getName const` abstract function
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||
- Generic TMTC Bridge Update
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
||||
- comment tweak to event parser can read everything
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
|
||||
- CMakeLists file updates
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
|
||||
- improve srv20 error messages
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
|
||||
- I2C Linux: remove duplicate printout
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
|
||||
- printout handling improvements
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
|
||||
- vec getter, reset for content
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
|
||||
- updates for source sequence counter
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
|
||||
- SP reader getPacketData is const now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
|
||||
- refactoring of serial drivers for linux
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
|
||||
- Local Pool Update Remove Add Data Ignore Fault Argument
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
|
||||
- Switch to new documentation server
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
|
||||
- Windows Tweaks
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
|
||||
- Refactor Local Pool API
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
|
||||
- group MGM data in local pool vectors
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
|
||||
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
|
||||
## CFDP
|
||||
|
||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
||||
# Version file handling #
|
||||
# ##############################################################################
|
||||
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 6)
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 5)
|
||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||
|
||||
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
set(FSFW_ETL_LIB_VERSION
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.35.14
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
|
89
scripts/check_release.py
Executable file → Normal file
89
scripts/check_release.py
Executable file → Normal file
@ -1,40 +1,29 @@
|
||||
#! /bin/python
|
||||
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import urllib.request
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="List undocumented PRs"
|
||||
)
|
||||
parser.add_argument("-v", "--version", type=str, required=True)
|
||||
parser.add_argument("-m", "--milestone", type=int, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
|
||||
milestone = args.milestone
|
||||
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones/" + str(milestone)) as milestone_json:
|
||||
milestone_title = json.load(milestone_json)['title']
|
||||
|
||||
match = re.search("(v[0-9]+\.[0-9]+\.[0-9]+)", milestone_title)
|
||||
|
||||
if not match:
|
||||
print("invalid version")
|
||||
print("invalid Milestone name")
|
||||
exit(1)
|
||||
|
||||
version = "v" + match.group(1)
|
||||
version = match.group(0)
|
||||
|
||||
print("looking for milestone for " + version + " ...")
|
||||
|
||||
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
|
||||
milestones = json.load(milestone_json)
|
||||
if (len(milestones) == 0):
|
||||
print("did not find any milestone")
|
||||
exit(1)
|
||||
if (len(milestones) > 1):
|
||||
print("found multiple milestons")
|
||||
milestone_title = milestones[0]['title']
|
||||
milestone = str(milestones[0]['id'])
|
||||
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
|
||||
print("detected Version " + version)
|
||||
|
||||
milestone_prs = []
|
||||
|
||||
@ -44,67 +33,11 @@ def main() -> None:
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
|
||||
pull_requests = json.load(pull_requests_json)
|
||||
for pr in pull_requests:
|
||||
milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']})
|
||||
milestone_prs.append(pr['number'])
|
||||
page += 1
|
||||
last_count = len(pull_requests)
|
||||
|
||||
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
|
||||
|
||||
print("looking for CHANGELOG.md ...")
|
||||
|
||||
path = Path(".")
|
||||
|
||||
files = list(path.glob("CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
files = list(path.glob("../CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
|
||||
exit(1)
|
||||
|
||||
print("Scanning CHANGELOG.md ...")
|
||||
|
||||
changelog_prs = []
|
||||
|
||||
with open(files[0]) as changelog:
|
||||
line = changelog.readline()
|
||||
while (line):
|
||||
#print("line: " + line)
|
||||
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
|
||||
if (match):
|
||||
if match.group(1) == version:
|
||||
#print("found version")
|
||||
line = changelog.readline()
|
||||
continue
|
||||
else:
|
||||
#print("done with " + match.group(1))
|
||||
break
|
||||
|
||||
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
|
||||
if match:
|
||||
changelog_prs.append(match.group(1))
|
||||
|
||||
line = changelog.readline()
|
||||
|
||||
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
|
||||
|
||||
print("")
|
||||
|
||||
copy_array = changelog_prs.copy()
|
||||
print("PRs in CHANGELOG.md that are not in Milestone:")
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] in copy_array:
|
||||
copy_array.remove(pr['number'])
|
||||
for pr in copy_array:
|
||||
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
|
||||
|
||||
print("")
|
||||
|
||||
print("PRs in milestone that are not in CHANGELOG.md:")
|
||||
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] not in changelog_prs:
|
||||
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
|
||||
|
||||
main()
|
||||
|
@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
|
||||
*buffer += 1;
|
||||
**buffer = pduDataFieldLen & 0x00ff;
|
||||
*buffer += 1;
|
||||
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
|
||||
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
|
||||
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
|
||||
pduConf.seqNum.getWidth();
|
||||
*buffer += 1;
|
||||
*size += 4;
|
||||
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);
|
||||
|
@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const {
|
||||
return static_cast<cfdp::WidthInBytes>(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1);
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
|
||||
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
|
||||
}
|
||||
|
||||
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
||||
|
@ -12,7 +12,6 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||
class FixedArrayList : public ArrayList<T, count_t> {
|
||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||
"count_t is not large enough to hold MAX_SIZE");
|
||||
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
|
||||
|
||||
private:
|
||||
T data[MAX_SIZE];
|
||||
|
@ -10,7 +10,7 @@ enum : uint8_t {
|
||||
CDH = 28,
|
||||
TCS_1 = 59,
|
||||
PCDU_1 = 42,
|
||||
POWER_SWITCH_IF = 43,
|
||||
PCDU_2 = 43,
|
||||
HEATER = 50,
|
||||
T_SENSORS = 52,
|
||||
FDIR = 70,
|
||||
@ -33,7 +33,6 @@ enum : uint8_t {
|
||||
PUS_SERVICE_23 = 103,
|
||||
MGM_LIS3MDL = 106,
|
||||
MGM_RM3100 = 107,
|
||||
CFDP = 108,
|
||||
|
||||
FW_SUBSYSTEM_ID_RANGE
|
||||
};
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "HealthTableIF.h"
|
||||
|
||||
class HealthTable : public HealthTableIF, public SystemObject {
|
||||
friend class CServiceHealthCommanding;
|
||||
|
||||
public:
|
||||
explicit HealthTable(object_id_t objectid);
|
||||
~HealthTable() override;
|
||||
|
@ -76,17 +76,14 @@ timeval Clock::getUptime() {
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
||||
// TODO This is not posix compatible and delivers only seconds precision
|
||||
// Linux specific file read but more precise.
|
||||
double uptimeSeconds;
|
||||
std::ifstream ifile("/proc/uptime");
|
||||
if (ifile.bad()) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (ifile >> uptimeSeconds) {
|
||||
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
|
||||
uptime->tv_sec = uptimeSeconds;
|
||||
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
return returnvalue::FAILED;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
// Wait for new FSFW Clock function delivering seconds uptime.
|
||||
|
@ -32,7 +32,7 @@ class Fuse : public SystemObject,
|
||||
gp_id_t poolIdPower;
|
||||
};
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
|
||||
//! PSS detected that current on a fuse is totally out of bounds.
|
||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
||||
//! PSS detected a fuse that went off.
|
||||
|
@ -28,12 +28,10 @@ class PowerSwitchIF {
|
||||
static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
||||
static const ReturnValue_t SWITCH_UNKNOWN = MAKE_RETURN_CODE(5);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
|
||||
//!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(
|
||||
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
/**
|
||||
* send a direct command to the Power Unit to enable/disable the specified switch.
|
||||
*
|
||||
@ -52,7 +50,6 @@ class PowerSwitchIF {
|
||||
* @return
|
||||
* - @c SWITCH_ON if the specified switch is on.
|
||||
* - @c SWITCH_OFF if the specified switch is off.
|
||||
* - @c SWITCH_UNKNOWN if the state of the specified switch is unknown.
|
||||
* - @c returnvalue::FAILED if an error occured
|
||||
*/
|
||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
||||
|
@ -9,4 +9,4 @@ target_sources(
|
||||
Service17Test.cpp
|
||||
Service20ParameterManagement.cpp
|
||||
CService200ModeCommanding.cpp
|
||||
CServiceHealthCommanding.cpp)
|
||||
CService201HealthCommanding.cpp)
|
||||
|
@ -20,7 +20,6 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
|
||||
case (Subservice::COMMAND_MODE_COMMAND):
|
||||
case (Subservice::COMMAND_MODE_READ):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
|
106
src/fsfw/pus/CService201HealthCommanding.cpp
Normal file
106
src/fsfw/pus/CService201HealthCommanding.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "fsfw/pus/CService201HealthCommanding.h"
|
||||
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthMessage.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid,
|
||||
uint8_t serviceId,
|
||||
uint8_t numParallelCommands,
|
||||
uint16_t commandTimeoutSeconds)
|
||||
: CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands,
|
||||
commandTimeoutSeconds) {}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Invalid Subservice" << std::endl;
|
||||
#endif
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
||||
const uint8_t *tcData,
|
||||
size_t tcDataLen,
|
||||
MessageQueueId_t *id,
|
||||
object_id_t *objectId) {
|
||||
if (tcDataLen < sizeof(object_id_t)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
|
||||
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||
if (destination == nullptr) {
|
||||
return CommandingServiceBase::INVALID_OBJECT;
|
||||
}
|
||||
|
||||
*messageQueueToSet = destination->getCommandQueue();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message,
|
||||
uint8_t subservice, const uint8_t *tcData,
|
||||
size_t tcDataLen, uint32_t *state,
|
||||
object_id_t objectId) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH): {
|
||||
HealthSetCommand healthCommand;
|
||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
break;
|
||||
}
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
||||
healthCommand.getHealth());
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Should never happen, subservice was already checked
|
||||
result = returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply,
|
||||
Command_t previousCommand, uint32_t *state,
|
||||
CommandMessage *optionalNextCommand,
|
||||
object_id_t objectId, bool *isStep) {
|
||||
Command_t replyId = reply->getCommand();
|
||||
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
||||
return EXECUTION_COMPLETE;
|
||||
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
||||
return reply->getReplyRejectedReason();
|
||||
}
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
}
|
||||
|
||||
// Not used for now, health state already reported by event
|
||||
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
|
||||
const CommandMessage *reply) {
|
||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||
HealthSetReply healthSetReply(health, oldHealth);
|
||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
||||
}
|
@ -1,26 +1,8 @@
|
||||
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
|
||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||
|
||||
struct HealthServiceCfg {
|
||||
HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable,
|
||||
uint16_t maxNumHealthInfoPerCycle)
|
||||
: objectId(objectId),
|
||||
apid(apid),
|
||||
table(healthTable),
|
||||
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
||||
object_id_t objectId;
|
||||
uint16_t apid;
|
||||
object_id_t table;
|
||||
uint16_t maxNumHealthInfoPerCycle;
|
||||
uint8_t service = 201;
|
||||
uint8_t numParallelCommands = 4;
|
||||
uint16_t commandTimeoutSeconds = 60;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom PUS service to set health of all objects
|
||||
* implementing hasHealthIF.
|
||||
@ -35,12 +17,11 @@ struct HealthServiceCfg {
|
||||
* child class like this service
|
||||
*
|
||||
*/
|
||||
class CServiceHealthCommanding : public CommandingServiceBase {
|
||||
class CService201HealthCommanding : public CommandingServiceBase {
|
||||
public:
|
||||
CServiceHealthCommanding(HealthServiceCfg args);
|
||||
~CServiceHealthCommanding() override = default;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
||||
~CService201HealthCommanding() override = default;
|
||||
|
||||
protected:
|
||||
/* CSB abstract function implementations */
|
||||
@ -56,14 +37,7 @@ class CServiceHealthCommanding : public CommandingServiceBase {
|
||||
CommandMessage *optionalNextCommand, object_id_t objectId,
|
||||
bool *isStep) override;
|
||||
|
||||
void doPeriodicOperation() override;
|
||||
|
||||
private:
|
||||
const object_id_t healthTableId;
|
||||
HealthTable *healthTable;
|
||||
uint16_t maxNumHealthInfoPerCycle = 0;
|
||||
bool reportAllHealth = false;
|
||||
ReturnValue_t iterateHealthTable(bool reset);
|
||||
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
||||
const object_id_t *objectId);
|
||||
|
@ -1,161 +0,0 @@
|
||||
#include <fsfw/events/EventManagerIF.h>
|
||||
#include <fsfw/pus/CServiceHealthCommanding.h>
|
||||
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthMessage.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
||||
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
||||
args.numParallelCommands, args.commandTimeoutSeconds),
|
||||
healthTableId(args.table),
|
||||
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::initialize() {
|
||||
ReturnValue_t result = CommandingServiceBase::initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
healthTable = ObjectManager::instance()->get<HealthTable>(healthTableId);
|
||||
if (healthTable == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Invalid Subservice" << std::endl;
|
||||
#endif
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
||||
const uint8_t *tcData,
|
||||
size_t tcDataLen,
|
||||
MessageQueueId_t *id,
|
||||
object_id_t *objectId) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
if (tcDataLen < sizeof(object_id_t)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
|
||||
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||
if (destination == nullptr) {
|
||||
return CommandingServiceBase::INVALID_OBJECT;
|
||||
}
|
||||
|
||||
*messageQueueToSet = destination->getCommandQueue();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||
const uint8_t *tcData, size_t tcDataLen,
|
||||
uint32_t *state, object_id_t objectId) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH): {
|
||||
if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
HealthSetCommand healthCommand;
|
||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
break;
|
||||
}
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
||||
healthCommand.getHealth());
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
ReturnValue_t result = iterateHealthTable(true);
|
||||
if (result == returnvalue::OK) {
|
||||
reportAllHealth = true;
|
||||
return EXECUTION_COMPLETE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default: {
|
||||
// Should never happen, subservice was already checked
|
||||
result = returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply,
|
||||
Command_t previousCommand, uint32_t *state,
|
||||
CommandMessage *optionalNextCommand,
|
||||
object_id_t objectId, bool *isStep) {
|
||||
Command_t replyId = reply->getCommand();
|
||||
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
||||
return EXECUTION_COMPLETE;
|
||||
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
||||
return reply->getReplyRejectedReason();
|
||||
}
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
}
|
||||
|
||||
void CServiceHealthCommanding::doPeriodicOperation() {
|
||||
if (reportAllHealth) {
|
||||
for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) {
|
||||
ReturnValue_t result = iterateHealthTable(false);
|
||||
if (result != returnvalue::OK) {
|
||||
reportAllHealth = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not used for now, health state already reported by event
|
||||
[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply(
|
||||
const CommandMessage *reply) {
|
||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||
HealthSetReply healthSetReply(health, oldHealth);
|
||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
||||
std::pair<object_id_t, HasHealthIF::HealthState> pair;
|
||||
|
||||
ReturnValue_t result = healthTable->iterate(&pair, reset);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
} else {
|
||||
EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
#include "version.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/FSFWVersion.h"
|
||||
|
||||
@ -21,7 +20,7 @@ fsfw::Version::Version(int major, int minor, int revision, const char* addInfo)
|
||||
|
||||
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
||||
if (addInfo != nullptr and std::strcmp(addInfo, "") != 0) {
|
||||
if (addInfo != nullptr) {
|
||||
snprintf(str + len, maxLen - len, "-%s", addInfo);
|
||||
}
|
||||
}
|
||||
@ -31,7 +30,7 @@ namespace fsfw {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
||||
os << v.major << "." << v.minor << "." << v.revision;
|
||||
if (v.addInfo != nullptr and std::strcmp(v.addInfo, "") != 0) {
|
||||
if (v.addInfo != nullptr) {
|
||||
os << "-" << v.addInfo;
|
||||
}
|
||||
return os;
|
||||
|
@ -97,7 +97,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(),
|
||||
SerializeIF::Endianness::BIG) == returnvalue::OK);
|
||||
CHECK(serBuf[0] == 0x3f);
|
||||
CHECK(serBuf[3] == 0x88);
|
||||
CHECK(serBuf[3] == 0x99);
|
||||
REQUIRE(creator.getCrcFlag() == true);
|
||||
REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER);
|
||||
REQUIRE(creator.getLargeFileFlag() == true);
|
||||
@ -127,7 +127,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED);
|
||||
REQUIRE(creator.getSegmentationControl() == true);
|
||||
// Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs)
|
||||
REQUIRE(serBuf[3] == 0b10111001);
|
||||
REQUIRE(serBuf[3] == 0b11001010);
|
||||
uint32_t entityId = 0;
|
||||
size_t deSerSize = 0;
|
||||
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize,
|
||||
@ -175,7 +175,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
REQUIRE(serBuf[1] == 0);
|
||||
REQUIRE(serBuf[2] == 0);
|
||||
// Entity and Transaction Sequence number are 1 byte large
|
||||
REQUIRE(serBuf[3] == 0b00000000);
|
||||
REQUIRE(serBuf[3] == 0b00010001);
|
||||
// Source ID
|
||||
REQUIRE(serBuf[4] == 0);
|
||||
// Transaction Seq Number
|
||||
@ -220,7 +220,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
REQUIRE(serBuf[1] == 0);
|
||||
REQUIRE(serBuf[2] == 0);
|
||||
// Entity and Transaction Sequence number are 1 byte large
|
||||
REQUIRE(serBuf[3] == 0b00000000);
|
||||
REQUIRE(serBuf[3] == 0b00010001);
|
||||
REQUIRE(serSize == 7);
|
||||
// Deser call not strictly necessary
|
||||
auto reader = PduHeaderReader(serBuf.data(), serBuf.size());
|
||||
@ -270,7 +270,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
REQUIRE(reader.parseData() == returnvalue::OK);
|
||||
// Everything except version bit flipped to one now
|
||||
REQUIRE(serBuf[0] == 0x3f);
|
||||
REQUIRE(serBuf[3] == 0b10111001);
|
||||
REQUIRE(serBuf[3] == 0b11001010);
|
||||
REQUIRE(reader.getWholePduSize() == 14);
|
||||
|
||||
REQUIRE(reader.getCrcFlag() == true);
|
||||
|
@ -68,7 +68,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") {
|
||||
// Bits 1 to 3 length of enitity IDs is 2
|
||||
// Bit 4: Segment metadata flag is set
|
||||
// Bit 5 to seven: length of transaction seq num is 2
|
||||
REQUIRE(fileDataBuffer[3] == 0b10011001);
|
||||
REQUIRE(fileDataBuffer[3] == 0b10101010);
|
||||
REQUIRE((fileDataBuffer[10] >> 6) &
|
||||
0b11 == cfdp::RecordContinuationState::CONTAINS_START_AND_END);
|
||||
// Segment metadata length
|
||||
|
@ -30,7 +30,7 @@ TEST_CASE("CFDP File Directive", "[cfdp][pdu]") {
|
||||
REQUIRE(serBuf[1] == 0);
|
||||
REQUIRE(serBuf[2] == 5);
|
||||
// Entity and Transaction Sequence number are 1 byte large
|
||||
REQUIRE(serBuf[3] == 0b00000000);
|
||||
REQUIRE(serBuf[3] == 0b00010001);
|
||||
// Source ID
|
||||
REQUIRE(serBuf[4] == 0);
|
||||
// Transaction Seq Number
|
||||
@ -82,4 +82,4 @@ TEST_CASE("CFDP File Directive", "[cfdp][pdu]") {
|
||||
// Invalid file directive
|
||||
REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,8 +33,8 @@ TEST_CASE("CFDP Base", "[cfdp]") {
|
||||
// PDU data field length is 5 (4 + Directive code octet)
|
||||
REQUIRE(serBuf[1] == 0);
|
||||
REQUIRE(serBuf[2] == 5);
|
||||
// Entity and Transaction Sequence number are 1 byte large, value minus one is stored
|
||||
REQUIRE(serBuf[3] == 0b00000000);
|
||||
// Entity and Transaction Sequence number are 1 byte large
|
||||
REQUIRE(serBuf[3] == 0b00010001);
|
||||
// Source ID
|
||||
REQUIRE(serBuf[4] == 0);
|
||||
// Transaction Seq Number
|
||||
|
Reference in New Issue
Block a user