eive-obsw/bsp_q7s/devices/startracker/StrImageLoader.cpp
2021-12-09 15:02:58 +01:00

249 lines
8.9 KiB
C++

#include "StrImageLoader.h"
#include <fstream>
#include <filesystem>
StrImageLoader::StrImageLoader(object_id_t objectId) : SystemObject(objectId){
}
StrImageLoader::~StrImageLoader() {
}
ReturnValue_t StrImageLoader::initialize() {
sdcMan = SdCardManager::instance();
if (sdcMan == nullptr) {
sif::warning << "StrImageLoader::initialize: Invalid SD Card Manager" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t StrImageLoader::performOperation(uint8_t operationCode) {
ReturnValue_t result = RETURN_OK;
semaphore.acquire();
while(true) {
switch(internalState) {
case InternalState::IDLE: {
semaphore.acquire();
break;
}
case InternalState::UPLOAD_IMAGE: {
result = performImageUpload();
if (result == RETURN_OK){
triggerEvent(IMAGE_UPLOAD_SUCCESSFUL);
}
internalState = InternalState::IDLE;
break;
}
case InternalState::DOWNLOAD_IMAGE:
result = performImageDownload();
if (result == RETURN_OK){
triggerEvent(IMAGE_DOWNLOAD_SUCCESSFUL);
}
internalState = InternalState::IDLE;
break;
}
}
}
void StrImageLoader::setComIF(DeviceCommunicationIF* communicationInterface_) {
communicationInterface = communicationInterface_;
}
void StrImageLoader::setComCookie(CookieIF* comCookie_) {
comCookie = comCookie_;
}
ReturnValue_t StrImageLoader::startImageUpload(std::string image) {
// Check if file is stored on SD card and if associated SD card is mounted
if (image.substr(0, sizeof(SdCardManager::SD_0_MOUNT_POINT))
== std::string(SdCardManager::SD_0_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "StrImageLoader::getImageLocation: SD card 0 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
} else if (image.substr(0, sizeof(SdCardManager::SD_1_MOUNT_POINT))
== std::string(SdCardManager::SD_1_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "StrImageLoader::getImageLocation: SD card 1 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
}
uploadImage = image;
if(not std::filesystem::exists(uploadImage)) {
return FILE_NOT_EXISTS;
}
internalState = InternalState::UPLOAD_IMAGE;
semaphore.release();
return RETURN_OK;
}
void StrImageLoader::startImageDownload(std::string downloadImage_) {
downloadImage = downloadImage_;
internalState = InternalState::DOWNLOAD_IMAGE;
semaphore.release();
}
ReturnValue_t StrImageLoader::performImageDownload() {
ReturnValue_t result;
struct DownloadActionRequest downloadReq;
uint32_t size = 0;
std::ofstream file(downloadImage, std::ios_base::app | std::ios_base::out);
while(downloadReq.position < LAST_POSITION) {
arc_pack_download_action_req(&downloadReq, commandBuffer, &size);
result = sendAndRead(size, downloadReq.position);
if (result != RETURN_OK) {
file.close();
return result;
}
result = checkReply();
if (result != RETURN_OK) {
file.close();
return result;
}
result = checkReplyPosition(downloadReq.position);
if (result != RETURN_OK) {
file.close();
return result;
}
file.write(reinterpret_cast<const char*>(datalinkLayer.getReply() + DATA_OFFSET),
IMAGE_DATA_SIZE);
downloadReq.position++;
}
file.close();
return RETURN_OK;
}
ReturnValue_t StrImageLoader::performImageUpload() {
ReturnValue_t result = RETURN_OK;
uint32_t size = 0;
uint32_t imageSize = 0;
struct UploadActionRequest uploadReq;
uploadReq.position = 0;
std::memset(&uploadReq.data, 0, sizeof(uploadReq.data));
if (not std::filesystem::exists(uploadImage)) {
triggerEvent(IMAGE_FILE_NOT_EXISTS, uploadReq.position);
internalState = InternalState::IDLE;
return RETURN_FAILED;
}
std::ifstream file(uploadImage, std::ifstream::binary);
// Set position of next character to end of file input stream
file.seekg(0, file.end);
// tellg returns position of character in input stream
imageSize = file.tellg();
while((uploadReq.position + 1) * SIZE_IMAGE_PART < imageSize) {
file.seekg(uploadReq.position * SIZE_IMAGE_PART, file.beg);
file.read(reinterpret_cast<char*>(uploadReq.data), SIZE_IMAGE_PART);
arc_pack_upload_action_req(&uploadReq, commandBuffer, &size);
result = sendAndRead(size, uploadReq.position);
if (result != RETURN_OK) {
return RETURN_FAILED;
}
result = checkReply();
if (result != RETURN_OK) {
return result;
}
uploadReq.position++;
}
std::memset(uploadReq.data, 0, sizeof(uploadReq.data));
uint32_t remainder = imageSize - uploadReq.position * SIZE_IMAGE_PART;
file.seekg(uploadReq.position * SIZE_IMAGE_PART, file.beg);
file.read(reinterpret_cast<char*>(uploadReq.data), remainder);
file.close();
uploadReq.position++;
arc_pack_upload_action_req(&uploadReq, commandBuffer, &size);
result = sendAndRead(size, uploadReq.position);
if (result != RETURN_OK) {
return RETURN_FAILED;
}
result = checkReply();
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
ReturnValue_t StrImageLoader::sendAndRead(size_t size, uint32_t position) {
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);
result = communicationInterface->sendMessage(comCookie, datalinkLayer.getEncodedFrame(),
datalinkLayer.getEncodedLength());
if (result != RETURN_OK) {
sif::warning << "StrImageLoader::sendAndRead: Failed to send packet" << std::endl;
triggerEvent(IMG_LOADER_SENDING_PACKET_FAILED, result, position);
return RETURN_FAILED;
}
decResult = ArcsecDatalinkLayer::DEC_IN_PROGRESS;
while (decResult == ArcsecDatalinkLayer::DEC_IN_PROGRESS) {
result = communicationInterface->requestReceiveMessage(comCookie,
StarTracker::MAX_FRAME_SIZE * 2 + 2);
if (result != RETURN_OK) {
sif::warning << "StrImageLoader::sendAndRead: Failed to request reply" << std::endl;
triggerEvent(IMG_LOADER_REQUESTING_MSG_FAILED, result, position);
return RETURN_FAILED;
}
result = communicationInterface->readReceivedMessage(comCookie, &receivedData, &receivedDataLen);
if (result != RETURN_OK) {
sif::warning << "StrImageLoader::sendAndRead: Failed to read received message" << std::endl;
triggerEvent(IMG_LOADER_READING_REPLY_FAILED, result, position);
return RETURN_FAILED;
}
if (receivedDataLen == 0 && missedReplies < MAX_POLLS) {
missedReplies++;
continue;
}
else if ((receivedDataLen == 0) && (missedReplies >= MAX_POLLS)) {
triggerEvent(IMG_LOADER_NO_REPLY, position);
return RETURN_FAILED;
}
else {
missedReplies = 0;
}
decResult = datalinkLayer.decodeFrame(receivedData, receivedDataLen, &bytesLeft);
if (bytesLeft != 0) {
// This should never happen
sif::warning << "StrImageLoader::sendAndRead: Bytes left after decoding" << std::endl;
triggerEvent(IMG_LOADER_COM_ERROR, result, position);
return RETURN_FAILED;
}
}
if (decResult != RETURN_OK) {
triggerEvent(IMG_LOADER_DEC_ERROR, decResult, position);
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t StrImageLoader::checkReply() {
uint8_t type = datalinkLayer.getReplyFrameType();
if (type != TMTC_ACTIONREPLY) {
sif::warning << "StrImageLoader::checkUploadReply: Received reply with invalid type ID"
<< std::endl;
triggerEvent(INVALID_TYPE_ID);
return RETURN_FAILED;
}
uint8_t status = datalinkLayer.getStatusField();
if (status != ArcsecDatalinkLayer::STATUS_OK) {
triggerEvent(STATUS_ERROR);
sif::warning << "StrImageLoader::checkUploadReply: Status failure" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t StrImageLoader::checkReplyPosition(uint32_t expectedPosition) {
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;
}