Files
libretiny/cores/common/base/api/lt_ota.h
2023-07-13 12:15:48 +02:00

136 lines
4.0 KiB
C

/* Copyright (c) Kuba Szczodrzyński 2023-03-09. */
#pragma once
#include <libretiny.h>
#include <uf2ota/uf2types.h>
/**
* @brief Chip's OTA type enumeration.
*/
typedef enum {
OTA_TYPE_SINGLE = 0,
OTA_TYPE_DUAL = 1,
OTA_TYPE_FILE = 2,
} lt_ota_type_t;
/**
* @brief OTA update process context.
*/
typedef struct {
uf2_ota_t uf2;
uf2_info_t info;
uint8_t buf[UF2_BLOCK_SIZE]; // block data buffer
uint8_t *buf_pos; // buffer writing position
uint32_t bytes_written; // update progress
uint32_t bytes_total; // total update size
uf2_err_t error; // LT OTA/uf2ota error code
bool running; // whether update has begun
void (*callback)(void *param); // progress callback
void *callback_param; // callback argument
} lt_ota_ctx_t;
/**
* @brief Initialize the update context to begin OTA process.
*
* @param ctx OTA context
* @param size length of the update file; 0 if unknown
*/
void lt_ota_begin(lt_ota_ctx_t *ctx, size_t size);
/**
* @brief Finish the update process. If the update has been written completely,
* try to activate the target image. Free allocated internal structures, regardless
* of the activation result.
*
* @param ctx OTA context
* @return false if activation was attempted and not successful; true otherwise
*/
bool lt_ota_end(lt_ota_ctx_t *ctx);
/**
* @brief Set family-specific, write-protected flash areas in the OTA update context.
* This shouldn't be called manually, as it's done by lt_ota_begin().
*
* @param uf2 uf2ota context
*/
void lt_ota_set_write_protect(uf2_ota_t *uf2);
/**
* @brief Process a chunk of data.
*
* Data is written to the buffer, unless a full UF2 block is already available,
* in which case it's also processed by UF2OTA and written to flash.
*
* It's advised to write in 512-byte chunks (or its multiples).
*
* @param ctx OTA context
* @param data chunk of bytes to process
* @param len size of the chunk
* @return number of bytes correctly processed; should equal 'len' in case of no errors
*/
size_t lt_ota_write(lt_ota_ctx_t *ctx, const uint8_t *data, size_t len);
/**
* @brief Try to write the block. In case of UF2 errors, error code is set in the context.
* Note: use lt_ota_write() instead. This is for internal usage only.
*
* @param block UF2 block to check and write; cannot be NULL
* @return whether no error has occurred
*/
bool lt_ota_write_block(lt_ota_ctx_t *ctx, uf2_block_t *block);
/**
* @brief Get OTA type of the device's chip.
*/
lt_ota_type_t lt_ota_get_type();
/**
* @brief Check if the specified OTA image is valid.
*
* @param index OTA index to check; 0 for single-OTA chips, 1 or 2 for dual-OTA chips
* @return true if index is valid for the chip's OTA type, and there is a valid image; false otherwise
*/
bool lt_ota_is_valid(uint8_t index);
/**
* @brief Check if OTA rollback is possible (switching the stored index to another partition).
*
* Note that this is not the same as "switching" OTA with revert=true.
*
* @return true if 2nd image is valid and the chip is dual-OTA; false otherwise
*/
bool lt_ota_can_rollback();
/**
* @brief Get the currently running firmware's OTA index.
*
* @return OTA index if dual-OTA is supported, 0 otherwise
*/
uint8_t lt_ota_dual_get_current();
/**
* @brief Read the currently active OTA index, i.e. the one that will boot upon restart.
*
* @return OTA index if dual-OTA is supported, 0 otherwise
*/
uint8_t lt_ota_dual_get_stored();
/**
* @brief Check which UF2 OTA scheme should be used for applying firmware updates.
*
* @return OTA scheme of the target partition
*/
uf2_ota_scheme_t lt_ota_get_uf2_scheme();
/**
* @brief Try to switch OTA index to the other image. For single-OTA chips, only check if the upgrade image is valid.
*
* This can be used to "activate" the upgrade after flashing.
*
* @param revert switch if (and only if) the other image is already marked as active (i.e.
* switch back to the running image)
* @return false if the second image (or upgrade image) is not valid; false if writing failed; true otherwise
*/
bool lt_ota_switch(bool revert);