v1.16.0 #323

Merged
muellerr merged 223 commits from develop into main 2022-11-18 14:23:24 +01:00
7 changed files with 316 additions and 202 deletions
Showing only changes of commit e8e3138fba - Show all commits

View File

@ -13,9 +13,14 @@ list yields a list of all related PRs for each release.
# [v1.11.0] # [v1.11.0]
## Fixed
- Host build working again
## Added ## Added
- ACS Subsystem - ACS Subsystem. PR: https://egit.irs.uni-stuttgart.de/eive/eive-obsw/pulls/231
- Custom Gomspace FDIR which disabled most of the default FDIR functionality
- Custom Syrlinks FDIR which disabled most of the default FDIR functionality - Custom Syrlinks FDIR which disabled most of the default FDIR functionality
## Changed ## Changed
@ -26,6 +31,8 @@ list yields a list of all related PRs for each release.
- Add `/usr/local/bin` to PATH. All shell scripts are there now - Add `/usr/local/bin` to PATH. All shell scripts are there now
- Rename GPS device to `/dev/gps0` - Rename GPS device to `/dev/gps0`
- Add Syrlinks and TMP devices to Software by default - Add Syrlinks and TMP devices to Software by default
- Update GPS Linux Hyperion Handler to use socket interface. Still allows switching
back to SHM interface, but the SHM interface is a possible cause of SW crashes
# [v1.10.1] # [v1.10.1]

View File

