#include "gd32_bkp.h"

static uint8_t g_bkp_first = 0;
void gd32_bkp_init(void){
	if (POWER_FIRSTFLAG_VALUE != bkp_read_data(POWER_FIRSTFLAG_REG)){
		/* enable PMU and BKPI clocks */
		rcu_periph_clock_enable(RCU_BKPI);
		rcu_periph_clock_enable(RCU_PMU);
		/* allow access to BKP domain */
		pmu_backup_write_enable();

		/* reset backup domain */
		bkp_deinit();
		rcu_osci_on(RCU_IRC40K);
		rcu_osci_stab_wait(RCU_IRC40K);
		bkp_write_data(POWER_FIRSTFLAG_REG, POWER_FIRSTFLAG_VALUE);
		g_bkp_first = 1;
	}else{
        /* allow access to BKP domain */
		rcu_periph_clock_enable(RCU_BKPI);
        rcu_periph_clock_enable(RCU_PMU);
        pmu_backup_write_enable();
		g_bkp_first = 0;
	}
}

bool gd32_bkp_first_startup(void){

	if(g_bkp_first == 1)
		return TRUE;
	else
		return FALSE;
}

bool gd32_bkp_btrace_valid(void){
	if( bkp_read_data(BACK_TRACE_MAIGC_REG) == BACK_TRACE_MAIGC_VALUE)
		return TRUE;
	else
		return FALSE;
}

void gd32_bkp_save_backtrace(uint32_t *backtrace, uint32_t stack_over, uint32_t stack_dep, uint16_t line){
	uint16_t value = ((stack_over << 8) & 0xFF00) | (stack_dep & 0x00FF);
	uint32_t index;
	bkp_data_register_enum trace_reg = BACK_TRACE_CALLTRACE_START_REG;
	
	bkp_write_data(BACK_TRACE_MAIGC_REG, BACK_TRACE_MAIGC_VALUE);
	bkp_write_data(BACK_TRACE_INFO_REG, value);

	for (index = 0; index < stack_dep; index ++){
		uint32_t value = (backtrace[index] >> 16) & 0xFFFF;
		bkp_write_data(trace_reg, (uint16_t)value);
		trace_reg ++;
		value = backtrace[index] & 0xFFFF;
		bkp_write_data(trace_reg, (uint16_t)value);
		trace_reg ++;
	}
	bkp_write_data(BACK_TRACE_LINE_REG, line);
}


void gd32_bkp_get_backtrace(uint32_t *backtrace, uint32_t *stack_over, uint32_t *stack_dep, uint16_t *line){
	uint16_t value = bkp_read_data(BACK_TRACE_INFO_REG);
	uint32_t index;
	*stack_over = (value >> 8) & 0xFF;
	*stack_dep = value & 0xFF;
	*stack_dep = *stack_dep > 16 ? 16 : *stack_dep;
	bkp_data_register_enum trace_reg = BACK_TRACE_CALLTRACE_START_REG;
	for (index = 0; index < *stack_dep; index++){
		uint32_t t_h = bkp_read_data(trace_reg);
		trace_reg ++;
		uint32_t t_l = bkp_read_data(trace_reg);
		trace_reg ++;
		backtrace[index] = (t_h << 16 & 0xFFFF0000) | (t_l & 0xFFFF);
	}
	*line = bkp_read_data(BACK_TRACE_LINE_REG);
}


