#include "StrHelper.h" #include "mission/utility/Timestamp.h" #include #include StrHelper::StrHelper(object_id_t objectId) : SystemObject(objectId){ } StrHelper::~StrHelper() { } ReturnValue_t StrHelper::initialize() { sdcMan = SdCardManager::instance(); if (sdcMan == nullptr) { sif::warning << "StrHelper::initialize: Invalid SD Card Manager" << std::endl; return RETURN_FAILED; } return RETURN_OK; } ReturnValue_t StrHelper::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); } else { triggerEvent(IMAGE_UPLOAD_FAILED); } internalState = InternalState::IDLE; break; } case InternalState::DOWNLOAD_IMAGE: { result = performImageDownload(); if (result == RETURN_OK){ triggerEvent(IMAGE_DOWNLOAD_SUCCESSFUL); } else { triggerEvent(IMAGE_DOWNLOAD_FAILED); } internalState = InternalState::IDLE; break; } case InternalState::FLASH_WRITE: { result = performFlashWrite(); if (result == RETURN_OK){ triggerEvent(FLASH_WRITE_SUCCESSFUL); } else { triggerEvent(FLASH_WRITE_FAILED); } internalState = InternalState::IDLE; break; } case InternalState::FLASH_READ: { result = performFlashRead(); if (result == RETURN_OK){ triggerEvent(FLASH_READ_SUCCESSFUL); } else { triggerEvent(FLASH_READ_FAILED); } internalState = InternalState::IDLE; break; } default: sif::debug << "StrHelper::performOperation: Invalid state" << std::endl; break; } } } ReturnValue_t StrHelper::setComIF(DeviceCommunicationIF* communicationInterface_) { uartComIF = dynamic_cast(communicationInterface_); if (uartComIF == nullptr) { sif::warning << "StrHelper::initialize: Invalid uart com if" << std::endl; return RETURN_FAILED; } return RETURN_OK; } void StrHelper::setComCookie(CookieIF* comCookie_) { comCookie = comCookie_; } ReturnValue_t StrHelper::startImageUpload(std::string uploadImage_) { ReturnValue_t result = checkPath(uploadImage_); if (result != RETURN_OK) { return result; } uploadImage = uploadImage_; if(not std::filesystem::exists(uploadImage)) { return FILE_NOT_EXISTS; } internalState = InternalState::UPLOAD_IMAGE; semaphore.release(); terminate = false; return RETURN_OK; } ReturnValue_t StrHelper::startImageDownload(std::string downloadPath_) { ReturnValue_t result = checkPath(downloadPath_); if (result != RETURN_OK) { return result; } if(not std::filesystem::exists(downloadPath_)) { return PATH_NOT_EXISTS; } downloadPath = downloadPath_; internalState = InternalState::DOWNLOAD_IMAGE; terminate = false; semaphore.release(); return RETURN_OK; } void StrHelper::stopProcess() { terminate = true; } void StrHelper::setDownloadImageName(std::string image) { downloadImage = image; } void StrHelper::setFlashReadFilename(std::string filename) { flashReadFile = filename; } ReturnValue_t StrHelper::startFlashWrite(std::string flashWriteFile_, uint8_t region, uint32_t address) { ReturnValue_t result = checkPath(flashWriteFile_); if (result != RETURN_OK) { return result; } flashWriteFile = flashWriteFile_; if(not std::filesystem::exists(flashWriteFile)) { return FILE_NOT_EXISTS; } flashWriteAddress = address; flashWriteRegion = region; internalState = InternalState::FLASH_WRITE; semaphore.release(); terminate = false; return RETURN_OK; } ReturnValue_t StrHelper::startFlashRead(std::string flashReadPath_, uint8_t region, uint32_t address, uint32_t length) { ReturnValue_t result = checkPath(flashReadPath_); if (result != RETURN_OK) { return result; } flashReadPath = flashReadPath_; if(not std::filesystem::exists(flashReadPath)) { return FILE_NOT_EXISTS; } flashReadAddress = address; flashReadRegion = region; flashReadSize = length; internalState = InternalState::FLASH_READ; semaphore.release(); terminate = false; return RETURN_OK; } ReturnValue_t StrHelper::performImageDownload() { ReturnValue_t result; struct DownloadActionRequest downloadReq; uint32_t size = 0; uint32_t retries = 0; 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; } downloadReq.position = 0; while(downloadReq.position < LAST_POSITION) { if (terminate) { return RETURN_OK; } arc_pack_download_action_req(&downloadReq, commandBuffer, &size); result = sendAndRead(size, downloadReq.position); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } result = checkReply(); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } result = checkReplyPosition(downloadReq.position); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } file.write(reinterpret_cast(datalinkLayer.getReply() + IMAGE_DATA_OFFSET), IMAGE_DATA_SIZE); downloadReq.position++; retries = 0; } file.close(); return RETURN_OK; } ReturnValue_t StrHelper::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(STR_HELPER_FILE_NOT_EXISTS, static_cast(internalState)); 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) { if (terminate) { return RETURN_OK; } 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 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(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(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 = checkFlashActionReply(req.region, req.address, req.length); if (result != RETURN_OK) { return result; } remainingBytes = remainingBytes - MAX_FLASH_DATA; } file.seekg(fileSize - remainingBytes, file.beg); file.read(reinterpret_cast(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 = checkFlashActionReply(req.region, req.address, req.length); if (result != RETURN_OK) { return result; } return RETURN_OK; } ReturnValue_t StrHelper::performFlashRead() { ReturnValue_t result; struct ReadActionRequest req; uint32_t bytesRead = 0; uint32_t size = 0; uint32_t retries = 0; Timestamp timestamp; std::string fullname = flashReadPath + "/" + timestamp.str() + flashReadFile ; std::ofstream file(fullname, std::ios_base::app | std::ios_base::out); if (not std::filesystem::exists(fullname)) { return FILE_CREATION_FAILED; } req.region = flashReadRegion; while(bytesRead < flashReadSize) { if (terminate) { return RETURN_OK; } if ((flashReadSize - bytesRead) < MAX_FLASH_DATA) { req.length = flashReadSize - bytesRead; } else { req.length = MAX_FLASH_DATA; } req.address = flashReadAddress + bytesRead; arc_pack_read_action_req(&req, commandBuffer, &size); result = sendAndRead(size, req.address); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } result = checkReply(); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } result = checkFlashActionReply(req.region, req.address, req.length); if (result != RETURN_OK) { if (retries < CONFIG_MAX_DOWNLOAD_RETRIES) { uartComIF->flushUartRxBuffer(comCookie); retries++; continue; } file.close(); return result; } file.write(reinterpret_cast(datalinkLayer.getReply() + FLASH_READ_DATA_OFFSET), req.length); bytesRead += req.length; retries = 0; } file.close(); return RETURN_OK; } ReturnValue_t StrHelper::sendAndRead(size_t size, uint32_t parameter) { 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 = uartComIF->sendMessage(comCookie, datalinkLayer.getEncodedFrame(), datalinkLayer.getEncodedLength()); if (result != RETURN_OK) { sif::warning << "StrHelper::sendAndRead: Failed to send packet" << std::endl; triggerEvent(STR_HELPER_SENDING_PACKET_FAILED, result, parameter); return RETURN_FAILED; } decResult = ArcsecDatalinkLayer::DEC_IN_PROGRESS; while (decResult == ArcsecDatalinkLayer::DEC_IN_PROGRESS) { result = uartComIF->requestReceiveMessage(comCookie, StarTracker::MAX_FRAME_SIZE * 2 + 2); if (result != RETURN_OK) { sif::warning << "StrHelper::sendAndRead: Failed to request reply" << std::endl; triggerEvent(STR_HELPER_REQUESTING_MSG_FAILED, result, parameter); return RETURN_FAILED; } result = uartComIF->readReceivedMessage(comCookie, &receivedData, &receivedDataLen); if (result != RETURN_OK) { sif::warning << "StrHelper::sendAndRead: Failed to read received message" << std::endl; triggerEvent(STR_HELPER_READING_REPLY_FAILED, result, parameter); return RETURN_FAILED; } if (receivedDataLen == 0 && missedReplies < MAX_POLLS) { missedReplies++; continue; } else if ((receivedDataLen == 0) && (missedReplies >= MAX_POLLS)) { triggerEvent(STR_HELPER_NO_REPLY, parameter); return RETURN_FAILED; } else { missedReplies = 0; } decResult = datalinkLayer.decodeFrame(receivedData, receivedDataLen, &bytesLeft); if (bytesLeft != 0) { // This should never happen sif::warning << "StrHelper::sendAndRead: Bytes left after decoding" << std::endl; triggerEvent(STR_HELPER_COM_ERROR, result, parameter); return RETURN_FAILED; } } if (decResult != RETURN_OK) { triggerEvent(STR_HELPER_DEC_ERROR, decResult, parameter); return RETURN_FAILED; } return RETURN_OK; } ReturnValue_t StrHelper::checkReply() { uint8_t type = datalinkLayer.getReplyFrameType(); if (type != TMTC_ACTIONREPLY) { sif::warning << "StrHelper::checkReply: Received reply with invalid type ID" << std::endl; return INVALID_TYPE_ID; } uint8_t status = datalinkLayer.getStatusField(); if (status != ArcsecDatalinkLayer::STATUS_OK) { sif::warning << "StrHelper::checkReply: Status failure: " << static_cast(status) << std::endl; return STATUS_ERROR; } return RETURN_OK; } ReturnValue_t StrHelper::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; } ReturnValue_t StrHelper::checkFlashActionReply(uint8_t region_, uint32_t address_, uint16_t length_) { ReturnValue_t result = RETURN_OK; result = checkReply(); if (result != RETURN_OK) { return result; } 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::checkFlashActionReply: 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::checkFlashActionReply: Deserialization of length failed" << std::endl; } if (region != region_) { return REGION_MISMATCH; } if (address != address_) { return ADDRESS_MISMATCH; } if (length != length_) { return LENGTH_MISMATCH; } return RETURN_OK; } ReturnValue_t StrHelper::checkPath(std::string name) { if (name.substr(0, sizeof(SdCardManager::SD_0_MOUNT_POINT)) == std::string(SdCardManager::SD_0_MOUNT_POINT)) { if (!sdcMan->isSdCardMounted(sd::SLOT_0)) { sif::warning << "StrHelper::checkPath: SD card 0 not mounted" << std::endl; 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)) { sif::warning << "StrHelper::checkPath: SD card 1 not mounted" << std::endl; return SD_NOT_MOUNTED; } } return RETURN_OK; }