@ -23,8 +23,9 @@
Q7STestTask::Q7STestTask(object_id_t objectId) : TestTask(objectId) { Q7STestTask::Q7STestTask(object_id_t objectId) : TestTask(objectId) {
doTestSdCard = false; doTestSdCard = false;
doTestScratchApi = false; doTestScratchApi = false;
doTestGps = false; doTestGpsShm = false;
doTestXadc = true; doTestGpsSocket = false;
doTestXadc = false;
} }
ReturnValue_t Q7STestTask::performOneShotAction() { ReturnValue_t Q7STestTask::performOneShotAction() {
@ -36,15 +37,20 @@ ReturnValue_t Q7STestTask::performOneShotAction() {
} }
// testJsonLibDirect(); // testJsonLibDirect();
// testDummyParams(); // testDummyParams();
// testProtHandler(); if (doTestProtHandler) {
testProtHandler();
}
FsOpCodes opCode = FsOpCodes::APPEND_TO_FILE; FsOpCodes opCode = FsOpCodes::APPEND_TO_FILE;
testFileSystemHandlerDirect(opCode); testFileSystemHandlerDirect(opCode);
return TestTask::performOneShotAction(); return TestTask::performOneShotAction();
} }
ReturnValue_t Q7STestTask::performPeriodicAction() { ReturnValue_t Q7STestTask::performPeriodicAction() {
if (doTestGps) { if (doTestGpsShm) {
testGpsDaemon(); testGpsDaemonShm();
}
if (doTestGpsSocket) {
testGpsDaemonSocket();
} }
if (doTestXadc) { if (doTestXadc) {
xadcTest(); xadcTest();
@ -238,8 +244,8 @@ void Q7STestTask::testProtHandler() {
} }
} }
void Q7STestTask::testGpsDaemon() { void Q7STestTask::testGpsDaemonShm() {
gpsmm gpsmm(GPSD_SHARED_MEMORY, 0); gpsmm gpsmm(GPSD_SHARED_MEMORY, "");
gps_data_t* gps; gps_data_t* gps;
gps = gpsmm.read(); gps = gpsmm.read();
if (gps == nullptr) { if (gps == nullptr) {
@ -266,6 +272,69 @@ void Q7STestTask::testGpsDaemon() {
sif::info << "Speed(m/s): " << gps->fix.speed << std::endl; sif::info << "Speed(m/s): " << gps->fix.speed << std::endl;
} }
void Q7STestTask::testGpsDaemonSocket() {
if(gpsmmShmPtr == nullptr) {
gpsmmShmPtr = new gpsmm("localhost", DEFAULT_GPSD_PORT);
}
// The data from the device will generally be read all at once. Therefore, we
// can set all field here
if (not gpsmmShmPtr->is_open()) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "Q7STestTask::testGpsDaemonSocket: Opening GPSMM failed | "
<< "Error " << errno << " | " << gps_errstr(errno) << std::endl;
#endif
gpsNotOpenSwitch = false;
}
return;
}
// Stopwatch watch;
gps_data_t *gps = nullptr;
gpsmmShmPtr->stream(WATCH_ENABLE | WATCH_JSON);
if(not gpsmmShmPtr->waiting(50000000)) {
return;
}
gps = gpsmmShmPtr->read();
if (gps == nullptr) {
if (gpsReadFailedSwitch) {
gpsReadFailedSwitch = false;
sif::warning << "Q7STestTask::testGpsDaemonSocket: Reading GPS data failed"
<< std::endl;
}
return;
}
if (MODE_SET != (MODE_SET & gps->set)) {
if (noModeSetCntr >= 0) {
noModeSetCntr++;
}
if (noModeSetCntr == 10) {
// TODO: Trigger event here
sif::warning << "Q7STestTask::testGpsDaemonSocket: No mode could be "
"read for 10 consecutive reads"
<< std::endl;
noModeSetCntr = -1;
}
return;
} else {
noModeSetCntr = 0;
}
sif::info << "-- Q7STestTask: GPS socket read test --" << std::endl;
#if LIBGPS_VERSION_MINOR <= 17
time_t timeRaw = gps->fix.time;
#else
time_t timeRaw = gps->fix.time.tv_sec;
#endif
std::tm* time = gmtime(&timeRaw);
sif::info << "Time: " << std::put_time(time, "%c %Z") << std::endl;
sif::info << "Visible satellites: " << gps->satellites_visible << std::endl;
sif::info << "Satellites used: " << gps->satellites_used << std::endl;
sif::info << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl;
sif::info << "Latitude: " << gps->fix.latitude << std::endl;
sif::info << "Longitude: " << gps->fix.longitude << std::endl;
}
void Q7STestTask::testFileSystemHandlerDirect(FsOpCodes opCode) { void Q7STestTask::testFileSystemHandlerDirect(FsOpCodes opCode) {
auto fsHandler = ObjectManager::instance()->get<FileSystemHandler>(objects::FILE_SYSTEM_HANDLER); auto fsHandler = ObjectManager::instance()->get<FileSystemHandler>(objects::FILE_SYSTEM_HANDLER);
if (fsHandler == nullptr) { if (fsHandler == nullptr) {

View File

@ -1,6 +1,7 @@
#ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ #ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
#define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ #define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
#include <libgpsmm.h>
#include "test/testtasks/TestTask.h" #include "test/testtasks/TestTask.h"
class CoreController; class CoreController;
@ -14,14 +15,22 @@ class Q7STestTask : public TestTask {
private: private:
bool doTestSdCard = false; bool doTestSdCard = false;
bool doTestScratchApi = false; bool doTestScratchApi = false;
bool doTestGps = false; bool doTestGpsShm = false;
bool doTestGpsSocket = false;
bool doTestProtHandler = false;
bool doTestXadc = false; bool doTestXadc = false;
bool gpsNotOpenSwitch = false;
bool gpsReadFailedSwitch = false;
int32_t noModeSetCntr = 0;
gpsmm* gpsmmShmPtr = nullptr;
CoreController* coreController = nullptr; CoreController* coreController = nullptr;
ReturnValue_t performOneShotAction() override; ReturnValue_t performOneShotAction() override;
ReturnValue_t performPeriodicAction() override; ReturnValue_t performPeriodicAction() override;
void testGpsDaemon(); void testGpsDaemonShm();
void testGpsDaemonSocket();
void testSdCard(); void testSdCard();
void fileTests(); void fileTests();

View File

@ -24,7 +24,10 @@ GPSHyperionLinuxController::GPSHyperionLinuxController(object_id_t objectId, obj
timeUpdateCd.resetTimer(); timeUpdateCd.resetTimer();
} }
GPSHyperionLinuxController::~GPSHyperionLinuxController() {} GPSHyperionLinuxController::~GPSHyperionLinuxController() {
gps_stream(&gps, WATCH_DISABLE, nullptr);
gps_close(&gps);
}
void GPSHyperionLinuxController::performControlOperation() { void GPSHyperionLinuxController::performControlOperation() {
#ifdef FSFW_OSAL_LINUX #ifdef FSFW_OSAL_LINUX
@ -99,6 +102,27 @@ ReturnValue_t GPSHyperionLinuxController::initialize() {
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
auto openError = [&](const char *type, int error) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Opening GPSMM " << type
<< " failed | Error " << error << " | " << gps_errstr(error) << std::endl;
#endif
gpsNotOpenSwitch = false;
}
};
if (readMode == ReadModes::SOCKET) {
int retval = gps_open("localhost", DEFAULT_GPSD_PORT, &gps);
if (retval != 0) {
openError("Socket", retval);
}
} else if (readMode == ReadModes::SHM) {
int retval = gps_open(GPSD_SHARED_MEMORY, "", &gps);
if (retval != 0) {
openError("SHM", retval);
}
}
return result; return result;
} }
@ -107,41 +131,29 @@ ReturnValue_t GPSHyperionLinuxController::handleCommandMessage(CommandMessage *m
} }
#ifdef FSFW_OSAL_LINUX #ifdef FSFW_OSAL_LINUX
void GPSHyperionLinuxController::readGpsDataFromGpsd() {
gpsmm gpsmm("localhost", DEFAULT_GPSD_PORT);
// The data from the device will generally be read all at once. Therefore, we
// can set all field here
if (not gpsmm.is_open()) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Opening GPSMM failed | "
<< "Error " << errno << " | " << gps_errstr(errno) << std::endl;
#endif
gpsNotOpenSwitch = false; void GPSHyperionLinuxController::readGpsDataFromGpsd() {
} auto readError = [&](int error) {
return;
}
// Stopwatch watch;
gps_data_t *gps = nullptr;
gps = gpsmm.stream(WATCH_ENABLE | WATCH_JSON);
if (gps == nullptr) {
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd:: Setting GPSD watch "
"policy failed"
<< std::endl;
}
while (gpsmm.waiting(2000)) {
gps = gpsmm.read();
if (gps == nullptr) {
if (gpsReadFailedSwitch) { if (gpsReadFailedSwitch) {
gpsReadFailedSwitch = false; gpsReadFailedSwitch = false;
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading GPS data failed" sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading GPS data failed | "
<< std::endl; "Error "
<< error << " | " << gps_errstr(error) << std::endl;
} }
};
currentClientBuf = gps_data(&gps);
if (readMode == ReadModes::SOCKET) {
gps_stream(&gps, WATCH_ENABLE | WATCH_JSON, nullptr);
// Exit if no data is seen in 2 seconds (should not happen)
if (not gps_waiting(&gps, 2000000)) {
return; return;
} }
if (MODE_SET != (MODE_SET & gps->set)) { int result = gps_read(&gps);
if (result == -1) {
readError(result);
return;
}
if (MODE_SET != (MODE_SET & gps.set)) {
if (noModeSetCntr >= 0) { if (noModeSetCntr >= 0) {
noModeSetCntr++; noModeSetCntr++;
} }
@ -152,24 +164,31 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
<< std::endl; << std::endl;
noModeSetCntr = -1; noModeSetCntr = -1;
} }
return; }
} else {
noModeSetCntr = 0; noModeSetCntr = 0;
} else if (readMode == ReadModes::SHM) {
int result = gps_read(&gps);
if (result == -1) {
readError(result);
return;
} }
} }
gps = gpsmm.stream(WATCH_DISABLE); handleGpsRead();
}
ReturnValue_t GPSHyperionLinuxController::handleGpsRead() {
PoolReadGuard pg(&gpsSet); PoolReadGuard pg(&gpsSet);
if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) { if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading dataset failed" << std::endl; sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading dataset failed" << std::endl;
#endif #endif
return; return RETURN_FAILED;
} }
bool validFix = false; bool validFix = false;
static_cast<void>(validFix); static_cast<void>(validFix);
// 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix // 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
int newFixMode = gps->fix.mode; int newFixMode = gps.fix.mode;
if (newFixMode == 2 or newFixMode == 3) { if (newFixMode == 2 or newFixMode == 3) {
validFix = true; validFix = true;
} }
@ -177,7 +196,7 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFixMode); triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFixMode);
} }
gpsSet.fixMode.value = newFixMode; gpsSet.fixMode.value = newFixMode;
if (gps->fix.mode == 0 or gps->fix.mode == 1) { if (gps.fix.mode == 0 or gps.fix.mode == 1) {
if (modeCommanded and maxTimeToReachFix.hasTimedOut()) { if (modeCommanded and maxTimeToReachFix.hasTimedOut()) {
// We are supposed to be on and functioning, but not fix was found // We are supposed to be on and functioning, but not fix was found
if (mode == MODE_ON or mode == MODE_NORMAL) { if (mode == MODE_ON or mode == MODE_NORMAL) {
@ -186,51 +205,51 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
modeCommanded = false; modeCommanded = false;
} }
gpsSet.setValidity(false, true); gpsSet.setValidity(false, true);
} else if (gps->satellites_used > 0) { } else if (gps.satellites_used > 0) {
gpsSet.setValidity(true, true); gpsSet.setValidity(true, true);
} }
gpsSet.satInUse.value = gps->satellites_used; gpsSet.satInUse.value = gps.satellites_used;
gpsSet.satInView.value = gps->satellites_visible; gpsSet.satInView.value = gps.satellites_visible;
if (std::isfinite(gps->fix.latitude)) { if (std::isfinite(gps.fix.latitude)) {
// Negative latitude -> South direction // Negative latitude -> South direction
gpsSet.latitude.value = gps->fix.latitude; gpsSet.latitude.value = gps.fix.latitude;
} else { } else {
gpsSet.latitude.setValid(false); gpsSet.latitude.setValid(false);
} }
if (std::isfinite(gps->fix.longitude)) { if (std::isfinite(gps.fix.longitude)) {
// Negative longitude -> West direction // Negative longitude -> West direction
gpsSet.longitude.value = gps->fix.longitude; gpsSet.longitude.value = gps.fix.longitude;
} else { } else {
gpsSet.longitude.setValid(false); gpsSet.longitude.setValid(false);
} }
if (std::isfinite(gps->fix.altitude)) { if (std::isfinite(gps.fix.altitude)) {
gpsSet.altitude.value = gps->fix.altitude; gpsSet.altitude.value = gps.fix.altitude;
} else { } else {
gpsSet.altitude.setValid(false); gpsSet.altitude.setValid(false);
} }
if (std::isfinite(gps->fix.speed)) { if (std::isfinite(gps.fix.speed)) {
gpsSet.speed.value = gps->fix.speed; gpsSet.speed.value = gps.fix.speed;
} else { } else {
gpsSet.speed.setValid(false); gpsSet.speed.setValid(false);
} }
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
gpsSet.unixSeconds.value = gps->fix.time; gpsSet.unixSeconds.value = gps.fix.time;
#else #else
gpsSet.unixSeconds.value = gps->fix.time.tv_sec; gpsSet.unixSeconds.value = gps.fix.time.tv_sec;
#endif #endif
timeval time = {}; timeval time = {};
time.tv_sec = gpsSet.unixSeconds.value; time.tv_sec = gpsSet.unixSeconds.value;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
double fractionalPart = gps->fix.time - std::floor(gps->fix.time); double fractionalPart = gps.fix.time - std::floor(gps.fix.time);
time.tv_usec = fractionalPart * 1000.0 * 1000.0; time.tv_usec = fractionalPart * 1000.0 * 1000.0;
#else #else
time.tv_usec = gps->fix.time.tv_nsec / 1000; time.tv_usec = gps.fix.time.tv_nsec / 1000;
#endif #endif
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
if (time.tv_sec == t) { if (time.tv_sec == t) {
@ -271,26 +290,28 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
if (debugHyperionGps) { if (debugHyperionGps) {
sif::info << "-- Hyperion GPS Data --" << std::endl; sif::info << "-- Hyperion GPS Data --" << std::endl;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
time_t timeRaw = gps->fix.time; time_t timeRaw = gps.fix.time;
#else #else
time_t timeRaw = gps->fix.time.tv_sec; time_t timeRaw = gps.fix.time.tv_sec;
#endif #endif
std::tm *time = gmtime(&timeRaw); std::tm *time = gmtime(&timeRaw);
std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl; std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl;
std::cout << "Visible satellites: " << gps->satellites_visible << std::endl; std::cout << "Visible satellites: " << gps.satellites_visible << std::endl;
std::cout << "Satellites used: " << gps->satellites_used << std::endl; std::cout << "Satellites used: " << gps.satellites_used << std::endl;
std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl; std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps.fix.mode << std::endl;
std::cout << "Latitude: " << gps->fix.latitude << std::endl; std::cout << "Latitude: " << gps.fix.latitude << std::endl;
std::cout << "Longitude: " << gps->fix.longitude << std::endl; std::cout << "Longitude: " << gps.fix.longitude << std::endl;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
std::cout << "Altitude(MSL): " << gps->fix.altitude << std::endl; std::cout << "Altitude(MSL): " << gps.fix.altitude << std::endl;
#else #else
std::cout << "Altitude(MSL): " << gps->fix.altMSL << std::endl; std::cout << "Altitude(MSL): " << gps.fix.altMSL << std::endl;
#endif #endif
std::cout << "Speed(m/s): " << gps->fix.speed << std::endl; std::cout << "Speed(m/s): " << gps.fix.speed << std::endl;
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t); std::tm tm = *std::gmtime(&t);
std::cout << "C Time: " << std::put_time(&tm, "%c") << std::endl; std::cout << "C Time: " << std::put_time(&tm, "%c") << std::endl;
} }
return RETURN_OK;
} }
#endif #endif

View File

@ -24,6 +24,8 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
public: public:
static constexpr uint32_t MAX_SECONDS_TO_REACH_FIX = 60 * 60 * 5; static constexpr uint32_t MAX_SECONDS_TO_REACH_FIX = 60 * 60 * 5;
enum ReadModes { SHM = 0, SOCKET = 1 };
GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId, GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId,
bool debugHyperionGps = false); bool debugHyperionGps = false);
virtual ~GPSHyperionLinuxController(); virtual ~GPSHyperionLinuxController();
@ -47,8 +49,13 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
ReturnValue_t handleGpsRead();
private: private:
GpsPrimaryDataset gpsSet; GpsPrimaryDataset gpsSet;
gps_data_t gps = {};
const char* currentClientBuf = nullptr;
ReadModes readMode = ReadModes::SOCKET;
Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000); Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000);
bool modeCommanded = true; bool modeCommanded = true;
bool timeInit = true; bool timeInit = true;

