/*
 * Copyright 2024 Google LLC
 *
 * 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.
 */

#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#define FW_METADATA_CURRENT_STRUCT_VERSION 0x1
#define FW_METADATA_VERSION_SHORT_BYTES 8
#define FW_METADATA_VERSION_TAG_BYTES 32

typedef enum {
  FirmwareMetadataPlatformUnknown = 0,
  FirmwareMetadataPlatformPebbleOneEV1 = 1,
  FirmwareMetadataPlatformPebbleOneEV2 = 2,
  FirmwareMetadataPlatformPebbleOneEV2_3 = 3,
  FirmwareMetadataPlatformPebbleOneEV2_4 = 4,
  FirmwareMetadataPlatformPebbleOnePointFive = 5,
  FirmwareMetadataPlatformPebbleTwoPointZero = 6,
  FirmwareMetadataPlatformPebbleOneBigboard = 0xff,
  FirmwareMetadataPlatformPebbleOneBigboard2 = 0xfe,
} FirmwareMetadataPlatform;

// WARNING: changes in this struct must be reflected in:
// - iOS/PebblePrivateKit/PebblePrivateKit/PBBundle.m

struct FirmwareMetadata {
  uint32_t version_timestamp;
  char version_tag[FW_METADATA_VERSION_TAG_BYTES];
  char version_short[FW_METADATA_VERSION_SHORT_BYTES];
  const bool is_recovery_firmware;
  const uint8_t hw_platform;
  const uint8_t metadata_version; //!< This should be the last field, since we put the meta data struct at the end of the fw binary.
} __attribute__((__packed__));
typedef struct FirmwareMetadata FirmwareMetadata;

extern const FirmwareMetadata TINTIN_METADATA;

//! Copies the version metadata of the running firmware in the provided struct.
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
//! @returns true if it successfully copied the version metadata.
bool version_copy_running_fw_metadata(FirmwareMetadata *out_metadata);

//! Copies the version metadata of the recovery firmware in the provided struct.
//! If there is no valid metadata available, the struct will be wiped to be all zeroes.
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
//! @returns true if it successfully copied the version metadata.
bool version_copy_recovery_fw_metadata(FirmwareMetadata *out_metadata);

//! Copies the version metadata of the update firmware located in
//! FLASH_REGION_FIRMWARE_SCRATCH_BEGIN into the provided struct.
//! If there is no valid metadata available, the struct will be wiped to be all zeroes.
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
//! @returns true if it successfully copied the version metadata.
bool version_copy_update_fw_metadata(FirmwareMetadata *out_metadata);

//! Read recovery version_short from flash and copy to dest; copy at most
//! dest_len_bytes - 1 before being null-terminated via strncpy()
//!
//! @param dest: char[dest_len_bytes]
//! @returns true on success, false otherwise
bool version_copy_recovery_fw_version(char* dest, const int dest_len_bytes);

//! Checks to see if a valid PRF is installed with a correct checksum.
//! @return true if a PRF is installed, false otherwise.
bool version_is_prf_installed(void);

//! @return Pointer to the GNU build id data. This is a hash of the firmware
//! that is generated by the linker and uniquely identifies the binary.
//! @param[out] out_len The length of the build id in bytes.
const uint8_t * version_get_build_id(size_t *out_len);

//! Copies a hex C-string of the build id into the supplied buffer.
//! Get the build id from an elf, using `arm-none-eabi-readelf -n tintin_fw.elf`
//! @param[out] buffer The buffer into which the string should be copied.
//! @param max_length The length of buffer.
void version_copy_build_id_hex_string(char *buffer, size_t max_length);

//! Checks the firmware stored in FLASH_REGION_FIRMWARE_SCRATCH_BEGIN and compares it to the
//! currently running firmware.
//! @returns true if a downgrade is detected.
bool version_fw_downgrade_detected(void);
