eive-obsw/bsp_q7s/devices/startracker/StrHelper.cpp

431 lines
14 KiB
C++
Raw Normal View History

2021-12-21 15:46:09 +01:00
#include "StrHelper.h"
2021-12-11 11:56:47 +01:00
#include "mission/utility/Timestamp.h"
2021-11-30 16:01:02 +01:00
2021-12-06 19:36:21 +01:00
#include <fstream>
2021-11-30 16:01:02 +01:00
#include <filesystem>
2021-12-21 15:46:09 +01:00
StrHelper::StrHelper(object_id_t objectId) : SystemObject(objectId){
2021-11-30 16:01:02 +01:00
}
2021-12-21 15:46:09 +01:00
StrHelper::~StrHelper() {
2021-11-30 16:01:02 +01:00
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::initialize() {
2021-11-30 16:01:02 +01:00
sdcMan = SdCardManager::instance();
if (sdcMan == nullptr) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::initialize: Invalid SD Card Manager" << std::endl;
2021-12-06 19:36:21 +01:00
return RETURN_FAILED;
2021-11-30 16:01:02 +01:00
}
2021-12-06 19:36:21 +01:00
return RETURN_OK;
2021-11-30 16:01:02 +01:00
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::performOperation(uint8_t operationCode) {
2021-12-02 08:05:33 +01:00
ReturnValue_t result = RETURN_OK;
2021-11-30 16:01:02 +01:00
semaphore.acquire();
while(true) {
switch(internalState) {
2021-12-02 08:05:33 +01:00
case InternalState::IDLE: {
2021-11-30 16:01:02 +01:00
semaphore.acquire();
break;
2021-12-02 08:05:33 +01:00
}
case InternalState::UPLOAD_IMAGE: {
2021-12-06 19:36:21 +01:00
result = performImageUpload();
2021-12-02 08:05:33 +01:00
if (result == RETURN_OK){
triggerEvent(IMAGE_UPLOAD_SUCCESSFUL);
}
2021-12-10 10:07:23 +01:00
else {
triggerEvent(IMAGE_UPLOAD_FAILED);
}
2021-12-06 19:36:21 +01:00
internalState = InternalState::IDLE;
2021-11-30 16:01:02 +01:00
break;
2021-12-02 08:05:33 +01:00
}
2021-12-21 15:46:09 +01:00
case InternalState::DOWNLOAD_IMAGE: {
2021-12-09 15:02:58 +01:00
result = performImageDownload();
if (result == RETURN_OK){
triggerEvent(IMAGE_DOWNLOAD_SUCCESSFUL);
}
2021-12-10 10:07:23 +01:00
else {
triggerEvent(IMAGE_DOWNLOAD_FAILED);
}
2021-12-09 15:02:58 +01:00
internalState = InternalState::IDLE;
2021-11-30 16:01:02 +01:00
break;
}
2021-12-21 15:46:09 +01:00
case InternalState::FLASH_WRITE: {
result = performFlashWrite();
if (result == RETURN_OK){
triggerEvent(FLASH_WRITE_SUCCESSFUL);
}
else {
triggerEvent(FLASH_WRITE_FAILED);
}
internalState = InternalState::IDLE;
break;
}
default:
sif::debug << "StrHelper::performOperation: Invalid state" << std::endl;
break;
}
2021-11-30 16:01:02 +01:00
}
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::setComIF(DeviceCommunicationIF* communicationInterface_) {
2021-12-10 10:07:23 +01:00
uartComIF = dynamic_cast<UartComIF*>(communicationInterface_);
if (uartComIF == nullptr) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::initialize: Invalid uart com if" << std::endl;
2021-12-10 10:07:23 +01:00
return RETURN_FAILED;
}
return RETURN_OK;
2021-11-30 16:01:02 +01:00
}
2021-12-21 15:46:09 +01:00
void StrHelper::setComCookie(CookieIF* comCookie_) {
2021-11-30 16:01:02 +01:00
comCookie = comCookie_;
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::startImageUpload(std::string uploadImage_) {
2021-12-11 11:56:47 +01:00
ReturnValue_t result = checkPath(uploadImage_);
if (result != RETURN_OK) {
return result;
2021-11-30 16:01:02 +01:00
}
2021-12-11 11:56:47 +01:00
uploadImage = uploadImage_;
2021-11-30 16:01:02 +01:00
if(not std::filesystem::exists(uploadImage)) {
return FILE_NOT_EXISTS;
}
internalState = InternalState::UPLOAD_IMAGE;
semaphore.release();
2021-12-10 10:07:23 +01:00
terminate = false;
2021-12-06 19:36:21 +01:00
return RETURN_OK;
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::startImageDownload(std::string downloadPath_) {
2021-12-11 11:56:47 +01:00
ReturnValue_t result = checkPath(downloadPath_);
if (result != RETURN_OK) {
return result;
}
if(not std::filesystem::exists(downloadPath_)) {
return PATH_NOT_EXISTS;
}
downloadPath = downloadPath_;
2021-12-09 15:02:58 +01:00
internalState = InternalState::DOWNLOAD_IMAGE;
2021-12-10 10:07:23 +01:00
terminate = false;
2021-12-09 15:02:58 +01:00
semaphore.release();
2021-12-11 11:56:47 +01:00
return RETURN_OK;
2021-12-09 15:02:58 +01:00
}
2021-12-21 15:46:09 +01:00
void StrHelper::stopProcess() {
2021-12-10 10:07:23 +01:00
terminate = true;
}
2021-12-21 15:46:09 +01:00
void StrHelper::setDownloadImageName(std::string image) {
2021-12-11 11:56:47 +01:00
downloadImage = image;
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::startFlashWrite(std::string flashWriteFile_, uint8_t region,
uint32_t flashWriteAddress) {
ReturnValue_t result = checkPath(flashWriteFile_);
if (result != RETURN_OK) {
return result;
}
flashWriteFile = flashWriteFile_;
if(not std::filesystem::exists(flashWriteFile)) {
return FILE_NOT_EXISTS;
}
internalState = InternalState::FLASH_WRITE;
semaphore.release();
terminate = false;
return RETURN_OK;
}
ReturnValue_t StrHelper::performImageDownload() {
2021-12-09 15:02:58 +01:00
ReturnValue_t result;
struct DownloadActionRequest downloadReq;
uint32_t size = 0;
2021-12-10 10:07:23 +01:00
uint32_t retries = 0;
2021-12-11 11:56:47 +01:00
Timestamp timestamp;
std::string image = downloadPath + "/" + timestamp.str() + downloadImage ;
std::ofstream file(image, std::ios_base::app | std::ios_base::out);
if(not std::filesystem::exists(image)) {
return FILE_CREATION_FAILED;
}
2021-12-10 10:07:23 +01:00
downloadReq.position = 0;
2021-12-09 15:02:58 +01:00
while(downloadReq.position < LAST_POSITION) {
2021-12-10 10:07:23 +01:00
if (terminate) {
return RETURN_OK;
}
2021-12-09 15:02:58 +01:00
arc_pack_download_action_req(&downloadReq, commandBuffer, &size);
result = sendAndRead(size, downloadReq.position);
if (result != RETURN_OK) {
2021-12-10 10:07:23 +01:00
if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) {
uartComIF->flushUartRxBuffer(comCookie);
retries++;
continue;
}
2021-12-09 15:02:58 +01:00
file.close();
return result;
}
result = checkReply();
if (result != RETURN_OK) {
2021-12-10 10:07:23 +01:00
if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) {
uartComIF->flushUartRxBuffer(comCookie);
retries++;
continue;
}
2021-12-09 15:02:58 +01:00
file.close();
return result;
}
result = checkReplyPosition(downloadReq.position);
if (result != RETURN_OK) {
2021-12-10 10:07:23 +01:00
if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) {
uartComIF->flushUartRxBuffer(comCookie);
retries++;
continue;
}
2021-12-09 15:02:58 +01:00
file.close();
return result;
}
file.write(reinterpret_cast<const char*>(datalinkLayer.getReply() + DATA_OFFSET),
IMAGE_DATA_SIZE);
downloadReq.position++;
2021-12-10 10:07:23 +01:00
retries = 0;
2021-12-09 15:02:58 +01:00
}
file.close();
2021-12-06 19:36:21 +01:00
return RETURN_OK;
2021-11-30 16:01:02 +01:00
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::performImageUpload() {
2021-12-02 08:05:33 +01:00
ReturnValue_t result = RETURN_OK;
2021-12-09 15:02:58 +01:00
uint32_t size = 0;
2021-12-02 08:05:33 +01:00
uint32_t imageSize = 0;
struct UploadActionRequest uploadReq;
uploadReq.position = 0;
2021-12-06 19:36:21 +01:00
std::memset(&uploadReq.data, 0, sizeof(uploadReq.data));
2021-12-02 08:05:33 +01:00
if (not std::filesystem::exists(uploadImage)) {
2021-12-21 15:46:09 +01:00
triggerEvent(STR_HELPER_FILE_NOT_EXISTS, static_cast<uint32_t>(internalState));
2021-12-06 19:36:21 +01:00
internalState = InternalState::IDLE;
2021-12-02 08:05:33 +01:00
return RETURN_FAILED;
}
std::ifstream file(uploadImage, std::ifstream::binary);
2021-12-06 19:36:21 +01:00
// Set position of next character to end of file input stream
2021-12-02 08:05:33 +01:00
file.seekg(0, file.end);
2021-12-06 19:36:21 +01:00
// tellg returns position of character in input stream
2021-12-02 08:05:33 +01:00
imageSize = file.tellg();
2021-12-09 15:02:58 +01:00
while((uploadReq.position + 1) * SIZE_IMAGE_PART < imageSize) {
2021-12-10 10:07:23 +01:00
if (terminate) {
return RETURN_OK;
}
2021-12-09 15:02:58 +01:00
file.seekg(uploadReq.position * SIZE_IMAGE_PART, file.beg);
2021-12-06 19:36:21 +01:00
file.read(reinterpret_cast<char*>(uploadReq.data), SIZE_IMAGE_PART);
2021-12-09 15:02:58 +01:00
arc_pack_upload_action_req(&uploadReq, commandBuffer, &size);
result = sendAndRead(size, uploadReq.position);
2021-12-06 19:36:21 +01:00
if (result != RETURN_OK) {
return RETURN_FAILED;
}
2021-12-09 15:02:58 +01:00
result = checkReply();
2021-12-06 19:36:21 +01:00
if (result != RETURN_OK) {
return result;
}
uploadReq.position++;
2021-12-02 08:05:33 +01:00
}
2021-12-06 19:36:21 +01:00
std::memset(uploadReq.data, 0, sizeof(uploadReq.data));
2021-12-02 08:05:33 +01:00
uint32_t remainder = imageSize - uploadReq.position * SIZE_IMAGE_PART;
2021-12-09 15:02:58 +01:00
file.seekg(uploadReq.position * SIZE_IMAGE_PART, file.beg);
2021-12-02 08:05:33 +01:00
file.read(reinterpret_cast<char*>(uploadReq.data), remainder);
2021-12-06 19:36:21 +01:00
file.close();
2021-12-02 08:05:33 +01:00
uploadReq.position++;
2021-12-09 15:02:58 +01:00
arc_pack_upload_action_req(&uploadReq, commandBuffer, &size);
result = sendAndRead(size, uploadReq.position);
2021-12-06 19:36:21 +01:00
if (result != RETURN_OK) {
return RETURN_FAILED;
}
2021-12-09 15:02:58 +01:00
result = checkReply();
2021-12-06 19:36:21 +01:00
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::performFlashWrite() {
ReturnValue_t result = RETURN_OK;
uint32_t size = 0;
uint32_t remainingBytes = 0;
uint32_t fileSize = 0;
struct WriteActionRequest req;
if (not std::filesystem::exists(flashWriteFile)) {
triggerEvent(STR_HELPER_FILE_NOT_EXISTS, static_cast<uint32_t>(internalState));
internalState = InternalState::IDLE;
return RETURN_FAILED;
}
std::ifstream file(flashWriteFile, std::ifstream::binary);
file.seekg(0, file.end);
fileSize = file.tellg();
remainingBytes = fileSize;
req.region = flashWriteRegion;
req.address = flashWriteAddress;
req.length = MAX_FLASH_DATA;
while(remainingBytes >= MAX_FLASH_DATA) {
if (terminate) {
return RETURN_OK;
}
file.seekg(fileSize - remainingBytes, file.beg);
file.read(reinterpret_cast<char*>(req.data), MAX_FLASH_DATA);
arc_pack_write_action_req(&req, commandBuffer, &size);
result = sendAndRead(size, req.address);
if (result != RETURN_OK) {
return RETURN_FAILED;
}
result = checkFlashWriteReply(req);
if (result != RETURN_OK) {
return result;
}
remainingBytes = remainingBytes - MAX_FLASH_DATA;
}
file.seekg(fileSize - remainingBytes, file.beg);
file.read(reinterpret_cast<char*>(req.data), remainingBytes);
file.close();
arc_pack_write_action_req(&req, commandBuffer, &size);
result = sendAndRead(size, req.address);
if (result != RETURN_OK) {
return RETURN_FAILED;
}
result = checkFlashWriteReply(req);
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
ReturnValue_t StrHelper::sendAndRead(size_t size, uint32_t parameter) {
2021-12-06 19:36:21 +01:00
ReturnValue_t result = RETURN_OK;
ReturnValue_t decResult = RETURN_OK;
size_t receivedDataLen = 0;
uint8_t *receivedData = nullptr;
size_t bytesLeft = 0;
uint32_t missedReplies = 0;
datalinkLayer.encodeFrame(commandBuffer, size);
2021-12-10 10:07:23 +01:00
result = uartComIF->sendMessage(comCookie, datalinkLayer.getEncodedFrame(),
2021-12-06 19:36:21 +01:00
datalinkLayer.getEncodedLength());
if (result != RETURN_OK) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::sendAndRead: Failed to send packet" << std::endl;
triggerEvent(STR_HELPER_SENDING_PACKET_FAILED, result, parameter);
2021-12-02 08:05:33 +01:00
return RETURN_FAILED;
}
2021-12-06 19:36:21 +01:00
decResult = ArcsecDatalinkLayer::DEC_IN_PROGRESS;
while (decResult == ArcsecDatalinkLayer::DEC_IN_PROGRESS) {
2021-12-10 10:07:23 +01:00
result = uartComIF->requestReceiveMessage(comCookie,
2021-12-06 19:36:21 +01:00
StarTracker::MAX_FRAME_SIZE * 2 + 2);
2021-12-02 08:05:33 +01:00
if (result != RETURN_OK) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::sendAndRead: Failed to request reply" << std::endl;
triggerEvent(STR_HELPER_REQUESTING_MSG_FAILED, result, parameter);
2021-12-02 08:05:33 +01:00
return RETURN_FAILED;
}
2021-12-10 10:07:23 +01:00
result = uartComIF->readReceivedMessage(comCookie, &receivedData, &receivedDataLen);
2021-12-02 08:05:33 +01:00
if (result != RETURN_OK) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::sendAndRead: Failed to read received message" << std::endl;
triggerEvent(STR_HELPER_READING_REPLY_FAILED, result, parameter);
2021-12-06 19:36:21 +01:00
return RETURN_FAILED;
}
if (receivedDataLen == 0 && missedReplies < MAX_POLLS) {
missedReplies++;
continue;
}
else if ((receivedDataLen == 0) && (missedReplies >= MAX_POLLS)) {
2021-12-21 15:46:09 +01:00
triggerEvent(STR_HELPER_NO_REPLY, parameter);
2021-12-06 19:36:21 +01:00
return RETURN_FAILED;
}
else {
missedReplies = 0;
2021-12-02 08:05:33 +01:00
}
2021-12-06 19:36:21 +01:00
decResult = datalinkLayer.decodeFrame(receivedData, receivedDataLen, &bytesLeft);
2021-12-02 08:05:33 +01:00
if (bytesLeft != 0) {
// This should never happen
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::sendAndRead: Bytes left after decoding" << std::endl;
triggerEvent(STR_HELPER_COM_ERROR, result, parameter);
2021-12-02 08:05:33 +01:00
return RETURN_FAILED;
}
}
2021-12-06 19:36:21 +01:00
if (decResult != RETURN_OK) {
2021-12-21 15:46:09 +01:00
triggerEvent(STR_HELPER_DEC_ERROR, decResult, parameter);
2021-12-06 19:36:21 +01:00
return RETURN_FAILED;
}
return RETURN_OK;
}
2021-12-02 08:05:33 +01:00
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::checkReply() {
2021-12-06 19:36:21 +01:00
uint8_t type = datalinkLayer.getReplyFrameType();
if (type != TMTC_ACTIONREPLY) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::checkReply: Received reply with invalid type ID"
2021-12-06 19:36:21 +01:00
<< std::endl;
triggerEvent(INVALID_TYPE_ID);
return RETURN_FAILED;
2021-12-02 08:05:33 +01:00
}
2021-12-06 19:36:21 +01:00
uint8_t status = datalinkLayer.getStatusField();
if (status != ArcsecDatalinkLayer::STATUS_OK) {
triggerEvent(STATUS_ERROR);
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::checkReply: Status failure" << std::endl;
2021-12-06 19:36:21 +01:00
return RETURN_FAILED;
2021-12-02 08:05:33 +01:00
}
2021-12-06 19:36:21 +01:00
return RETURN_OK;
2021-11-30 16:01:02 +01:00
}
2021-12-09 15:02:58 +01:00
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::checkReplyPosition(uint32_t expectedPosition) {
2021-12-09 15:02:58 +01:00
uint32_t receivedPosition = 0;
std::memcpy(&receivedPosition, datalinkLayer.getReply() + POS_OFFSET, sizeof(receivedPosition));
if (receivedPosition != expectedPosition) {
triggerEvent(POSITION_MISMATCH, receivedPosition);
return RETURN_FAILED;
}
return RETURN_OK;
}
2021-12-11 11:56:47 +01:00
2021-12-21 15:46:09 +01:00
ReturnValue_t StrHelper::checkFlashWriteReply(struct WriteActionRequest& req) {
ReturnValue_t result = RETURN_OK;
const uint8_t* data = datalinkLayer.getReply();
uint8_t region = *(data + REGION_OFFSET);
uint32_t address;
const uint8_t* addressData = data + ADDRESS_OFFSET;
size_t size = sizeof(address);
result = SerializeAdapter::deSerialize(&address, &addressData, &size,
SerializeIF::Endianness::LITTLE);
if (result != RETURN_OK) {
sif::warning << "StrHelper::checkFlashWriteReply: Deserialization of address failed"
<< std::endl;
}
uint16_t length;
size = sizeof(length);
const uint8_t* lengthData = data + LENGTH_OFFSET;
result = SerializeAdapter::deSerialize(&length, lengthData, &size,
SerializeIF::Endianness::LITTLE);
if (result != RETURN_OK) {
sif::warning << "StrHelper::checkFlashWriteReply: Deserialization of length failed"
<< std::endl;
}
if (region != req.region) {
return REGION_MISMATCH;
}
if (address != req.address) {
return ADDRESS_MISMATCH;
}
if (region != req.length) {
return LENGTH_MISMATCH;
}
return RETURN_OK;
}
ReturnValue_t StrHelper::checkPath(std::string name) {
2021-12-11 11:56:47 +01:00
if (name.substr(0, sizeof(SdCardManager::SD_0_MOUNT_POINT))
== std::string(SdCardManager::SD_0_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::checkPath: SD card 0 not mounted" << std::endl;
2021-12-11 11:56:47 +01:00
return SD_NOT_MOUNTED;
}
} else if (name.substr(0, sizeof(SdCardManager::SD_1_MOUNT_POINT))
== std::string(SdCardManager::SD_1_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
2021-12-21 15:46:09 +01:00
sif::warning << "StrHelper::checkPath: SD card 1 not mounted" << std::endl;
2021-12-11 11:56:47 +01:00
return SD_NOT_MOUNTED;
}
}
return RETURN_OK;
}