/****************************************************************************
* Copyright (C) 2015-2016 by the SotS Team *
* *
* This file is part of Sovereign of the Skies. *
* *
* Sovereign of the Skies is free software: you can redistribute it *
* and/or modify it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version provided you include a copy of the *
* licence and this header. *
* *
* Sovereign of the Skies is distributed in the hope that it will be *
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with Sovereign of the Skies. *
* If not, see . *
****************************************************************************/
/**
* @file debug.c
* @author Sturmvogel
* @date 15 dec 2016
* @brief Operate with the sots debug engine, very temporary
*/
/* === INCLUDE === */
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* === STRUCTURES === */
struct assert_memory {
char *file;
int line;
char *expression;
};
/* === STATICS === */
struct assert_memory *assert_global = (struct assert_memory *)0x0203FEC4;
static struct print_engine *print_memory = (struct print_engine *)(0x0203FFF0);
/* === PROTOTYPES === */
/**
* @brief convert int to char
* @param i integer
* @param ref buffer to output to
*/
void debug_int_to_char(u32 i, char *ref);
/**
* @get length of integer
* @param i integer
* @return length
*/
u32 debug_dec_len(u32 i);
/**
* @brief update debug environment
*/
void debug_update();
/**
* @brief reset scrolling (from overworld e.g.)
*/
void debug_reset_scrolling();
/**
* @brief start a unit test function
*/
void debug_init_unit_test();
/**
* @brief handle for the debug scene
*/
void debug_scene();
/**
* @brief convert character to byte
* @param character character
* @return byte from character
*/
u8 char_to_byte(char character);
/**
* @brief print a character on the debug environment
* @param line line to print to
* @param row row to print to
* @param character character to print
* @param color color to print in
*/
void debug_print_char(u16 line, u16 row, char character, u8 color);
/**
* @brief print a string to the debug environment
* @param line line to print to
* @param row row to start
* @param color color to print in
* @param pBuf string buffer to print (null terminated)
*/
void debug_print_string(u16 line, u16 row, u8 color, char *pBuf);
/**
* @brief build power
* @param n integer to power
* @param power exponent
* @return n^power
*/
u32 debug_power(u32 n, u32 power);
void debug_init_stage_one();
void debug_init_stage_two();
/**
* @brief set bg color of debug environment
* @param color color to set to
*/
void debug_set_bg(u16 color) {
u16 *bgc = (u16 *)0x020375f8;
*bgc = color;
return;
}
/* === STATIC STRUCTURES === */
static struct bg_config debug_bg_config[4] = {
{0, 0, 0x19, 0, 0, 0}, {1, 1, 0x1A, 0, 0, 1}, {2, 2, 0x1B, 0, 0, 2}, {3, 3, 0x1C, 0, 0, 3}};
/* === IMPLEMENTATIONS === */
void as_assert(char *expression, char *file, int line) {
assert_global->file = file;
assert_global->line = line;
assert_global->expression = expression;
set_callback2(debug_assert_scene);
vblank_handler_set(debug_update);
superstate.multi_purpose_state_tracker = 0;
}
void debug_scene() {
if (superstate.multi_purpose_state_tracker == 0) {
debug_init_stage_one();
superstate.multi_purpose_state_tracker++;
} else if (superstate.multi_purpose_state_tracker == 1) {
debug_init_stage_two();
superstate.multi_purpose_state_tracker++;
} else if (superstate.multi_purpose_state_tracker == 2) {
debug_init_unit_test();
superstate.multi_purpose_state_tracker++;
}
return;
}
void debug_some_test() {
set_callback2(debug_scene);
vblank_handler_set(debug_update);
superstate.multi_purpose_state_tracker = 0;
return;
}
void debug_reset_scrolling() {
lcd_io_set_func(0x12, 0x0);
lcd_io_set_func(0x14, 0x0);
lcd_io_set_func(0x16, 0x0);
lcd_io_set_func(0x18, 0x0);
lcd_io_set_func(0x1A, 0x0);
lcd_io_set_func(0x1C, 0x0);
lcd_io_set_func(0x1E, 0x0);
return;
}
void debug_init_unit_test() { test_speed(); }
void debug_print_string(u16 line, u16 row, u8 color, char *pBuf) {
while (*pBuf) {
debug_print_char(line, row++, *pBuf++, color);
}
return;
}
void debug_print(char *str) {
while (*str) {
if (print_memory->row > 29) {
print_memory->line++;
print_memory->row = 0;
}
if (*str == '\n') {
print_memory->line++;
print_memory->row = 0;
}
if (*str == '\xFE') {
str++;
u8 c = *str;
if (c > 2)
c = 0;
print_memory->color = c;
} else {
debug_print_char(print_memory->line, print_memory->row, *str, print_memory->color);
print_memory->row++;
}
str++;
}
return;
}
void debug_printf(char *str, int arg) {
while (*str) {
if (print_memory->row > 29) {
print_memory->line++;
print_memory->row = 0;
}
if (*str == '\n') {
print_memory->line++;
print_memory->row = 0;
}
if (*str == '\xFE') {
str++;
u8 c = *str;
if (c > 2)
c = 0;
print_memory->color = c;
} else if (*str == '%') {
str++;
if (*str == '%') {
debug_print_char(print_memory->line, print_memory->row, *str, print_memory->color);
print_memory->row++;
} else if (*str == 'd') {
u32 len = debug_dec_len(arg);
char temp[debug_dec_len(len + 1)];
temp[len] = 0;
debug_int_to_char(arg, temp);
debug_print(temp);
} else if (*str == 'c') {
char print_char = (char)(arg);
debug_print_char(print_memory->line, print_memory->row, print_char, print_memory->color);
print_memory->row++;
}
} else {
debug_print_char(print_memory->line, print_memory->row, *str, print_memory->color);
print_memory->row++;
}
str++;
}
}
void debug_clean() {
memset((void *)0x0600C800, 0, 0x800);
print_memory->row = 0;
print_memory->line = 0;
print_memory->color = 0;
return;
}
void debug_wait_for_btn(u16 field) {
volatile u16 *control_io = (volatile u16 *)(0x04000130);
while (*control_io & field) {
}
return;
}
void debug_init_stage_one() {
print_memory->row = 0;
print_memory->line = 0;
print_memory->color = 0;
gpu_tile_bg_drop_all_sets(0);
gpu_tile_bg_drop_all_sets(1);
gpu_tile_bg_drop_all_sets(2);
gpu_tile_bg_drop_all_sets(3);
gpu_bg_vram_setup(0, debug_bg_config, 4);
gpu_bg_show(0);
gpu_bg_show(1);
gpu_bg_show(2);
gpu_bg_show(3);
gpu_sync_bg_visibility_and_mode();
debug_reset_scrolling();
obj_delete_all();
memset((void *)0x06000000, 0, 0x17fe0);
memset((void *)0x020375F8, 0, 0x400);
}
void debug_init_stage_two() {
vram_decompress((void *)asciiTiles, (void *)0x06000000);
memcpy((void *)0x020375F8, (void *)asciiPal, 0x60);
debug_set_bg(0x0000);
}
void debug_assert_scene() {
if (superstate.multi_purpose_state_tracker == 0) {
debug_init_stage_one();
superstate.multi_purpose_state_tracker++;
} else if (superstate.multi_purpose_state_tracker == 1) {
debug_init_stage_two();
superstate.multi_purpose_state_tracker++;
} else if (superstate.multi_purpose_state_tracker == 2) {
debug_print("Assertion Failed: ");
debug_print(assert_global->expression);
debug_print("\n\nFile: ");
debug_print(assert_global->file);
debug_printf("\n\nLine: %d", assert_global->line);
superstate.multi_purpose_state_tracker++;
}
/* Loop Endlessly in this stage */
return;
}
void debug_print_char(u16 line, u16 row, char character, u8 color) {
if (color > 2)
color = 0;
u16 position = (32 * line) + row;
union t_map_entry map_entry;
map_entry.entry.tile = char_to_byte(character);
map_entry.entry.pal = color;
u16 *ptr = (u16 *)(0x0600c800 + (position * 2));
*ptr = map_entry.short_map;
return;
}
u8 char_to_byte(char character) {
if (character >= 0x20 && character <= 0x7E)
return character - 0x20;
else
return 3;
}
void debug_update() {
fade_update();
task_exec();
objc_exec();
obj_sync();
gpu_pal_upload();
obj_gpu_sprites_upload();
}
void debug_int_to_char(u32 i, char *ref) {
if (i == 0) {
ref[0] = '0';
return;
}
u32 len = debug_dec_len(i);
while (i > 0) {
ref[len - 1] = '0' + (i % 10);
i /= 10;
len--;
}
return;
}
u32 debug_power(u32 n, u32 power) {
u32 out = 1;
for (u32 i = 0; i < power; ++i) {
out = out * n;
}
return out;
}
u32 debug_dec_len(u32 i) {
u32 len = 1;
while ((i /= 10) > 0) {
len++;
}
return len;
}