Merge pull request #13 from archshift/cleanup

General cleanup and logging to file.
This commit is contained in:
bunnei 2014-12-15 22:10:40 -05:00
commit e9cad6b632
14 changed files with 244 additions and 126 deletions

View File

@ -19,7 +19,7 @@ include $(DEVKITARM)/3ds_rules
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR)) export TARGET := $(shell basename $(CURDIR))
BUILD := build BUILD := build
SOURCES := source source/tests source/tests/fs source/tests/cpu SOURCES := source source/common source/tests source/tests/fs source/tests/cpu
DATA := data DATA := data
INCLUDES := source #include INCLUDES := source #include

View File

@ -0,0 +1,49 @@
#include "string_funcs.h"
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
namespace Common {
std::string FormatString(const char* format, ...)
{
va_list arguments;
char *va_str;
va_start(arguments, format);
vasprintf(&va_str, format, arguments);
va_end(arguments);
std::string out_str(va_str);
free(va_str);
return out_str;
}
int CountLines(const std::string& str)
{
if (str.empty())
return 0;
return 1 + std::count_if(str.begin(), str.end(), [](char c) { return c == '\n'; });
}
void DeleteFirstLine(std::string* str)
{
if (str->empty())
return;
size_t linebreak = str->find_first_of('\n');
if (linebreak == std::string::npos || linebreak + 1 > str->length()) {
*str = {};
return;
}
*str = str->substr(linebreak + 1);
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <string>
namespace Common {
std::string FormatString(const char* format, ...);
/**
* Returns the number of lines (broken by '\n') in the string
*/
int CountLines(const std::string& str);
/**
* Deletes the first line (broken by '\n') from the string
*/
void DeleteFirstLine(std::string* str);
}

View File

@ -1,13 +1,20 @@
#include <stdlib.h> #include "draw.h"
#include <stdio.h>
#include <string.h> #include <cstdlib>
#include <cstdio>
#include <cstring>
#include <3ds.h> #include <3ds.h>
#include "text.h"
#include "font.h" #include "font.h"
//this code is not meant to be readable Rect GetScreenSize(gfxScreen_t screen)
int drawCharacter(u8* fb, font_s* font, char c, s16 x, s16 y, u16 w, u16 h) {
return { (screen == GFX_TOP) ? 400 : 320, 240 };
}
// This code is not meant to be readable -- Smea
int DrawCharacter(u8* fb, font_s* font, char c, s16 x, s16 y, u16 w, u16 h)
{ {
Glyph* cd = &font->desc[(int)c]; Glyph* cd = &font->desc[(int)c];
@ -52,7 +59,7 @@ int drawCharacter(u8* fb, font_s* font, char c, s16 x, s16 y, u16 w, u16 h)
return cd->xa; return cd->xa;
} }
void drawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w, u16 h) void DrawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w, u16 h)
{ {
if (!f || !fb) if (!f || !fb)
return; return;
@ -60,7 +67,7 @@ void drawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w,
int dx = 0, dy = 0; int dx = 0, dy = 0;
for (const char& c : str) for (const char& c : str)
{ {
dx += drawCharacter(fb, f, c, x + dx, y + dy, w, h); dx += DrawCharacter(fb, f, c, x + dx, y + dy, w, h);
if (c == '\n') { if (c == '\n') {
dx = 0; dx = 0;
dy -= f->height; dy -= f->height;
@ -68,7 +75,7 @@ void drawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w,
} }
} }
void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s* font, const std::string& str, s16 x, s16 y) void DrawText(gfxScreen_t screen, gfx3dSide_t side, font_s* font, const std::string& str, s16 x, s16 y)
{ {
if (!font) if (!font)
font = &fontDefault; font = &fontDefault;
@ -76,5 +83,16 @@ void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s* font, const std::
u16 fbWidth, fbHeight; u16 fbWidth, fbHeight;
u8* fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); u8* fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight);
drawString(fbAdr, font, str, y, x, fbHeight, fbWidth); DrawString(fbAdr, font, str, y, x, fbHeight, fbWidth);
}
void FillScreen(gfxScreen_t screen, u8 bg_r, u8 bg_g, u8 bg_b)
{
Rect screen_size = GetScreenSize(screen);
u8* fb_addr = gfxGetFramebuffer(screen, GFX_LEFT, nullptr, nullptr);
for (int i = 0; i < screen_size.w * screen_size.h * 3; i += 3) {
fb_addr[i] = bg_b;
fb_addr[i+1] = bg_g;
fb_addr[i+2] = bg_r;
}
} }

