| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title FileDownlink.hpp | ||
| 3 | // \author bocchino, mstarch | ||
| 4 | // \brief hpp file for FileDownlink component implementation class | ||
| 5 | // | ||
| 6 | // \copyright | ||
| 7 | // Copyright 2009-2015, by the California Institute of Technology. | ||
| 8 | // ALL RIGHTS RESERVED. United States Government Sponsorship | ||
| 9 | // acknowledged. | ||
| 10 | // ====================================================================== | ||
| 11 | |||
| 12 | #ifndef Svc_FileDownlink_HPP | ||
| 13 | #define Svc_FileDownlink_HPP | ||
| 14 | |||
| 15 | #include <Fw/FilePacket/FilePacket.hpp> | ||
| 16 | #include <Fw/Types/FileNameString.hpp> | ||
| 17 | #include <Os/File.hpp> | ||
| 18 | #include <Os/Mutex.hpp> | ||
| 19 | #include <Os/Queue.hpp> | ||
| 20 | #include <Os/SandboxedFile.hpp> | ||
| 21 | #include <Svc/FileDownlink/FileDownlinkComponentAc.hpp> | ||
| 22 | #include <config/FileDownlinkCfg.hpp> | ||
| 23 | |||
| 24 | namespace Svc { | ||
| 25 | |||
| 26 | class FileDownlink final : public FileDownlinkComponentBase { | ||
| 27 | friend class FileDownlinkTester; | ||
| 28 | |||
| 29 | private: | ||
| 30 | // ---------------------------------------------------------------------- | ||
| 31 | // Types | ||
| 32 | // ---------------------------------------------------------------------- | ||
| 33 | |||
| 34 | //! The Mode class | ||
| 35 | class Mode { | ||
| 36 | friend class FileDownlinkTester; | ||
| 37 | |||
| 38 | public: | ||
| 39 | //! The Mode type | ||
| 40 | typedef enum { IDLE, DOWNLINK, CANCEL, WAIT, COOLDOWN } Type; | ||
| 41 | |||
| 42 | public: | ||
| 43 | //! Constructor | ||
| 44 | 9 | Mode() : m_value(IDLE) {} | |
| 45 | |||
| 46 | public: | ||
| 47 | //! Set the Mode value | ||
| 48 | 36 | void set(const Type value) { | |
| 49 | 36 | this->m_mutex.lock(); | |
| 50 | 36 | this->m_value = value; | |
| 51 | 36 | this->m_mutex.unLock(); | |
| 52 | 36 | } | |
| 53 | |||
| 54 | //! Get the Mode value | ||
| 55 | 216 | Type get() const { | |
| 56 | 216 | this->m_mutex.lock(); | |
| 57 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
|
216 | const Type value = this->m_value; |
| 58 | 216 | this->m_mutex.unLock(); | |
| 59 | 216 | return value; | |
| 60 | } | ||
| 61 | |||
| 62 | private: | ||
| 63 | //! The Mode value | ||
| 64 | Type m_value; | ||
| 65 | |||
| 66 | //! The Mode mutex | ||
| 67 | mutable Os::Mutex m_mutex; | ||
| 68 | }; | ||
| 69 | |||
| 70 | //! Class representing an outgoing file | ||
| 71 | class File { | ||
| 72 | friend class FileDownlinkTester; | ||
| 73 | |||
| 74 | public: | ||
| 75 | //! Constructor | ||
| 76 |
3/3✓ Branch 7 taken 9 times.
✓ Branch 13 taken 9 times.
✓ Branch 21 taken 9 times.
|
9 | File() : m_size(0) {} |
| 77 | |||
| 78 | private: | ||
| 79 | //! The source file name | ||
| 80 | Fw::LogStringArg m_sourceName; | ||
| 81 | |||
| 82 | //! The destination file name | ||
| 83 | Fw::LogStringArg m_destName; | ||
| 84 | |||
| 85 | //! The underlying OS file (sandboxed to restrict read locations) | ||
| 86 | Os::SandboxedFile m_osFile; | ||
| 87 | |||
| 88 | //! The file size | ||
| 89 | U32 m_size; | ||
| 90 | |||
| 91 | //! The checksum for the file | ||
| 92 | CFDP::Checksum m_checksum; | ||
| 93 | |||
| 94 | public: | ||
| 95 | //! Open the OS file for reading and initialize the checksum | ||
| 96 | Os::File::Status open(const Fw::FileNameString& sourceFileName, //!< The source file name | ||
| 97 | const Fw::FileNameString& destFileName //!< The destination file name | ||
| 98 | ); | ||
| 99 | |||
| 100 | //! Read bytes from the OS file and update the checksum | ||
| 101 | Os::File::Status read(U8* const data, const U32 byteOffset, const U32 size); | ||
| 102 | |||
| 103 | //! Get the checksum | ||
| 104 | 4 | void getChecksum(CFDP::Checksum& checksum) { checksum = this->m_checksum; } | |
| 105 | |||
| 106 | //! Get the source file name | ||
| 107 | 19 | Fw::LogStringArg& getSourceName(void) { return this->m_sourceName; } | |
| 108 | |||
| 109 | //! Get the destination file name | ||
| 110 | 17 | Fw::LogStringArg& getDestName(void) { return this->m_destName; } | |
| 111 | |||
| 112 | //! Configure the allowed read directory for sandboxed file opens | ||
| 113 | 9 | void configureSandbox(const char* directory) { this->m_osFile.configure(directory); } | |
| 114 | |||
| 115 | //! Get the underlying OS file | ||
| 116 | 6 | Os::SandboxedFile& getOsFile(void) { return this->m_osFile; } | |
| 117 | |||
| 118 | //! Get the file size | ||
| 119 | 11 | U32 getSize(void) { return this->m_size; } | |
| 120 | }; | ||
| 121 | |||
| 122 | //! Class to record files sent | ||
| 123 | class FilesSent { | ||
| 124 | friend class FileDownlinkTester; | ||
| 125 | |||
| 126 | public: | ||
| 127 | //! Construct a FilesSent object | ||
| 128 | 9 | FilesSent(FileDownlink* const fileDownlink) : m_sent_file_count(0), m_fileDownlink(fileDownlink) {} | |
| 129 | |||
| 130 | public: | ||
| 131 | //! Record a file sent | ||
| 132 | 4 | void fileSent() { | |
| 133 | 4 | ++this->m_sent_file_count; | |
| 134 |
2/2✓ Branch 8 taken 4 times.
✓ Branch 12 taken 4 times.
|
4 | this->m_fileDownlink->tlmWrite_FilesSent(m_sent_file_count); |
| 135 | 4 | } | |
| 136 | |||
| 137 | private: | ||
| 138 | //! The total number of file sent | ||
| 139 | U32 m_sent_file_count; | ||
| 140 | |||
| 141 | //! The enclosing FileDownlink object | ||
| 142 | FileDownlink* const m_fileDownlink; | ||
| 143 | }; | ||
| 144 | |||
| 145 | //! Class to record packets sent | ||
| 146 | class PacketsSent { | ||
| 147 | friend class FileDownlinkTester; | ||
| 148 | |||
| 149 | public: | ||
| 150 | //! Construct a PacketsSent object | ||
| 151 | 9 | PacketsSent(FileDownlink* const fileDownlink) : m_sent_packet_count(0), m_fileDownlink(fileDownlink) {} | |
| 152 | |||
| 153 | public: | ||
| 154 | //! Record a packet sent | ||
| 155 | 14 | void packetSent() { | |
| 156 | 14 | ++this->m_sent_packet_count; | |
| 157 |
2/2✓ Branch 8 taken 14 times.
✓ Branch 12 taken 14 times.
|
14 | this->m_fileDownlink->tlmWrite_PacketsSent(m_sent_packet_count); |
| 158 | 14 | } | |
| 159 | |||
| 160 | private: | ||
| 161 | //! The total number of downlinked packets | ||
| 162 | U32 m_sent_packet_count; | ||
| 163 | |||
| 164 | //! The enclosing FileDownlink object | ||
| 165 | FileDownlink* const m_fileDownlink; | ||
| 166 | }; | ||
| 167 | |||
| 168 | //! Class to record warnings | ||
| 169 | class Warnings { | ||
| 170 | friend class FileDownlinkTester; | ||
| 171 | |||
| 172 | public: | ||
| 173 | //! Construct a Warnings object | ||
| 174 | 9 | Warnings(FileDownlink* const fileDownlink) : m_warning_count(0), m_fileDownlink(fileDownlink) {} | |
| 175 | |||
| 176 | public: | ||
| 177 | //! Issue a File Open Error warning | ||
| 178 | void fileOpenError(); | ||
| 179 | |||
| 180 | //! Issue a File Read Error warning | ||
| 181 | void fileRead(const Os::File::Status status); | ||
| 182 | |||
| 183 | //! Issue a Zero-Size File warning | ||
| 184 | void zeroSize(); | ||
| 185 | |||
| 186 | //! Issue a Source Out Of Sandbox warning | ||
| 187 | void sourceOutOfSandbox(); | ||
| 188 | |||
| 189 | private: | ||
| 190 | //! Record a warning | ||
| 191 | 2 | void warning() { | |
| 192 | 2 | ++this->m_warning_count; | |
| 193 |
2/2✓ Branch 8 taken 2 times.
✓ Branch 12 taken 2 times.
|
2 | this->m_fileDownlink->tlmWrite_Warnings(m_warning_count); |
| 194 | 2 | } | |
| 195 | |||
| 196 | private: | ||
| 197 | //! The total number of warnings | ||
| 198 | U32 m_warning_count; | ||
| 199 | |||
| 200 | //! The enclosing FileDownlink object | ||
| 201 | FileDownlink* const m_fileDownlink; | ||
| 202 | }; | ||
| 203 | |||
| 204 | //! Sources of send file requests | ||
| 205 | enum CallerSource { COMMAND, PORT }; | ||
| 206 | |||
| 207 | //! Used to track a single file downlink request | ||
| 208 | struct FileEntry { | ||
| 209 | Fw::FileNameString srcFilename; // Name of requested file | ||
| 210 | Fw::FileNameString destFilename; // Name of requested file | ||
| 211 | U32 offset; | ||
| 212 | U32 length; | ||
| 213 | CallerSource source; // Source of the downlink request | ||
| 214 | FwOpcodeType opCode; // Op code of command, only set for CMD sources. | ||
| 215 | U32 cmdSeq; // CmdSeq number, only set for CMD sources. | ||
| 216 | U32 context; // Context id of request, only set for PORT sources. | ||
| 217 | }; | ||
| 218 | |||
| 219 | //! Enumeration for packet types | ||
| 220 | //! Each type has a buffer to store it. | ||
| 221 | enum PacketType { FILE_PACKET, CANCEL_PACKET, COUNT_PACKET_TYPE }; | ||
| 222 | |||
| 223 | public: | ||
| 224 | // ---------------------------------------------------------------------- | ||
| 225 | // Construction, initialization, and destruction | ||
| 226 | // ---------------------------------------------------------------------- | ||
| 227 | |||
| 228 | //! Construct object FileDownlink | ||
| 229 | //! | ||
| 230 | FileDownlink(const char* const compName //!< The component name | ||
| 231 | ); | ||
| 232 | |||
| 233 | //! Configure FileDownlink component | ||
| 234 | //! | ||
| 235 | void configure(U32 cooldown, //!< Cooldown (in ms) between finishing a downlink and starting the next file. | ||
| 236 | U32 cycleTime, //!< Rate at which we are running | ||
| 237 | U32 fileQueueDepth //!< Max number of items in file downlink queue | ||
| 238 | ); | ||
| 239 | |||
| 240 | //! Restrict SendFile / SendPartial reads to paths under the configured directory. | ||
| 241 | //! Fail-open: until called, the sandbox defaults to `/` (any readable path is allowed). | ||
| 242 | void configure(const char* directory); | ||
| 243 | |||
| 244 | //! Cleans up file queue before dispatching to underlying component | ||
| 245 | void deinit(); | ||
| 246 | |||
| 247 | //! Start FileDownlink component | ||
| 248 | //! The component must be configured with configure() before starting. | ||
| 249 | //! | ||
| 250 | void preamble(); | ||
| 251 | |||
| 252 | //! Destroy object FileDownlink | ||
| 253 | //! | ||
| 254 | ~FileDownlink(); | ||
| 255 | |||
| 256 | private: | ||
| 257 | // ---------------------------------------------------------------------- | ||
| 258 | // Handler implementations for user-defined typed input ports | ||
| 259 | // ---------------------------------------------------------------------- | ||
| 260 | |||
| 261 | //! Handler implementation for Run | ||
| 262 | //! | ||
| 263 | void Run_handler(const FwIndexType portNum, //!< The port number | ||
| 264 | U32 context //!< The call order | ||
| 265 | ); | ||
| 266 | |||
| 267 | //! Handler implementation for SendFile | ||
| 268 | //! | ||
| 269 | Svc::SendFileResponse SendFile_handler( | ||
| 270 | const FwIndexType portNum, /*!< The port number*/ | ||
| 271 | const Fw::StringBase& sourceFilename, /*!< Path of file to downlink*/ | ||
| 272 | const Fw::StringBase& destFilename, /*!< Path to store downlinked file at*/ | ||
| 273 | U32 offset, /*!< Amount of data in bytes to downlink from file. 0 to read until end of file*/ | ||
| 274 | U32 length /*!< Amount of data in bytes to downlink from file. 0 to read until end of file*/ | ||
| 275 | ); | ||
| 276 | |||
| 277 | //! Handler implementation for bufferReturn | ||
| 278 | //! | ||
| 279 | void bufferReturn_handler(const FwIndexType portNum, //!< The port number | ||
| 280 | Fw::Buffer& fwBuffer); | ||
| 281 | |||
| 282 | //! Handler implementation for pingIn | ||
| 283 | //! | ||
| 284 | void pingIn_handler(const FwIndexType portNum, /*!< The port number*/ | ||
| 285 | U32 key /*!< Value to return to pinger*/ | ||
| 286 | ); | ||
| 287 | |||
| 288 | private: | ||
| 289 | // ---------------------------------------------------------------------- | ||
| 290 | // Command handler implementations | ||
| 291 | // ---------------------------------------------------------------------- | ||
| 292 | |||
| 293 | //! Implementation for FileDownlink_SendFile command handler | ||
| 294 | //! | ||
| 295 | void SendFile_cmdHandler(const FwOpcodeType opCode, //!< The opcode | ||
| 296 | const U32 cmdSeq, //!< The command sequence number | ||
| 297 | const Fw::CmdStringArg& sourceFilename, //!< The name of the on-board file to send | ||
| 298 | const Fw::CmdStringArg& destFilename //!< The name of the destination file on the ground | ||
| 299 | ); | ||
| 300 | |||
| 301 | //! Implementation for FileDownlink_Cancel command handler | ||
| 302 | //! | ||
| 303 | void Cancel_cmdHandler(const FwOpcodeType opCode, //!< The opcode | ||
| 304 | const U32 cmdSeq //!< The command sequence number | ||
| 305 | ); | ||
| 306 | |||
| 307 | //! Implementation for FILE_DWN_SEND_PARTIAL command handler | ||
| 308 | //! | ||
| 309 | void SendPartial_cmdHandler( | ||
| 310 | FwOpcodeType opCode, //!< The opcode | ||
| 311 | U32 cmdSeq, //!< The command sequence number | ||
| 312 | const Fw::CmdStringArg& sourceFilename, //!< The name of the on-board file to send | ||
| 313 | const Fw::CmdStringArg& destFilename, //!< The name of the destination file on the ground | ||
| 314 | U32 startOffset, //!< Starting offset of the source file | ||
| 315 | U32 length //!< Number of bytes to send from starting offset. Length of 0 implies until the end of the file | ||
| 316 | ); | ||
| 317 | |||
| 318 | private: | ||
| 319 | // ---------------------------------------------------------------------- | ||
| 320 | // Private helper methods | ||
| 321 | // ---------------------------------------------------------------------- | ||
| 322 | |||
| 323 | void sendFile( | ||
| 324 | const Fw::FileNameString& sourceFilename, //!< The name of the on-board file to send | ||
| 325 | const Fw::FileNameString& destFilename, //!< The name of the destination file on the ground | ||
| 326 | U32 startOffset, //!< Starting offset of the source file | ||
| 327 | U32 length //!< Number of bytes to send from starting offset. Length of 0 implies until the end of the file | ||
| 328 | ); | ||
| 329 | |||
| 330 | // Individual packet transfer functions | ||
| 331 | Os::File::Status sendDataPacket(U32& byteOffset); | ||
| 332 | void sendCancelPacket(); | ||
| 333 | void sendEndPacket(); | ||
| 334 | void sendStartPacket(); | ||
| 335 | void sendFilePacket(const Fw::FilePacket& filePacket); | ||
| 336 | |||
| 337 | // State-helper functions | ||
| 338 | void exitFileTransfer(); | ||
| 339 | void enterCooldown(); | ||
| 340 | |||
| 341 | // Function to acquire a buffer internally | ||
| 342 | void getBuffer(Fw::Buffer& buffer, PacketType type); | ||
| 343 | // Downlink the "next" packet | ||
| 344 | void downlinkPacket(); | ||
| 345 | // Finish the file transfer | ||
| 346 | void finishHelper(bool is_cancel); | ||
| 347 | // Convert internal status enum to a command response | ||
| 348 | Fw::CmdResponse statusToCmdResp(SendFileStatus status); | ||
| 349 | // Send response after completing file downlink | ||
| 350 | void sendResponse(SendFileStatus resp); | ||
| 351 | |||
| 352 | private: | ||
| 353 | // ---------------------------------------------------------------------- | ||
| 354 | // Member variables | ||
| 355 | // ---------------------------------------------------------------------- | ||
| 356 | |||
| 357 | //! Whether the configuration function has been called. | ||
| 358 | bool m_configured; | ||
| 359 | |||
| 360 | //! File downlink queue | ||
| 361 | Os::Queue m_fileQueue; | ||
| 362 | |||
| 363 | //! Buffer's memory backing | ||
| 364 | U8 m_memoryStore[COUNT_PACKET_TYPE][FILEDOWNLINK_INTERNAL_BUFFER_SIZE]; | ||
| 365 | |||
| 366 | //! The mode | ||
| 367 | Mode m_mode; | ||
| 368 | |||
| 369 | //! The file | ||
| 370 | File m_file; | ||
| 371 | |||
| 372 | //! Files sent | ||
| 373 | FilesSent m_filesSent; | ||
| 374 | |||
| 375 | //! Packets sent | ||
| 376 | PacketsSent m_packetsSent; | ||
| 377 | |||
| 378 | //! Warnings | ||
| 379 | Warnings m_warnings; | ||
| 380 | |||
| 381 | //! The current sequence index | ||
| 382 | U32 m_sequenceIndex; | ||
| 383 | |||
| 384 | //! Timeout threshold (milliseconds) while in WAIT state | ||
| 385 | U32 m_timeout; | ||
| 386 | |||
| 387 | //! Cooldown (in ms) between finishing a downlink and starting the next file. | ||
| 388 | U32 m_cooldown; | ||
| 389 | |||
| 390 | //! current time residing in WAIT state | ||
| 391 | U32 m_curTimer; | ||
| 392 | |||
| 393 | //! rate (milliseconds) at which we are running | ||
| 394 | U32 m_cycleTime; | ||
| 395 | |||
| 396 | ////! Buffer for sending file data | ||
| 397 | Fw::Buffer m_buffer; | ||
| 398 | |||
| 399 | //! Buffer size for file data | ||
| 400 | U32 m_bufferSize; | ||
| 401 | |||
| 402 | //! Current byte offset in file | ||
| 403 | U32 m_byteOffset; | ||
| 404 | |||
| 405 | //! Amount of bytes left to read | ||
| 406 | U32 m_endOffset; | ||
| 407 | |||
| 408 | //! Set to true when all data packets have been sent | ||
| 409 | Fw::FilePacket::Type m_lastCompletedType; | ||
| 410 | |||
| 411 | //! Last buffer used | ||
| 412 | U32 m_lastBufferId; | ||
| 413 | |||
| 414 | //! Current in progress file entry from queue | ||
| 415 | struct FileEntry m_curEntry; | ||
| 416 | |||
| 417 | //! Incrementing context id used to unique identify a specific downlink request | ||
| 418 | U32 m_cntxId; | ||
| 419 | }; | ||
| 420 | |||
| 421 | } // end namespace Svc | ||
| 422 | |||
| 423 | #endif | ||
| 424 |