Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
flash_journal.h
00001 /* 00002 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #ifndef __FLASH_JOURNAL_H__ 00019 #define __FLASH_JOURNAL_H__ 00020 00021 #ifdef __cplusplus 00022 extern "C" { 00023 #endif // __cplusplus 00024 00025 #include "storage_abstraction/Driver_Storage.h" 00026 00027 /** 00028 * General return codes. All Flash-Journal APIs return an int32_t to allow for 00029 * both error and success status returns. This enumeration contains all 00030 * possible error status values. 00031 */ 00032 typedef enum _FlashJournal_Status 00033 { 00034 JOURNAL_STATUS_OK = 0, 00035 JOURNAL_STATUS_ERROR = -1, ///< Unspecified error 00036 JOURNAL_STATUS_BUSY = -2, ///< Underlying storage is currently unavailable 00037 JOURNAL_STATUS_TIMEOUT = -3, ///< Timeout occurred 00038 JOURNAL_STATUS_UNSUPPORTED = -4, ///< Operation not supported 00039 JOURNAL_STATUS_PARAMETER = -5, ///< Parameter error 00040 JOURNAL_STATUS_BOUNDED_CAPACITY = -6, ///< Attempt to write larger than available capacity 00041 JOURNAL_STATUS_STORAGE_API_ERROR = -7, ///< Failure from some Storage API 00042 JOURNAL_STATUS_STORAGE_IO_ERROR = -8, ///< Failure from underlying storage during an IO operation. 00043 JOURNAL_STATUS_NOT_INITIALIZED = -9, ///< journal not initialized 00044 JOURNAL_STATUS_EMPTY = -10, ///< There is no further data to read 00045 JOURNAL_STATUS_SMALL_LOG_REQUEST = -11, ///< log request is smaller than the program_unit of the underlying MTD block. 00046 JOURNAL_STATUS_NOT_FORMATTED = -12, ///< need to call xxx_format() before using the journal. 00047 JOURNAL_STATUS_METADATA_ERROR = -13, ///< sanity checks for the journal metadata failed. 00048 JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE = -14, ///< validation or run-time errors arising from the badkend media. 00049 } FlashJournal_Status_t; 00050 00051 /** 00052 * Command opcodes for flash. Completion callbacks use these codes to refer to 00053 * completing commands. Refer to \ref ARM_Flash_Callback_t. 00054 */ 00055 typedef enum _FlashJournal_OpCode { 00056 FLASH_JOURNAL_OPCODE_FORMAT, 00057 FLASH_JOURNAL_OPCODE_INITIALIZE, 00058 FLASH_JOURNAL_OPCODE_GET_INFO, 00059 FLASH_JOURNAL_OPCODE_READ_BLOB, 00060 FLASH_JOURNAL_OPCODE_LOG_BLOB, 00061 FLASH_JOURNAL_OPCODE_COMMIT, 00062 FLASH_JOURNAL_OPCODE_RESET, 00063 } FlashJournal_OpCode_t; 00064 00065 /** 00066 * @brief Flash Journal information. This contains journal-metadata, and is the 00067 * return value from calling GetInfo() on the journal driver. 00068 */ 00069 typedef struct _FlashJournal_Info { 00070 uint64_t capacity; ///< Maximum capacity (in octets) of the flash journal--i.e. the largest 'blob' which can be contained as payload. 00071 uint64_t sizeofJournaledBlob; ///< size (in octets) of the most recently logged blob. 00072 uint32_t program_unit; ///< Minimum programming size (in units of octets) for 00073 ///< the current storage block--the one which will be used 00074 ///< for the next log() operation. This value may change as we 00075 ///< cycle through the blocks of the underlying MTD. 00076 ///< Callers of FlashJournal_log() should refer to this field 00077 ///< upon receiving the error JOURNAL_STATUS_SMALL_LOG_REQUEST 00078 ///< (of when the actual amount of data logged is smaller than 00079 ///< the requested amount). 00080 } FlashJournal_Info_t; 00081 00082 00083 static const uint32_t FLASH_JOURNAL_HEADER_MAGIC = 0xA00AEE1DUL; 00084 static const uint32_t FLASH_JOURNAL_HEADER_VERSION = 1; 00085 00086 /** 00087 * Meta-data placed at the head of a Journal. The actual header would be an 00088 * extension of this generic header, and would depend on the implementation 00089 * strategy. Initialization algorithms can expect to find this generic header at 00090 * the start of every Journal. 00091 */ 00092 typedef struct _FlashJournalHeader { 00093 uint32_t magic; /** Journal-header specific magic code */ 00094 uint32_t version; /** Revision number for this generic journal header. */ 00095 uint64_t totalSize; /** Total space (in bytes) occupied by the journal, including the header. 00096 * Both 'mtdOffset' and 'mtdOffset + totalSize' should 00097 * lie on erase boundaries. */ 00098 uint32_t sizeofHeader; /** The size of the journal header; this is expected to be larger than this generic header. */ 00099 uint32_t journalOffset; /** Offset from the start of the journal header to the actual logged journal. */ 00100 uint32_t checksum; /** CRC32 over the entire flash-journal-header, including the implementation 00101 * specific extension (i.e. over 'sizeofHeader' bytes). The value of the 00102 * field is taken to be 0 for the purpose of computing the checksum. */ 00103 } FlashJournalHeader_t; 00104 00105 /** 00106 * This is the type of the command completion callback handler for the 00107 * asynchronous flash-journal APIs: initialize(), read(), log(), commit() and 00108 * reset() (which is nearly all APIs). 00109 * 00110 * @param status 00111 * A code to indicate the status of the completed operation. For data 00112 * transfer operations, the status field is overloaded in case of 00113 * success to return the amount of data successfully transferred; this 00114 * can be done safely because error codes are negative values. 00115 * 00116 * @param cmd_code 00117 * The command op-code of type FlashJournal_OpCode_t. This value isn't 00118 * essential for the callback, but it is expected that this information 00119 * could be a quick and useful filter. 00120 */ 00121 typedef void (*FlashJournal_Callback_t)(int32_t status, FlashJournal_OpCode_t cmd_code); 00122 00123 /* forward declarations. */ 00124 struct FlashJournal_t; 00125 00126 /** 00127 * @ref FlashJournal_t is an abstraction implemented by a table of generic 00128 * operations (i.e. strategy) together with an opaque, strategy-specific 00129 * data. Taken together, the FlashJournal_t is an opaque handle containing 00130 * such top-level metadata. 00131 * 00132 * Algorithms depending on the FlashJournal can be generic (i.e. independent of 00133 * the strategy) in their use of the Flash-Journal APIs. For the sake of being 00134 * able to allocate a FlashJournal_t for use in such generic algorithms, the 00135 * FlashJournal_t contains a MAX_SIZE to accommodate the largest of the 00136 * strategy-specific metadata. The value of this MAX_SIZE may need to be 00137 * increased if some future journal-strategy needs more metadata. 00138 */ 00139 #define FLASH_JOURNAL_HANDLE_MAX_SIZE 160 00140 00141 /** 00142 * This is the set of operations offered by the flash-journal abstraction. A set 00143 * of implementations for these operations defines a logging strategy. 00144 */ 00145 00146 typedef struct FlashJournal_Ops_t { 00147 /** 00148 * \brief Initialize the flash journal. Refer to @ref FlashJournal_initialize. 00149 */ 00150 int32_t (*initialize)(struct FlashJournal_t *journal, 00151 ARM_DRIVER_STORAGE *mtd, 00152 const struct FlashJournal_Ops_t *ops, 00153 FlashJournal_Callback_t callback); 00154 00155 /** 00156 * \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo. 00157 */ 00158 FlashJournal_Status_t (*getInfo) (struct FlashJournal_t *journal, FlashJournal_Info_t *info); 00159 00160 /** 00161 * @brief Read from the most recently logged blob. Refer to @ref FlashJournal_read. 00162 */ 00163 int32_t (*read) (struct FlashJournal_t *journal, void *buffer, size_t size); 00164 00165 /** 00166 * @brief Read from the most recently logged blob from a particular offset. Refer to @ref FlashJournal_readFrom. 00167 */ 00168 int32_t (*readFrom) (struct FlashJournal_t *journal, size_t offset, void *buffer, size_t size); 00169 00170 /** 00171 * @brief Start logging a new blob or append to the one currently being logged. Refer to @ref FlashJournal_log. 00172 */ 00173 int32_t (*log) (struct FlashJournal_t *journal, const void *blob, size_t size); 00174 00175 /** 00176 * @brief commit a blob accumulated through a non-empty sequence of 00177 * previously successful log() operations. Refer to @ref FlashJournal_commit. 00178 */ 00179 int32_t (*commit) (struct FlashJournal_t *journal); 00180 00181 /** 00182 * @brief Reset the journal. This has the effect of erasing all valid blobs. 00183 * Refer to @ref FlashJournal_reset. 00184 */ 00185 int32_t (*reset) (struct FlashJournal_t *journal); 00186 } FlashJournal_Ops_t; 00187 00188 /** 00189 * @brief An opaque handle constituting the Flash Journal. 00190 * 00191 * @details This structure is intentionally opaque to avoid exposing data 00192 * internal to an implementation strategy; this prevents accesses through any 00193 * means other than through the defined API. 00194 * 00195 * Having a known size for the handle allows the caller to remain malloc-free. 00196 * 00197 * @note: There should be static asserts in the code to verify our assumption 00198 * that the real FlashJournal handle fits within FLASH_JOURNAL_HANDLE_MAX_SIZE 00199 * bytes. 00200 * 00201 * @note: there is a risk of overallocation in case an implementation doesn't 00202 * need FLASH_JOURNAL_HANDLE_MAX_SIZE bytes, but the impact should be small. 00203 */ 00204 typedef struct FlashJournal_t { 00205 FlashJournal_Ops_t ops; 00206 00207 union { 00208 ARM_DRIVER_STORAGE *mtd; 00209 FlashJournal_Info_t info; 00210 void *pointer; 00211 uint8_t octet; 00212 uint32_t data[FLASH_JOURNAL_HANDLE_MAX_SIZE / sizeof(uint32_t)]; 00213 } opaque; 00214 } FlashJournal_t; 00215 00216 /** 00217 * @brief Initialize a flash journal. 00218 * 00219 * This is a front-end for @ref FlashJournal_Ops_t::initialize() of the 00220 * underlying strategy. 00221 * 00222 * This function must be called *before* the middle-ware component starts 00223 * using a journal. As a part of bringing the journal to a ready state, it 00224 * also discovers the most recently logged blob. 00225 * 00226 * Initialize() receives a callback handler to be invoked upon completion of 00227 * asynchronous operations. 00228 * 00229 * @param [out] journal 00230 * A caller-supplied buffer large enough to hold an 00231 * initialized journal. The internals of the actual journal 00232 * are opaque to the caller and depend on the logging 00233 * strategy (as defined by the parameter 'ops'). This memory 00234 * should be at least as large as 'FLASH_JOURNAL_HANDLE_MAX_SIZE'. 00235 * Upon successful return, the journal is setup in an 00236 * initialized state. 00237 * 00238 * @param [in] mtd 00239 * The underlying Storage_Driver targeted by the journal. MTD 00240 * stands for Memory-Technology-Device. 00241 * 00242 * @param [in] ops 00243 * This is the set of operations which define the logging strategy. 00244 * 00245 * @param [in] callback 00246 * Caller-defined callback to be invoked upon command completion of 00247 * initialization; and also for all future invocations of 00248 * asynchronous APIs. Use a NULL pointer when no 00249 * callback signals are required. 00250 * 00251 * @note: this is an asynchronous operation, but it can finish 00252 * synchronously if the underlying MTD supports that. 00253 * 00254 * @return 00255 * The function executes in the following ways: 00256 * - When the operation is asynchronous, the function only starts the 00257 * initialization and control returns to the caller with an 00258 * JOURNAL_STATUS_OK before the actual completion of the operation (or 00259 * with an appropriate error code in case of failure). When the 00260 * operation is completed the command callback is invoked with 00261 * 1 passed in as the 'status' parameter of the 00262 * callback. In case of errors, the completion callback is invoked with 00263 * an error status. 00264 * - When the operation is executed by the journal in a blocking (i.e. 00265 * synchronous) manner, control returns to the caller only upon the actual 00266 * completion of the operation or the discovery of a failure condition. In 00267 * this case, the function returns 1 to signal successful synchronous 00268 * completion or an appropriate error code, and no further 00269 * invocation of the completion callback should be expected at a later time. 00270 * 00271 * @note The user must call an appropriate xxx_format() to format underlying 00272 * storage before initializing it for use. If Initialize() is called on 00273 * unformatted storage, an error value of JOURNAL_STATUS_NOT_FORMATTED will be 00274 * returned. 00275 * 00276 * Here's a code snippet to suggest how this API might be used by callers: 00277 * \code 00278 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00279 * int32_t returnValue = FlashJournal_initialize(&journal, MTD, &STRATEGY_SEQUENTIAL, callbackHandler); 00280 * if (returnValue < JOURNAL_STATUS_OK) { 00281 * // handle error 00282 * } else if (returnValue == JOURNAL_STATUS_OK) { 00283 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00284 * // handle early return from asynchronous execution 00285 * } else { 00286 * ASSERT(returnValue == 1); 00287 * // handle synchronous completion 00288 * } 00289 * \endcode 00290 */ 00291 static inline int32_t FlashJournal_initialize(FlashJournal_t *journal, 00292 ARM_DRIVER_STORAGE *mtd, 00293 const FlashJournal_Ops_t *ops, 00294 FlashJournal_Callback_t callback) 00295 { 00296 return ops->initialize(journal, mtd, ops, callback); 00297 } 00298 00299 /** 00300 * @brief Fetch journal metadata. A front-end for @ref FlashJournal_Ops_t::getInfo(). 00301 * 00302 * @param [in] journal 00303 * A previously initialized journal. 00304 * 00305 * @param [out] info 00306 * A caller-supplied buffer capable of being filled in with an 00307 * FlashJournal_Info_t. 00308 * 00309 * @return JOURNAL_STATUS_OK if a FlashJournal_Info_t structure containing 00310 * top level metadata about the journal is filled into the supplied 00311 * buffer, else an appropriate error value. 00312 * 00313 * @note It is the caller's responsibility to ensure that the buffer passed in 00314 * is able to be initialized with a FlashJournal_Info_t. 00315 * 00316 * @note getInfo()s can still be called during a sequence of 00317 * log()s. 00318 * 00319 * @note This API returns synchronously--it does not result in an invocation 00320 * of a completion callback. 00321 * 00322 * Here's a code snippet to suggest how this API might be used by callers: 00323 * \code 00324 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00325 * FlashJournal_Info_t info; 00326 * int32_t returnValue = FlashJournal_getInfo(&journal, &info); 00327 * if (returnValue < JOURNAL_STATUS_OK) { 00328 * // handle error 00329 * } else { 00330 * ASSERT(returnValue == JOURNAL_STATUS_OK); 00331 * // work with the 'info'. 00332 * } 00333 * \endcode 00334 */ 00335 static inline FlashJournal_Status_t FlashJournal_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info) 00336 { 00337 return journal->ops.getInfo(journal, info); 00338 } 00339 00340 /** 00341 * @brief Read from the most recently logged blob. A front-end for @ref 00342 * FlashJournal_Ops_t::read(). 00343 * 00344 * @details Read off a chunk of the logged blob sequentially. The blob may 00345 * be larger than the size of the read (or even of available SRAM), so 00346 * multiple calls to read() could be necessary before the entire blob is 00347 * read off. The journal maintains a read-pointer internally to allow 00348 * reads to continue where the previous one left off. 00349 * 00350 * @note: Once the entire blob is read, the final read() returns the error 00351 * JOURNAL_STATUS_EMPTY (or passes that value as the status of a 00352 * completion callback) and resets the read-pointer to allow re-reading 00353 * the blob from the start. 00354 * 00355 * @param [in] journal 00356 * A previously initialized journal. 00357 * 00358 * @param [out] buffer 00359 * The destination of the read operation. The memory is owned 00360 * by the caller and should remain valid for the lifetime 00361 * of this operation. 00362 * 00363 * @param [in] size 00364 * The maximum amount of data which can be read in this 00365 * operation. The memory pointed to by 'buffer' should be as 00366 * large as this amount. 00367 * 00368 * @return 00369 * The function executes in the following ways: 00370 * - When the operation is asynchronous--i.e. when the underlying MTD's 00371 * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation 00372 * executed by the journal in a non-blocking (i.e. asynchronous) manner, 00373 * control returns to the caller with JOURNAL_STATUS_OK before the actual 00374 * completion of the operation (or with an appropriate error code in case of 00375 * failure). When the operation completes, the command callback is 00376 * invoked with the number of successfully transferred bytes passed in as 00377 * the 'status' parameter of the callback. If any error is encountered 00378 * after the launch of an asynchronous operation, the completion callback 00379 * is invoked with an error status. 00380 * - When the operation is executed by the journal in a blocking (i.e. 00381 * synchronous) manner, control returns to the caller only upon the 00382 * actual completion of the operation, or the discovery of a failure 00383 * condition. In synchronous mode, the function returns the number 00384 * of data items read or an appropriate error code. 00385 * 00386 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00387 * is set then this operation may execute asynchronously. In the case of 00388 * asynchronous operation, the invocation returns early (with 00389 * JOURNAL_STATUS_OK) and results in a completion callback later. 00390 * 00391 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00392 * is set, the journal is not required to operate asynchronously. A Read 00393 * operation can be finished synchronously in spite of 00394 * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the 00395 * number of data items read to indicate successful completion, or an 00396 * appropriate error code. In this case no further invocation of a 00397 * completion callback should be expected at a later time. 00398 * 00399 * Here's a code snippet to suggest how this API might be used by callers: 00400 * \code 00401 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00402 * int32_t returnValue = FlashJournal_read(&journal, buffer, size); 00403 * if (returnValue < JOURNAL_STATUS_OK) { 00404 * // handle error 00405 * } else if (returnValue == JOURNAL_STATUS_OK) { 00406 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00407 * // handle early return from asynchronous execution 00408 * } else { 00409 * ASSERT(returnValue == size); 00410 * // handle synchronous completion 00411 * } 00412 * \endcode 00413 */ 00414 static inline int32_t FlashJournal_read(FlashJournal_t *journal, void *blob, size_t n) 00415 { 00416 return journal->ops.read(journal, blob, n); 00417 } 00418 00419 /** 00420 * @brief Read from the most recently logged blob at a given offset. A front-end 00421 * for @ref FlashJournal_Ops_t::readFrom(). 00422 * 00423 * @details Read off a chunk of the logged blob from a given offset. The journal 00424 * maintains a read-pointer internally to allow reads to continue where the 00425 * previous one left off. This call effectively sets the read-counter before 00426 * fetching data. Subsequent reads continue sequentially from where the 00427 * readFrom() left off. 00428 * 00429 * @note: If the given offset stands at (or is beyond) the end of the previously 00430 * logged blob, readFrom() returns the error JOURNAL_STATUS_EMPTY (or passes 00431 * that value as the status of a completion callback) and resets the read- 00432 * pointer to allow re-reading the blob from the start. 00433 * 00434 * @param [in] journal 00435 * A previously initialized journal. 00436 * 00437 * @param [in] offset 00438 * The logical offset (within the blob) at which to read data from. 00439 * 00440 * @param [out] buffer 00441 * The destination of the read operation. The memory is owned 00442 * by the caller and should remain valid for the lifetime 00443 * of this operation. 00444 * 00445 * @param [in] size 00446 * The maximum amount of data which can be read in this 00447 * operation. The memory pointed to by 'buffer' should be as 00448 * large as this amount. 00449 * 00450 * @return 00451 * The function executes in the following ways: 00452 * - When the operation is asynchronous--i.e. when the underlying MTD's 00453 * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation 00454 * executed by the journal in a non-blocking (i.e. asynchronous) manner, 00455 * control returns to the caller with JOURNAL_STATUS_OK before the actual 00456 * completion of the operation (or with an appropriate error code in case of 00457 * failure). When the operation completes, the command callback is 00458 * invoked with the number of successfully transferred bytes passed in as 00459 * the 'status' parameter of the callback. If any error is encountered 00460 * after the launch of an asynchronous operation, the completion callback 00461 * is invoked with an error status. 00462 * - When the operation is executed by the journal in a blocking (i.e. 00463 * synchronous) manner, control returns to the caller only upon the 00464 * actual completion of the operation, or the discovery of a failure 00465 * condition. In synchronous mode, the function returns the number 00466 * of data items read or an appropriate error code. 00467 * 00468 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00469 * is set then this operation may execute asynchronously. In the case of 00470 * asynchronous operation, the invocation returns early (with 00471 * JOURNAL_STATUS_OK) and results in a completion callback later. 00472 * 00473 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00474 * is set, the journal is not required to operate asynchronously. A Read 00475 * operation can be finished synchronously in spite of 00476 * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the 00477 * number of data items read to indicate successful completion, or an 00478 * appropriate error code. In this case no further invocation of a 00479 * completion callback should be expected at a later time. 00480 * 00481 * Here's a code snippet to suggest how this API might be used by callers: 00482 * \code 00483 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00484 * int32_t returnValue = FlashJournal_readFrom(&journal, offset, buffer, size); 00485 * if (returnValue < JOURNAL_STATUS_OK) { 00486 * // handle error 00487 * } else if (returnValue == JOURNAL_STATUS_OK) { 00488 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00489 * // handle early return from asynchronous execution 00490 * } else { 00491 * ASSERT(returnValue == size); 00492 * // handle synchronous completion 00493 * } 00494 * \endcode 00495 */ 00496 static inline int32_t FlashJournal_readFrom(struct FlashJournal_t *journal, size_t offset, void *blob, size_t n) 00497 { 00498 return journal->ops.readFrom(journal, offset, blob, n); 00499 } 00500 00501 /** 00502 * @brief Start logging a new blob or append to the one currently being logged. 00503 * A front-end for @ref FlashJournal_Ops_t::log(). 00504 * 00505 * @details Extend (or start off) the currently logged blob sequentially. 00506 * There could be several calls to log() before the entire blob is 00507 * accumulated. A sequence of one or more log() must be terminated by a 00508 * commit() before the state of the blob is sealed and made persistent. 00509 * The journal maintains a log-pointer internally to allow 00510 * log()s to continue where the previous one left off. 00511 * 00512 * @param [in] journal 00513 * A previously initialized journal. 00514 * 00515 * @param [in] blob 00516 * The source of the log operation. The memory is owned 00517 * by the caller and should remain valid for the lifetime 00518 * of this operation. 00519 * 00520 * @param [in] size 00521 * The amount of data being logged in this operation. The 00522 * buffer pointed to by 'blob' should be as large as this 00523 * amount. 00524 * 00525 * @return [please be sure to read notes (below) regarding other return values] 00526 * The function executes in the following ways: 00527 * - When the operation is asynchronous--i.e. when the underlying MTD's 00528 * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation 00529 * executed by the journal in a non-blocking (i.e. asynchronous) manner, 00530 * control returns to the caller with JOURNAL_STATUS_OK before the actual 00531 * completion of the operation (or with an appropriate error code in case of 00532 * failure). When the operation completes, the command callback is 00533 * invoked with the number of successfully transferred bytes passed in as 00534 * the 'status' parameter of the callback. If any error is encountered 00535 * after the launch of an asynchronous operation, the completion callback 00536 * is invoked with an error status. 00537 * - When the operation is executed by the journal in a blocking (i.e. 00538 * synchronous) manner, control returns to the caller only upon the actual 00539 * completion of the operation, or the discovery of a failure condition. In 00540 * synchronous mode, the function returns the number of data items 00541 * logged, or an appropriate error code. 00542 * 00543 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00544 * is set then this operation may execute asynchronously. In the case of 00545 * asynchronous operation, the invocation returns early (with 00546 * JOURNAL_STATUS_OK) and results in a completion callback later. 00547 * 00548 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00549 * is set, the journal is not required to operate asynchronously. A log 00550 * operation can be finished synchronously in spite of 00551 * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the 00552 * number of data items logged to indicate successful completion, or an 00553 * appropriate error code. In this case no further invocation of a 00554 * completion callback should be expected at a later time. 00555 * 00556 * @note If a log operation will exceed available capacity, it fails with the 00557 * error JOURNAL_STATUS_BOUNDED_CAPACITY. 00558 * 00559 * @note The actual size of data transfer (as reported by the status 00560 * parameter of the callback or the return value from log() in case of 00561 * synchronous operation) may be smaller than the amount requested. This 00562 * could be due to the 'program_unit' of the underlying storage block-- 00563 * i.e. the minimum programmable size. Refer to @ref 00564 * FlashJournal_Info_t::program_unit. It is the caller's responsibility 00565 * for resubmitting this left-over data in a subsequent call to log. 00566 * When logging an arbitrary amount of data, the last of a sequence of 00567 * logs may need to be padded in order to align with the 00568 * programming unit. 00569 * 00570 * @note If the total size requested to be logged is smaller 00571 * than the MTD's program_unit, log() fails with an error value of 00572 * JOURNAL_STATUS_SMALL_LOG_REQUEST. 00573 * 00574 * @note the data being logged isn't made persistent (or available for read- 00575 * backs) until a commit. A sequence of log() operations is expected to end 00576 * in a commit(). A new sequence of log()s should be initiated by the caller 00577 * only after a commit() has completed. If a sequence of logs() is followed 00578 * by an operation other than a commit, that operation will very likely 00579 * return an error code. getInfo()s can still be called during a sequence of 00580 * log()s. 00581 * 00582 * Here's a code snippet to suggest how this API might be used by callers: 00583 * \code 00584 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00585 * int32_t returnValue = FlashJournal_log(&journal, buffer, size); 00586 * if (returnValue < JOURNAL_STATUS_OK) { 00587 * // handle error 00588 * } else if (returnValue == JOURNAL_STATUS_OK) { 00589 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00590 * // handle early return from asynchronous execution 00591 * } else { 00592 * ASSERT(returnValue <= size); 00593 * // handle synchronous completion 00594 * 00595 * if (returnValue < size) { 00596 * #if DEBUG 00597 * FlashJournal_Info_t info; 00598 * int32_t rc = FlashJournal_getInfo(&journal, &info); 00599 * ASSERT(rc == JOURNAL_STATUS_OK); 00600 * ASSERT(returnValue == (size - (size % info.program_unit))); 00601 * #endif 00602 * // move the last (size - returnValue) bytes of the buffer to the 00603 * // beginning of the buffer to be used for the successive request. 00604 * } 00605 * } 00606 * \endcode 00607 */ 00608 static inline int32_t FlashJournal_log(FlashJournal_t *journal, const void *blob, size_t n) 00609 { 00610 return journal->ops.log(journal, blob, n); 00611 } 00612 00613 /** 00614 * @brief Commit a blob accumulated through a (possibly empty) sequence of previously 00615 * successful log() operations. A front-end for @ref FlashJournal_Ops_t::commit(). 00616 * 00617 * @param [in] journal 00618 * A previously initialized journal. 00619 * 00620 * @return 00621 * The function executes in the following ways: 00622 * - When the operation is asynchronous--i.e. when the underlying MTD's 00623 * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation 00624 * executed by the journal in a non-blocking (i.e. asynchronous) manner, 00625 * control returns to the caller with JOURNAL_STATUS_OK before the actual 00626 * completion of the operation (or with an appropriate error code in case of 00627 * failure). When the operation completes, the command callback is invoked 00628 * with 1 passed in as the 'status' parameter of the callback to indicate 00629 * success. If any error is encountered after the launch of an asynchronous 00630 * operation, the completion callback is invoked with an error status. 00631 * - When the operation is executed by the journal in a blocking (i.e. 00632 * synchronous) manner, control returns to the caller only upon the actual 00633 * completion of the operation, or the discovery of a failure condition. In 00634 * synchronous mode, the function returns 1 to indicate success, or an 00635 * appropriate error code. 00636 * 00637 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00638 * is set then this operation may execute asynchronously. In the case of 00639 * asynchronous operation, the invocation returns early (with 00640 * JOURNAL_STATUS_OK) and results in a completion callback later. 00641 * 00642 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00643 * is set, the journal is not required to operate asynchronously. A 00644 * commit operation can be finished synchronously in spite of 00645 * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the 00646 * total size of the committed blob to indicate successful completion, 00647 * or an appropriate error code. In this case no further invocation of a 00648 * completion callback should be expected at a later time. 00649 * 00650 * Here's a code snippet to suggest how this API might be used by callers: 00651 * \code 00652 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00653 * int32_t returnValue = FlashJournal_commit(&journal); 00654 * if (returnValue < JOURNAL_STATUS_OK) { 00655 * // handle error 00656 * } else if (returnValue == JOURNAL_STATUS_OK) { 00657 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00658 * // handle early return from asynchronous execution 00659 * } else { 00660 * // handle synchronous completion 00661 * ASSERT(returnValue == 1); 00662 * ... 00663 * } 00664 * \endcode 00665 * 00666 * @note A sequence of log() operations is expected to end in a commit(). A new 00667 * sequence of log()s should be initiated by the caller only after a 00668 * commit() has completed. If a sequence of logs() is followed 00669 * by an operation other than a commit, that operation will very likely 00670 * return an error code. 00671 */ 00672 static inline int32_t FlashJournal_commit(FlashJournal_t *journal) 00673 { 00674 return journal->ops.commit(journal); 00675 } 00676 00677 /** 00678 * @brief Reset the journal. This has the effect of erasing all valid blobs. A 00679 * front-end for @ref FlashJournal_Ops_t::reset(). 00680 * 00681 * @param [in] journal 00682 * A previously initialized journal. 00683 * 00684 * @return 00685 * The function executes in the following ways: 00686 * - When the operation is asynchronous--i.e. when the underlying MTD's 00687 * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the 00688 * operation executed by the journal in a non-blocking (i.e. 00689 * asynchronous) manner, control returns to the caller with 00690 * JOURNAL_STATUS_OK before the actual completion of the operation (or 00691 * with an appropriate error code in case of failure). When the 00692 * operation completes, the command callback is invoked with 00693 * JOURNAL_STATUS_OK passed in as the 'status' parameter of the 00694 * callback. If any error is encountered after the launch of an 00695 * asynchronous operation, the completion callback is invoked with an 00696 * error status. 00697 * - When the operation is executed by the journal in a blocking (i.e. 00698 * synchronous) manner, control returns to the caller only upon the 00699 * actual completion of the operation, or the discovery of a failure 00700 * condition. In synchronous mode, the function returns 1 to signal 00701 * successful completion, or an appropriate error code. 00702 * 00703 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00704 * is set then this operation may execute asynchronously. In the case of 00705 * asynchronous operation, the invocation returns early (with 00706 * JOURNAL_STATUS_OK) and results in a completion callback later. 00707 * 00708 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops 00709 * is set, the journal is not required to operate asynchronously. A 00710 * reset operation can be finished synchronously in spite of 00711 * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning 1 to 00712 * indicate successful completion, or an appropriate error code. In this 00713 * case no further invocation of a completion callback should be 00714 * expected at a later time. 00715 * 00716 * Here's a code snippet to suggest how this API might be used by callers: 00717 * \code 00718 * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code 00719 * int32_t returnValue = FlashJournal_reset(&journal); 00720 * if (returnValue < JOURNAL_STATUS_OK) { 00721 * // handle error 00722 * } else if (returnValue == JOURNAL_STATUS_OK) { 00723 * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); 00724 * // handle early return from asynchronous execution 00725 * } else { 00726 * ASSERT(returnValue == 1); 00727 * // handle synchronous completion 00728 * } 00729 * \endcode 00730 */ 00731 static inline int32_t FlashJournal_reset(FlashJournal_t *journal) 00732 { 00733 return journal->ops.reset(journal); 00734 } 00735 00736 #ifdef __cplusplus 00737 } 00738 #endif // __cplusplus 00739 00740 #endif /* __FLASH_JOURNAL_H__ */
Generated on Tue Jul 12 2022 13:15:49 by
