/*
 * flash.c
 *
 *  Created on: Jun 23, 2023
 *      Author: true
 */

#include "hk32f030m.h"
#include "flash.h"

#include "led_sk.h"



/**
 * @brief   This function erases a single flash page.
 * @return  status: Report about the success of the erasing.
 */
__attribute__ ((long_call, section(".ramfunc"))) BL_flash_status flash_erase_page(uint32_t addr)
{
	BL_flash_status status = FLASH_ERROR;

	FLASH_Unlock();

	if (FLASH_ErasePage(addr) == FLASH_COMPLETE) {
		status = FLASH_OK;
	}

	FLASH_Lock();

	return status;
}

/**
 * @brief   This function flashes the memory.
 * @param   addr:    First address to be written to.
 * @param   *data:   Array of the data that we want to write.
 * @param   *length: Size of the data array, in 16-bit words.
 * @return  status:  Report about the success of the writing.
 */
__attribute__ ((long_call, section(".ramfunc"))) BL_flash_status flash_write(uint32_t addr, uint8_t *data, uint16_t length)
{
	BL_flash_status status = FLASH_OK;

	FLASH_Unlock();

	// note: using the halfword programming method instead of the byte method
	//       uses approximately 20 more bytes of program space, and might only
	//       be slightly faster.

	/* Loop through the data. */
	for (uint32_t i = 0u; (i < length) && (status == FLASH_OK); i++) {
		if (addr >= USER_APP_END_ADDR) {
			status = FLASH_ERROR_SIZE;
			break;
		} else {
			/* The actual flashing. If there is an error, then report it. */
			if (FLASH_ProgramByte(addr, data[i]) != FLASH_COMPLETE) {
				status |= FLASH_ERROR_WRITE;
			}

			/* Read back the content of the memory. If it is wrong, then report an error. */
			if (data[i] != (*(volatile uint8_t *)addr)) {
				status |= FLASH_ERROR_VERIFY;
			}

			/* Shift the address by a word. */
			addr++;
		}
	}

	FLASH_Lock();

	return status;
}

void jump_to_user_app()
{
	void (*user_app)(void);

	// check reset key to know what to do
	if (bootcheck == 0x1337b007) {
		// configure jump location
		user_app = (void (*)(void))(*(volatile uint32_t *)(USER_APP_START_ADDR + 4));

		// configure stack pointer
		__set_MSP(*(volatile uint32_t*)USER_APP_START_ADDR);

		// configure interrupt vector table
		// SCB->VTOR = USER_APP_START_ADDR;

		// cortex m0 doesn't have VTOR to remap vector table.
		// to address this, HK MCU has a flash offset thing which
		// remaps 256 bytes specified by an offset, to to 0x08000000
		FLASH->INT_VEC_OFFSET = USER_APP_START_ADDR & 0x3ffc;

		// let's do this
		user_app();
	} else {
		// we want the MCU to be at default settings
		// so set our flag, then reboot
		bootcheck = 0x1337b007;
		NVIC_SystemReset();
	}
}
