/* * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __FLASH_JOURNAL_H__ #define __FLASH_JOURNAL_H__ #ifdef __cplusplus extern "C" { #endif // __cplusplus #include "storage_abstraction/Driver_Storage.h" /** * General return codes. All Flash-Journal APIs return an int32_t to allow for * both error and success status returns. This enumeration contains all * possible error status values. */ typedef enum _FlashJournal_Status { JOURNAL_STATUS_OK = 0, JOURNAL_STATUS_ERROR = -1, ///< Unspecified error JOURNAL_STATUS_BUSY = -2, ///< Underlying storage is currently unavailable JOURNAL_STATUS_TIMEOUT = -3, ///< Timeout occurred JOURNAL_STATUS_UNSUPPORTED = -4, ///< Operation not supported JOURNAL_STATUS_PARAMETER = -5, ///< Parameter error JOURNAL_STATUS_BOUNDED_CAPACITY = -6, ///< Attempt to write larger than available capacity JOURNAL_STATUS_STORAGE_API_ERROR = -7, ///< Failure from some Storage API JOURNAL_STATUS_STORAGE_IO_ERROR = -8, ///< Failure from underlying storage during an IO operation. JOURNAL_STATUS_NOT_INITIALIZED = -9, ///< journal not initialized JOURNAL_STATUS_EMPTY = -10, ///< There is no further data to read JOURNAL_STATUS_SMALL_LOG_REQUEST = -11, ///< log request is smaller than the program_unit of the underlying MTD block. JOURNAL_STATUS_NOT_FORMATTED = -12, ///< need to call xxx_format() before using the journal. JOURNAL_STATUS_METADATA_ERROR = -13, ///< sanity checks for the journal metadata failed. JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE = -14, ///< validation or run-time errors arising from the badkend media. } FlashJournal_Status_t; /** * Command opcodes for flash. Completion callbacks use these codes to refer to * completing commands. Refer to \ref ARM_Flash_Callback_t. */ typedef enum _FlashJournal_OpCode { FLASH_JOURNAL_OPCODE_FORMAT, FLASH_JOURNAL_OPCODE_INITIALIZE, FLASH_JOURNAL_OPCODE_GET_INFO, FLASH_JOURNAL_OPCODE_READ_BLOB, FLASH_JOURNAL_OPCODE_LOG_BLOB, FLASH_JOURNAL_OPCODE_COMMIT, FLASH_JOURNAL_OPCODE_RESET, } FlashJournal_OpCode_t; /** * @brief Flash Journal information. This contains journal-metadata, and is the * return value from calling GetInfo() on the journal driver. */ typedef struct _FlashJournal_Info { uint64_t capacity; ///< Maximum capacity (in octets) of the flash journal--i.e. the largest 'blob' which can be contained as payload. uint64_t sizeofJournaledBlob; ///< size (in octets) of the most recently logged blob. uint32_t program_unit; ///< Minimum programming size (in units of octets) for ///< the current storage block--the one which will be used ///< for the next log() operation. This value may change as we ///< cycle through the blocks of the underlying MTD. ///< Callers of FlashJournal_log() should refer to this field ///< upon receiving the error JOURNAL_STATUS_SMALL_LOG_REQUEST ///< (of when the actual amount of data logged is smaller than ///< the requested amount). } FlashJournal_Info_t; static const uint32_t FLASH_JOURNAL_HEADER_MAGIC = 0xA00AEE1DUL; static const uint32_t FLASH_JOURNAL_HEADER_VERSION = 1; /** * Meta-data placed at the head of a Journal. The actual header would be an * extension of this generic header, and would depend on the implementation * strategy. Initialization algorithms can expect to find this generic header at * the start of every Journal. */ typedef struct _FlashJournalHeader { uint32_t magic; /** Journal-header specific magic code */ uint32_t version; /** Revision number for this generic journal header. */ uint64_t totalSize; /** Total space (in bytes) occupied by the journal, including the header. * Both 'mtdOffset' and 'mtdOffset + totalSize' should * lie on erase boundaries. */ uint32_t sizeofHeader; /** The size of the journal header; this is expected to be larger than this generic header. */ uint32_t journalOffset; /** Offset from the start of the journal header to the actual logged journal. */ uint32_t checksum; /** CRC32 over the entire flash-journal-header, including the implementation * specific extension (i.e. over 'sizeofHeader' bytes). The value of the * field is taken to be 0 for the purpose of computing the checksum. */ } FlashJournalHeader_t; /** * This is the type of the command completion callback handler for the * asynchronous flash-journal APIs: initialize(), read(), log(), commit() and * reset() (which is nearly all APIs). * * @param status * A code to indicate the status of the completed operation. For data * transfer operations, the status field is overloaded in case of * success to return the amount of data successfully transferred; this * can be done safely because error codes are negative values. * * @param cmd_code * The command op-code of type FlashJournal_OpCode_t. This value isn't * essential for the callback, but it is expected that this information * could be a quick and useful filter. */ typedef void (*FlashJournal_Callback_t)(int32_t status, FlashJournal_OpCode_t cmd_code); /* forward declarations. */ struct FlashJournal_t; /** * @ref FlashJournal_t is an abstraction implemented by a table of generic * operations (i.e. strategy) together with an opaque, strategy-specific * data. Taken together, the FlashJournal_t is an opaque handle containing * such top-level metadata. * * Algorithms depending on the FlashJournal can be generic (i.e. independent of * the strategy) in their use of the Flash-Journal APIs. For the sake of being * able to allocate a FlashJournal_t for use in such generic algorithms, the * FlashJournal_t contains a MAX_SIZE to accommodate the largest of the * strategy-specific metadata. The value of this MAX_SIZE may need to be * increased if some future journal-strategy needs more metadata. */ #define FLASH_JOURNAL_HANDLE_MAX_SIZE 160 /** * This is the set of operations offered by the flash-journal abstraction. A set * of implementations for these operations defines a logging strategy. */ typedef struct FlashJournal_Ops_t { /** * \brief Initialize the flash journal. Refer to @ref FlashJournal_initialize. */ int32_t (*initialize)(struct FlashJournal_t *journal, ARM_DRIVER_STORAGE *mtd, const struct FlashJournal_Ops_t *ops, FlashJournal_Callback_t callback); /** * \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo. */ FlashJournal_Status_t (*getInfo) (struct FlashJournal_t *journal, FlashJournal_Info_t *info); /** * @brief Read from the most recently logged blob. Refer to @ref FlashJournal_read. */ int32_t (*read) (struct FlashJournal_t *journal, void *buffer, size_t size); /** * @brief Read from the most recently logged blob from a particular offset. Refer to @ref FlashJournal_readFrom. */ int32_t (*readFrom) (struct FlashJournal_t *journal, size_t offset, void *buffer, size_t size); /** * @brief Start logging a new blob or append to the one currently being logged. Refer to @ref FlashJournal_log. */ int32_t (*log) (struct FlashJournal_t *journal, const void *blob, size_t size); /** * @brief commit a blob accumulated through a non-empty sequence of * previously successful log() operations. Refer to @ref FlashJournal_commit. */ int32_t (*commit) (struct FlashJournal_t *journal); /** * @brief Reset the journal. This has the effect of erasing all valid blobs. * Refer to @ref FlashJournal_reset. */ int32_t (*reset) (struct FlashJournal_t *journal); } FlashJournal_Ops_t; /** * @brief An opaque handle constituting the Flash Journal. * * @details This structure is intentionally opaque to avoid exposing data * internal to an implementation strategy; this prevents accesses through any * means other than through the defined API. * * Having a known size for the handle allows the caller to remain malloc-free. * * @note: There should be static asserts in the code to verify our assumption * that the real FlashJournal handle fits within FLASH_JOURNAL_HANDLE_MAX_SIZE * bytes. * * @note: there is a risk of overallocation in case an implementation doesn't * need FLASH_JOURNAL_HANDLE_MAX_SIZE bytes, but the impact should be small. */ typedef struct FlashJournal_t { FlashJournal_Ops_t ops; union { ARM_DRIVER_STORAGE *mtd; FlashJournal_Info_t info; void *pointer; uint8_t octet; uint32_t data[FLASH_JOURNAL_HANDLE_MAX_SIZE / sizeof(uint32_t)]; } opaque; } FlashJournal_t; /** * @brief Initialize a flash journal. * * This is a front-end for @ref FlashJournal_Ops_t::initialize() of the * underlying strategy. * * This function must be called *before* the middle-ware component starts * using a journal. As a part of bringing the journal to a ready state, it * also discovers the most recently logged blob. * * Initialize() receives a callback handler to be invoked upon completion of * asynchronous operations. * * @param [out] journal * A caller-supplied buffer large enough to hold an * initialized journal. The internals of the actual journal * are opaque to the caller and depend on the logging * strategy (as defined by the parameter 'ops'). This memory * should be at least as large as 'FLASH_JOURNAL_HANDLE_MAX_SIZE'. * Upon successful return, the journal is setup in an * initialized state. * * @param [in] mtd * The underlying Storage_Driver targeted by the journal. MTD * stands for Memory-Technology-Device. * * @param [in] ops * This is the set of operations which define the logging strategy. * * @param [in] callback * Caller-defined callback to be invoked upon command completion of * initialization; and also for all future invocations of * asynchronous APIs. Use a NULL pointer when no * callback signals are required. * * @note: this is an asynchronous operation, but it can finish * synchronously if the underlying MTD supports that. * * @return * The function executes in the following ways: * - When the operation is asynchronous, the function only starts the * initialization and control returns to the caller with an * JOURNAL_STATUS_OK before the actual completion of the operation (or * with an appropriate error code in case of failure). When the * operation is completed the command callback is invoked with * 1 passed in as the 'status' parameter of the * callback. In case of errors, the completion callback is invoked with * an error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the actual * completion of the operation or the discovery of a failure condition. In * this case, the function returns 1 to signal successful synchronous * completion or an appropriate error code, and no further * invocation of the completion callback should be expected at a later time. * * @note The user must call an appropriate xxx_format() to format underlying * storage before initializing it for use. If Initialize() is called on * unformatted storage, an error value of JOURNAL_STATUS_NOT_FORMATTED will be * returned. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_initialize(&journal, MTD, &STRATEGY_SEQUENTIAL, callbackHandler); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * ASSERT(returnValue == 1); * // handle synchronous completion * } * \endcode */ static inline int32_t FlashJournal_initialize(FlashJournal_t *journal, ARM_DRIVER_STORAGE *mtd, const FlashJournal_Ops_t *ops, FlashJournal_Callback_t callback) { return ops->initialize(journal, mtd, ops, callback); } /** * @brief Fetch journal metadata. A front-end for @ref FlashJournal_Ops_t::getInfo(). * * @param [in] journal * A previously initialized journal. * * @param [out] info * A caller-supplied buffer capable of being filled in with an * FlashJournal_Info_t. * * @return JOURNAL_STATUS_OK if a FlashJournal_Info_t structure containing * top level metadata about the journal is filled into the supplied * buffer, else an appropriate error value. * * @note It is the caller's responsibility to ensure that the buffer passed in * is able to be initialized with a FlashJournal_Info_t. * * @note getInfo()s can still be called during a sequence of * log()s. * * @note This API returns synchronously--it does not result in an invocation * of a completion callback. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * FlashJournal_Info_t info; * int32_t returnValue = FlashJournal_getInfo(&journal, &info); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else { * ASSERT(returnValue == JOURNAL_STATUS_OK); * // work with the 'info'. * } * \endcode */ static inline FlashJournal_Status_t FlashJournal_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info) { return journal->ops.getInfo(journal, info); } /** * @brief Read from the most recently logged blob. A front-end for @ref * FlashJournal_Ops_t::read(). * * @details Read off a chunk of the logged blob sequentially. The blob may * be larger than the size of the read (or even of available SRAM), so * multiple calls to read() could be necessary before the entire blob is * read off. The journal maintains a read-pointer internally to allow * reads to continue where the previous one left off. * * @note: Once the entire blob is read, the final read() returns the error * JOURNAL_STATUS_EMPTY (or passes that value as the status of a * completion callback) and resets the read-pointer to allow re-reading * the blob from the start. * * @param [in] journal * A previously initialized journal. * * @param [out] buffer * The destination of the read operation. The memory is owned * by the caller and should remain valid for the lifetime * of this operation. * * @param [in] size * The maximum amount of data which can be read in this * operation. The memory pointed to by 'buffer' should be as * large as this amount. * * @return * The function executes in the following ways: * - When the operation is asynchronous--i.e. when the underlying MTD's * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation * executed by the journal in a non-blocking (i.e. asynchronous) manner, * control returns to the caller with JOURNAL_STATUS_OK before the actual * completion of the operation (or with an appropriate error code in case of * failure). When the operation completes, the command callback is * invoked with the number of successfully transferred bytes passed in as * the 'status' parameter of the callback. If any error is encountered * after the launch of an asynchronous operation, the completion callback * is invoked with an error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the * actual completion of the operation, or the discovery of a failure * condition. In synchronous mode, the function returns the number * of data items read or an appropriate error code. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set then this operation may execute asynchronously. In the case of * asynchronous operation, the invocation returns early (with * JOURNAL_STATUS_OK) and results in a completion callback later. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set, the journal is not required to operate asynchronously. A Read * operation can be finished synchronously in spite of * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the * number of data items read to indicate successful completion, or an * appropriate error code. In this case no further invocation of a * completion callback should be expected at a later time. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_read(&journal, buffer, size); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * ASSERT(returnValue == size); * // handle synchronous completion * } * \endcode */ static inline int32_t FlashJournal_read(FlashJournal_t *journal, void *blob, size_t n) { return journal->ops.read(journal, blob, n); } /** * @brief Read from the most recently logged blob at a given offset. A front-end * for @ref FlashJournal_Ops_t::readFrom(). * * @details Read off a chunk of the logged blob from a given offset. The journal * maintains a read-pointer internally to allow reads to continue where the * previous one left off. This call effectively sets the read-counter before * fetching data. Subsequent reads continue sequentially from where the * readFrom() left off. * * @note: If the given offset stands at (or is beyond) the end of the previously * logged blob, readFrom() returns the error JOURNAL_STATUS_EMPTY (or passes * that value as the status of a completion callback) and resets the read- * pointer to allow re-reading the blob from the start. * * @param [in] journal * A previously initialized journal. * * @param [in] offset * The logical offset (within the blob) at which to read data from. * * @param [out] buffer * The destination of the read operation. The memory is owned * by the caller and should remain valid for the lifetime * of this operation. * * @param [in] size * The maximum amount of data which can be read in this * operation. The memory pointed to by 'buffer' should be as * large as this amount. * * @return * The function executes in the following ways: * - When the operation is asynchronous--i.e. when the underlying MTD's * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation * executed by the journal in a non-blocking (i.e. asynchronous) manner, * control returns to the caller with JOURNAL_STATUS_OK before the actual * completion of the operation (or with an appropriate error code in case of * failure). When the operation completes, the command callback is * invoked with the number of successfully transferred bytes passed in as * the 'status' parameter of the callback. If any error is encountered * after the launch of an asynchronous operation, the completion callback * is invoked with an error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the * actual completion of the operation, or the discovery of a failure * condition. In synchronous mode, the function returns the number * of data items read or an appropriate error code. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set then this operation may execute asynchronously. In the case of * asynchronous operation, the invocation returns early (with * JOURNAL_STATUS_OK) and results in a completion callback later. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set, the journal is not required to operate asynchronously. A Read * operation can be finished synchronously in spite of * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the * number of data items read to indicate successful completion, or an * appropriate error code. In this case no further invocation of a * completion callback should be expected at a later time. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_readFrom(&journal, offset, buffer, size); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * ASSERT(returnValue == size); * // handle synchronous completion * } * \endcode */ static inline int32_t FlashJournal_readFrom(struct FlashJournal_t *journal, size_t offset, void *blob, size_t n) { return journal->ops.readFrom(journal, offset, blob, n); } /** * @brief Start logging a new blob or append to the one currently being logged. * A front-end for @ref FlashJournal_Ops_t::log(). * * @details Extend (or start off) the currently logged blob sequentially. * There could be several calls to log() before the entire blob is * accumulated. A sequence of one or more log() must be terminated by a * commit() before the state of the blob is sealed and made persistent. * The journal maintains a log-pointer internally to allow * log()s to continue where the previous one left off. * * @param [in] journal * A previously initialized journal. * * @param [in] blob * The source of the log operation. The memory is owned * by the caller and should remain valid for the lifetime * of this operation. * * @param [in] size * The amount of data being logged in this operation. The * buffer pointed to by 'blob' should be as large as this * amount. * * @return [please be sure to read notes (below) regarding other return values] * The function executes in the following ways: * - When the operation is asynchronous--i.e. when the underlying MTD's * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation * executed by the journal in a non-blocking (i.e. asynchronous) manner, * control returns to the caller with JOURNAL_STATUS_OK before the actual * completion of the operation (or with an appropriate error code in case of * failure). When the operation completes, the command callback is * invoked with the number of successfully transferred bytes passed in as * the 'status' parameter of the callback. If any error is encountered * after the launch of an asynchronous operation, the completion callback * is invoked with an error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the actual * completion of the operation, or the discovery of a failure condition. In * synchronous mode, the function returns the number of data items * logged, or an appropriate error code. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set then this operation may execute asynchronously. In the case of * asynchronous operation, the invocation returns early (with * JOURNAL_STATUS_OK) and results in a completion callback later. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set, the journal is not required to operate asynchronously. A log * operation can be finished synchronously in spite of * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the * number of data items logged to indicate successful completion, or an * appropriate error code. In this case no further invocation of a * completion callback should be expected at a later time. * * @note If a log operation will exceed available capacity, it fails with the * error JOURNAL_STATUS_BOUNDED_CAPACITY. * * @note The actual size of data transfer (as reported by the status * parameter of the callback or the return value from log() in case of * synchronous operation) may be smaller than the amount requested. This * could be due to the 'program_unit' of the underlying storage block-- * i.e. the minimum programmable size. Refer to @ref * FlashJournal_Info_t::program_unit. It is the caller's responsibility * for resubmitting this left-over data in a subsequent call to log. * When logging an arbitrary amount of data, the last of a sequence of * logs may need to be padded in order to align with the * programming unit. * * @note If the total size requested to be logged is smaller * than the MTD's program_unit, log() fails with an error value of * JOURNAL_STATUS_SMALL_LOG_REQUEST. * * @note the data being logged isn't made persistent (or available for read- * backs) until a commit. A sequence of log() operations is expected to end * in a commit(). A new sequence of log()s should be initiated by the caller * only after a commit() has completed. If a sequence of logs() is followed * by an operation other than a commit, that operation will very likely * return an error code. getInfo()s can still be called during a sequence of * log()s. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_log(&journal, buffer, size); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * ASSERT(returnValue <= size); * // handle synchronous completion * * if (returnValue < size) { * #if DEBUG * FlashJournal_Info_t info; * int32_t rc = FlashJournal_getInfo(&journal, &info); * ASSERT(rc == JOURNAL_STATUS_OK); * ASSERT(returnValue == (size - (size % info.program_unit))); * #endif * // move the last (size - returnValue) bytes of the buffer to the * // beginning of the buffer to be used for the successive request. * } * } * \endcode */ static inline int32_t FlashJournal_log(FlashJournal_t *journal, const void *blob, size_t n) { return journal->ops.log(journal, blob, n); } /** * @brief Commit a blob accumulated through a (possibly empty) sequence of previously * successful log() operations. A front-end for @ref FlashJournal_Ops_t::commit(). * * @param [in] journal * A previously initialized journal. * * @return * The function executes in the following ways: * - When the operation is asynchronous--i.e. when the underlying MTD's * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation * executed by the journal in a non-blocking (i.e. asynchronous) manner, * control returns to the caller with JOURNAL_STATUS_OK before the actual * completion of the operation (or with an appropriate error code in case of * failure). When the operation completes, the command callback is invoked * with 1 passed in as the 'status' parameter of the callback to indicate * success. If any error is encountered after the launch of an asynchronous * operation, the completion callback is invoked with an error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the actual * completion of the operation, or the discovery of a failure condition. In * synchronous mode, the function returns 1 to indicate success, or an * appropriate error code. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set then this operation may execute asynchronously. In the case of * asynchronous operation, the invocation returns early (with * JOURNAL_STATUS_OK) and results in a completion callback later. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set, the journal is not required to operate asynchronously. A * commit operation can be finished synchronously in spite of * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the * total size of the committed blob to indicate successful completion, * or an appropriate error code. In this case no further invocation of a * completion callback should be expected at a later time. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_commit(&journal); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * // handle synchronous completion * ASSERT(returnValue == 1); * ... * } * \endcode * * @note A sequence of log() operations is expected to end in a commit(). A new * sequence of log()s should be initiated by the caller only after a * commit() has completed. If a sequence of logs() is followed * by an operation other than a commit, that operation will very likely * return an error code. */ static inline int32_t FlashJournal_commit(FlashJournal_t *journal) { return journal->ops.commit(journal); } /** * @brief Reset the journal. This has the effect of erasing all valid blobs. A * front-end for @ref FlashJournal_Ops_t::reset(). * * @param [in] journal * A previously initialized journal. * * @return * The function executes in the following ways: * - When the operation is asynchronous--i.e. when the underlying MTD's * ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the * operation executed by the journal in a non-blocking (i.e. * asynchronous) manner, control returns to the caller with * JOURNAL_STATUS_OK before the actual completion of the operation (or * with an appropriate error code in case of failure). When the * operation completes, the command callback is invoked with * JOURNAL_STATUS_OK passed in as the 'status' parameter of the * callback. If any error is encountered after the launch of an * asynchronous operation, the completion callback is invoked with an * error status. * - When the operation is executed by the journal in a blocking (i.e. * synchronous) manner, control returns to the caller only upon the * actual completion of the operation, or the discovery of a failure * condition. In synchronous mode, the function returns 1 to signal * successful completion, or an appropriate error code. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set then this operation may execute asynchronously. In the case of * asynchronous operation, the invocation returns early (with * JOURNAL_STATUS_OK) and results in a completion callback later. * * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops * is set, the journal is not required to operate asynchronously. A * reset operation can be finished synchronously in spite of * ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning 1 to * indicate successful completion, or an appropriate error code. In this * case no further invocation of a completion callback should be * expected at a later time. * * Here's a code snippet to suggest how this API might be used by callers: * \code * ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code * int32_t returnValue = FlashJournal_reset(&journal); * if (returnValue < JOURNAL_STATUS_OK) { * // handle error * } else if (returnValue == JOURNAL_STATUS_OK) { * ASSERT(MTD->GetCapabilities().asynchronous_ops == 1); * // handle early return from asynchronous execution * } else { * ASSERT(returnValue == 1); * // handle synchronous completion * } * \endcode */ static inline int32_t FlashJournal_reset(FlashJournal_t *journal) { return journal->ops.reset(journal); } #ifdef __cplusplus } #endif // __cplusplus #endif /* __FLASH_JOURNAL_H__ */