18
source/draw.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <3ds.h>
#include "font.h"
struct Rect {
int w, h;
};
Rect GetScreenSize(gfxScreen_t screen);
int DrawCharacter(u8* fb, font_s* f, char c, s16 x, s16 y, u16 w, u16 h);
void DrawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w, u16 h);
void DrawText(gfxScreen_t screen, gfx3dSide_t side, font_s* f, const std::string& str, s16 x, s16 y);
void FillScreen(gfxScreen_t screen, u8 bg_r, u8 bg_g, u8 bg_b);

View File

@ -1,52 +1,56 @@
#include <stdlib.h>
#include <stdio.h>
#include <3ds.h> #include <3ds.h>
#include "output.h" #include "output.h"
#include "tests/test.h"
#include "tests/fs/fs.h" #include "tests/fs/fs.h"
#include "tests/cpu/cputests.h" #include "tests/cpu/cputests.h"
static unsigned int testCounter = 0; static unsigned int test_counter = 0;
static void (*tests[]) (void) = { static TestCaller tests[] = {
FS::TestAll, FS::TestAll,
CPU::Integer::TestAll CPU::Integer::TestAll
}; };
int main() int main(int argc, char** argv)
{ {
srvInit(); srvInit();
aptInit(); aptInit();
hidInit(NULL); hidInit(NULL);
gfxInit(); gfxInit();
gfxSet3D(false); gfxSet3D(false);
fsInit();
InitOutput();
clearScreens(); ClearScreens();
print(GFX_TOP, "Press A to begin...\n"); Print(GFX_TOP, "Press A to begin...\n");
while (aptMainLoop()) { while (aptMainLoop()) {
drawFrames(); DrawBuffers();
hidScanInput(); hidScanInput();
if (hidKeysDown() & KEY_START) { if (hidKeysDown() & KEY_START) {
break; break;
} else if (hidKeysDown() & KEY_A) { } else if (hidKeysDown() & KEY_A) {
clearScreen(GFX_TOP); ClearScreens();
if (testCounter < (sizeof(tests) / sizeof(tests[0]))) { if (test_counter < (sizeof(tests) / sizeof(tests[0]))) {
tests[testCounter](); tests[test_counter]();
testCounter++; test_counter++;
} else { } else {
break; break;
} }
print(GFX_TOP, "\n"); Log(GFX_TOP, "\n");
print(GFX_TOP, "Press A to continue...\n"); Print(GFX_TOP, "Press A to continue...\n");
} }
gspWaitForEvent(GSPEVENT_VBlank0, false); gspWaitForEvent(GSPEVENT_VBlank0, false);
} }
clearScreens(); ClearScreens();
DeinitOutput();
fsExit();
gfxExit(); gfxExit();
hidExit(); hidExit();
aptExit(); aptExit();

View File

@ -1,98 +1,92 @@
#include "output.h"
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <3ds.h> #include <3ds.h>
#include "text.h" #include "output.h"
static std::string bufferTop; #include <cmath>
static std::string bufferBottom; #include <fstream>
static int countLines(const std::string& str) #include "draw.h"
#include "common/string_funcs.h"
static FILE* log_file;
static std::string buffer_top;
static std::string buffer_bottom;
static std::string& GetTextBuffer(gfxScreen_t screen)
{ {
if (str.empty()) switch (screen) {
return 0; case GFX_TOP: return buffer_top;
case GFX_BOTTOM: return buffer_bottom;
return 1 + std::count_if(str.begin(), str.end(), [](char c) { return c == '\n'; }); }
return buffer_top;
} }
static void deleteFirstLine(std::string* str) static void DrawBuffer(gfxScreen_t screen)
{ {
if (str->empty()) Rect screen_size = GetScreenSize(screen);
return; std::string& text_buffer = GetTextBuffer(screen);
size_t linebreak = str->find_first_of('\n'); int lines = Common::CountLines(text_buffer);
while (lines > (screen_size.h / fontDefault.height - 3)) {
if (linebreak == std::string::npos || linebreak + 1 > str->length()) { Common::DeleteFirstLine(&text_buffer);
*str = {};
return;
}
*str = str->substr(linebreak + 1);
}
static void drawFrame(gfxScreen_t screen, char b, char g, char r)
{
int screenHeight = 240;
int screenWidth = (screen == GFX_TOP) ? 400 : 320;
std::string& textBuffer = (screen == GFX_TOP) ? bufferTop : bufferBottom;
u8* bufAdr = gfxGetFramebuffer(screen, GFX_LEFT, nullptr, nullptr);
for (int i = 0; i < screenWidth * screenHeight * 3; i += 3) {
bufAdr[i] = b;
bufAdr[i+1] = g;
bufAdr[i+2] = r;
}
int lines = countLines(textBuffer);
while (lines > (screenHeight / fontDefault.height - 3)) {
deleteFirstLine(&textBuffer);
lines--; lines--;
} }
gfxDrawText(screen, GFX_LEFT, nullptr, textBuffer, screenHeight - fontDefault.height * 3, 10); DrawText(screen, GFX_LEFT, nullptr, text_buffer, screen_size.h - fontDefault.height * 3, 10);
} }
void drawFrames() void InitOutput()
{ {
drawFrame(GFX_TOP, 0x88, 0x66, 0x00); sdmcInit();
drawFrame(GFX_BOTTOM, 0x00, 0x00, 0x00); log_file = fopen("hwtest_log.txt", "w");
}
void DrawBuffers()
{
FillScreen(GFX_TOP, 0x00, 0x66, 0x88);
DrawBuffer(GFX_TOP);
FillScreen(GFX_BOTTOM, 0x00, 0x00, 0x00);
DrawBuffer(GFX_BOTTOM);
gfxFlushBuffers(); gfxFlushBuffers();
gfxSwapBuffers(); gfxSwapBuffers();
} }
void print(gfxScreen_t screen, const char* format, ...) void ClearScreen(gfxScreen_t screen, u8 bg_r, u8 bg_g, u8 bg_b)
{ {
std::string& textBuffer = (screen == GFX_TOP) ? bufferTop : bufferBottom; FillScreen(screen, bg_r, bg_g, bg_b);
GetTextBuffer(screen).clear();
va_list arguments; gfxFlushBuffers();
char *vaStr; gfxSwapBuffers();
va_start(arguments, format);
vasprintf(&vaStr, format, arguments);
va_end(arguments);
textBuffer += std::string(vaStr);
svcOutputDebugString(vaStr, strlen(vaStr));
free(vaStr);
drawFrames();
} }
void clearScreen(gfxScreen_t screen) void ClearScreens()
{ {
std::string& textBuffer = (screen == GFX_TOP) ? bufferTop : bufferBottom; ClearScreen(GFX_TOP, 0x00, 0x66, 0x88);
textBuffer.clear(); ClearScreen(GFX_BOTTOM, 0x00, 0x00, 0x00);
drawFrames();
} }
void clearScreens() void Print(gfxScreen_t screen, const std::string& text)
{ {
clearScreen(GFX_TOP); GetTextBuffer(screen) += text;
clearScreen(GFX_BOTTOM); DrawBuffers();
}
void Log(gfxScreen_t screen, const std::string& text)
{
Print(screen, text);
LogToFile(text);
}
void LogToFile(const std::string& text)
{
svcOutputDebugString(text.c_str(), text.length());
fprintf(log_file, "%s", text.c_str());
}
void DeinitOutput()
{
fclose(log_file);
sdmcExit();
} }

View File

@ -1,8 +1,23 @@
#pragma once #pragma once
#include <string>
#include <3ds.h> #include <3ds.h>
void drawFrames(); void InitOutput();
void print(gfxScreen_t screen, const char* format, ...);
void clearScreen(gfxScreen_t screen); void DrawBuffers();
void clearScreens();
/// Prints `text` to `screen`.
void Print(gfxScreen_t screen, const std::string& text);
/// Prints `text` to `screen`, and logs it in the log file.
void Log(gfxScreen_t screen, const std::string& text);
/// Logs `text` to the log file.
void LogToFile(const std::string& text);
void ClearScreen(gfxScreen_t screen, u8 bg_r, u8 bg_g, u8 bg_b);
void ClearScreens();
void DeinitOutput();

View File

@ -1,6 +1,3 @@
#include <3ds.h>
#include "tests/test.h"
#include "tests/fs/fs.h" #include "tests/fs/fs.h"
#include "tests/fs/fs_sdmc.h" #include "tests/fs/fs_sdmc.h"
@ -8,11 +5,7 @@ namespace FS {
void TestAll() void TestAll()
{ {
Test("FS", "Initializing service", fsInit(), 0L);
SDMC::TestAll(); SDMC::TestAll();
Test("FS", "Exiting service", fsExit(), 0L);
} }
} // namespace } // namespace

View File

@ -2,7 +2,7 @@
#include <cstring> #include <cstring>
#include <3ds.h> #include <3ds.h>
#include "scope_exit.h" #include "common/scope_exit.h"
#include "tests/test.h" #include "tests/test.h"
#include "tests/fs/fs_sdmc.h" #include "tests/fs/fs_sdmc.h"
@ -158,7 +158,7 @@ static bool TestDirRename(FS_archive sdmcArchive)
void TestAll() void TestAll()
{ {
FS_archive sdmcArchive = (FS_archive) { 0x00000009, { PATH_EMPTY, 1, (u8*) "" } }; FS_archive sdmcArchive = { 0x00000009, { PATH_EMPTY, 1, (u8*) "" } };
Test("SDMC", "Opening archive", FSUSER_OpenArchive(NULL, &sdmcArchive), 0L); Test("SDMC", "Opening archive", FSUSER_OpenArchive(NULL, &sdmcArchive), 0L);
Test("SDMC", "Creating and deleting file", TestFileCreateDelete(sdmcArchive), true); Test("SDMC", "Creating and deleting file", TestFileCreateDelete(sdmcArchive), true);

View File

@ -3,8 +3,15 @@
#include <3ds.h> #include <3ds.h>
#include "output.h" #include "output.h"
#include "common/string_funcs.h"
void PrintSuccess(std::string group, std::string name, bool val) void SoftAssertLog(const std::string& function, int line, const std::string& condition)
{ {
print(GFX_TOP, "%s: %s - %s\n", group.c_str(), name.c_str(), val ? "SUCCESS" : "FAILURE"); LogToFile(Common::FormatString("SOFTASSERT FAILURE: `%s`\n", condition.c_str()));
LogToFile(Common::FormatString(" At `%s` L%i\n", function.c_str(), line));
}
void PrintSuccess(const std::string& group, const std::string& name, bool val)
{
Log(GFX_TOP, Common::FormatString("%s: [%s] %s\n", val ? "SUCCESS" : "FAILURE", group.c_str(), name.c_str()));
} }

View File

@ -1,14 +1,24 @@
#pragma once #pragma once
#include <functional> #include <string>
typedef void (*TestCaller)(void);
void SoftAssertLog(const std::string& function, int line, const std::string& condition);
// If the condition fails, return false // If the condition fails, return false
#define SoftAssert(cond) do { if (!(cond)) { return false; } } while (0) #define SoftAssert(cond) \
do { \
if (!(cond)) { \
SoftAssertLog(__PRETTY_FUNCTION__, __LINE__, #cond); \
return false; \
} \
} while (0)
void PrintSuccess(std::string group, std::string name, bool val); void PrintSuccess(const std::string& group, const std::string& name, bool val);
template <typename T> template <typename T>
bool Test(std::string group, std::string name, T result, T expected) bool Test(const std::string& group, const std::string& name, T result, T expected)
{ {
PrintSuccess(group, name, result == expected); PrintSuccess(group, name, result == expected);
return result == expected; return result == expected;

View File

@ -1,9 +0,0 @@
#pragma once
#include <string>
#include "font.h"
int drawCharacter(u8* fb, font_s* f, char c, s16 x, s16 y, u16 w, u16 h);
void drawString(u8* fb, font_s* f, const std::string& str, s16 x, s16 y, u16 w, u16 h);
void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s* f, const std::string& str, s16 x, s16 y);