#include "StrImageLoader.h" #include #include 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(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(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(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; }