View File

@ -100,14 +100,9 @@ void PCDUHandler::readCommandQueue() {
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) { result = commandQueue->receiveMessage(&command)) {
result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) {
return;
}
result = poolManager.handleHousekeepingMessage(&command); result = poolManager.handleHousekeepingMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; continue;
} }
} }
} }

View File

@ -11,16 +11,27 @@ def main():
print(f"Running command: {cmd}") print(f"Running command: {cmd}")
result = os.system(cmd) result = os.system(cmd)
if result != 0: if result != 0:
print("") prompt_ssh_key_removal()
print("Removing problematic SSH key and trying again..")
remove_ssh_key_cmd = (
'ssh-keygen -f "${HOME}/.ssh/known_hosts" -R "[localhost]:1535"'
)
os.system(remove_ssh_key_cmd)
print(f'Running command "{cmd}"') print(f'Running command "{cmd}"')
result = os.system(cmd) result = os.system(cmd)
def prompt_ssh_key_removal():
do_remove_key = input("Do you want to remove problematic keys on localhost ([Y]/n)?: ")
if not do_remove_key.lower() in ["y", "yes", "1", ""]:
sys.exit(1)
port = 0
while True:
port = input("Enter port to remove: ")
if not port.isdecimal():
print("Invalid port detected")
else:
break
cmd = f'ssh-keygen -f "${{HOME}}/.ssh/known_hosts" -R "[localhost]:${port}"'
print(f"Removing problematic SSH key with command {cmd}..")
os.system(cmd)
def handle_args(): def handle_args():
help_string = ( help_string = (
"This script copies files to the Q7S as long as port forwarding is active.\n" "This script copies files to the Q7S as long as port forwarding is active.\n"
@ -58,8 +69,7 @@ def handle_args():
) )
# Positional argument(s) # Positional argument(s)
parser.add_argument( parser.add_argument(
"source", help="Source files to copy or target files to copy back to host", "source", help="Source files to copy or target files to copy back to host"
nargs="+"
) )
return parser.parse_args() return parser.parse_args()
@ -72,10 +82,6 @@ def build_cmd(args):
address = "" address = ""
port_args = "" port_args = ""
target = args.target target = args.target
if args.invert and len(args.source) > 1:
print("Multiple source files not allowed for inverse copying")
sys.exit(1)
source_files = " ".join(args.source)
if args.flatsat: if args.flatsat:
address = "eive@flatsat.eive.absatvirt.lw" address = "eive@flatsat.eive.absatvirt.lw"
else: else:
@ -92,9 +98,9 @@ def build_cmd(args):
else: else:
target = args.target target = args.target
if args.invert: if args.invert:
cmd += f"{port_args} {address}:{source_files} {target}" cmd += f"{port_args} {address}:{args.source} {target}"
else: else:
cmd += f"{port_args} {source_files} {address}:{target}" cmd += f"{port_args} {args.source} {address}:{target}"
return cmd return cmd