// Copyright 2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <quadflashlib.h>
#include <stdint.h>
#include <unity.h>

// First page of dummy project bin file
uint8_t page_buffer[256] = {
    0x11, 0xAF, 0x7A, 0xC0, 0x99, 0x19, 0x3A, 0xAF, 0x83, 0xB3, 0x5A, 0x4C, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x43, 0x00,
    0x00, 0x10, 0x00, 0x00, 0x00, 0x0E, 0x43, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x30, 0xF0, 0x50, 0x08,
    0x00, 0x00, 0x00, 0xB4, 0x90, 0x00, 0x00, 0xCA, 0x52, 0x00, 0x00, 0x20, 0x00, 0x20, 0x08, 0x9C, 0x30, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x0D, 0x43, 0x00, 0x00, 0x20, 0x00, 0x30, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x04, 0x77, 0x04,
    0xF7, 0xC8, 0x19, 0x04, 0x06, 0x08, 0x46, 0x20, 0x0F, 0xC8, 0x9D, 0xBF, 0x73, 0x20, 0x0F, 0x9B, 0x9D, 0xBE, 0x73,
    0x00, 0x0F, 0x18, 0xF6, 0x00, 0x0F, 0x44, 0x77, 0x10, 0x45, 0x24, 0x45, 0x38, 0x45, 0x20, 0x0F, 0xDA, 0x9D, 0xC8,
    0x19, 0x04, 0x86, 0x00, 0x0F, 0x28, 0xC6, 0x00, 0x0F, 0x57, 0x0D, 0x11, 0x0F, 0x82, 0x06, 0x04, 0x86, 0x00, 0x0F,
    0x38, 0xC6, 0x00, 0x0F, 0xE6, 0x0D, 0x00, 0x0F, 0x07, 0x0D, 0x00, 0x0F, 0x6C, 0xA6, 0x8C, 0xAE, 0xFC, 0xAE, 0x00,
    0x0F, 0x60, 0x0D, 0x10, 0xF5, 0x24, 0xF5, 0x4C, 0xF5, 0x38, 0xF5, 0x0C, 0x77, 0x00, 0x00, 0xFF, 0x71, 0x28, 0xF7,
    0x11, 0x0F, 0x72, 0x85, 0x00, 0x0F, 0x10, 0x87, 0x00, 0x0F, 0x10, 0x77, 0x01, 0x0F, 0xE0, 0x85, 0x00, 0x0F, 0x20,
    0x87, 0x01, 0x0F, 0xF0, 0x85, 0x00, 0x0F, 0x57, 0x2D,
};

void setUp() {}
void tearDown() {}

/* copied out of quadflashlib.h */
#define NIBBLE_SWAP_INT(X) (((X & 0x0f0f0f0f) << 4) | ((X & 0xf0f0f0f0) >> 4))
#define IMAGETAG_15_2 (0x0CA7FA11)

#define IMAGE_PAGE_SIZE 64
#define IMAGE_HEADER_SIZE 7
#define IMAGE_HEADER_SECURE_OFFSET 3

#define IMAGETAG_OFFSET 0
#define IMAGESIZE_OFFSET 3
#define IMAGESIZE_OFFSET_13 4
#define IMAGEVERSION_OFFSET 4
#define IMAGEVERSION_OFFSET_13 5
#define TOOLSVERSION_OFFSET_15_2 13

#define CRC_START_OFFSET_12 4
#define CRC_START_OFFSET_13 3
#define PAGE_CRC_OFFSET 1
#define TOOLS12_EXTRA_SKIP 1

/* Jury rig access to CRC function in flash library */
unsigned int fl_CalcCRC(unsigned int*, unsigned int, unsigned int);

void test_flash_image_info_reports_OK(void) {
  fl_BootImageInfo boot_image_info;
  int status = fl_getImageInfo(&boot_image_info, page_buffer);

  TEST_ASSERT_EQUAL(0, status);
  printf("Image size: %u\n", boot_image_info.size);
}

/*
 * These tests exist because fl_getImageInfo() only returns 1 regardless of failure result,
 * which can be tag check failed or CRC failed.
 */

void test_tag_is_correct(void) {
  unsigned* header = (unsigned*)page_buffer;

  unsigned int tag = NIBBLE_SWAP_INT(header[IMAGETAG_OFFSET]);
  TEST_ASSERT_EQUAL(IMAGETAG_15_2, tag);
}

void test_crc_is_correct(void) {
  unsigned* header = (unsigned*)page_buffer;

  unsigned int page_crc = fl_CalcCRC(header + CRC_START_OFFSET_13,
                                     IMAGE_PAGE_SIZE - CRC_START_OFFSET_13,
                                     NIBBLE_SWAP_INT(header[PAGE_CRC_OFFSET]));
  TEST_ASSERT_EQUAL_HEX(0, page_crc);
}
