summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2023-01-09 15:11:53 +0000
committerIan C <ianc@noddybox.co.uk>2023-01-09 15:11:53 +0000
commit2df835d00591d085de589ddf4d40ea3edc8f3fac (patch)
tree01bce387296a3590a26eb0856a51f12f9f207242 /source
parent5b9ffe70b622cee65ed5678163bee0e22fc0433d (diff)
Added support for debug logging over a socket.
Diffstat (limited to 'source')
-rw-r--r--source/debug.c161
-rw-r--r--source/gui.c151
-rw-r--r--source/main.c59
-rw-r--r--source/snap.c5
4 files changed, 341 insertions, 35 deletions
diff --git a/source/debug.c b/source/debug.c
new file mode 100644
index 0000000..f297238
--- /dev/null
+++ b/source/debug.c
@@ -0,0 +1,161 @@
+/*
+ 3dsspec - Nintendo 3DS Spectrum emulator
+
+ Copyright (C) 2021 Ian Cowburn <ianc@noddybox.co.uk>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>
+
+ -------------------------------------------------------------------------
+
+ Provides an interface for debug
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <3ds.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "debug.h"
+#include "gui.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* ---------------------------------------- GLOBAL EXTERNALS
+*/
+int debug_enabled = FALSE;
+
+/* ---------------------------------------- PRIVATE DAYA
+*/
+static char debug_host[256];
+static char debug_port[32];
+static int sock = -1;
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Error(const char *format, ...)
+{
+ static char buff[4096];
+ va_list va;
+
+ va_start(va, format);
+ vsnprintf(buff, 4096, format, va);
+ buff[4095] = 0;
+ va_end(va);
+
+ GUI_Alert(FALSE, buff);
+}
+
+static void OpenDebugConnection(void)
+{
+ if (sock == -1)
+ {
+ struct addrinfo *addr, *addr_p;
+ struct addrinfo hints = {0};
+
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (getaddrinfo(debug_host, debug_port, &hints, &addr) == 0)
+ {
+ for(addr_p = addr; addr_p && sock == -1; addr_p = addr_p->ai_next)
+ {
+ sock = socket(addr_p->ai_family,
+ addr_p->ai_socktype,
+ addr_p->ai_protocol);
+
+ if (sock != -1)
+ {
+ if (connect(sock, addr_p->ai_addr, addr_p->ai_addrlen)
+ == -1)
+ {
+ Error("Failed to connect socket");
+ close(sock);
+ sock = -1;
+ }
+ }
+ else
+ {
+ Error("Failed to create socket(%d,%d,%d)\n%d %s",
+ addr_p->ai_family,
+ addr_p->ai_socktype,
+ addr_p->ai_protocol,
+ errno,
+ strerror(errno));
+ }
+ }
+ }
+ else
+ {
+ Error("Failed to getaddrinfo(%s,%s)", debug_host, debug_port);
+ }
+ }
+}
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void DEBUG_SetAddress(const char *host, const char *port)
+{
+ strncpy(debug_host, host, (sizeof debug_host) - 1);
+ strncpy(debug_port, port, (sizeof debug_port) - 1);
+
+ debug_host[(sizeof debug_host) - 1] = 0;
+ debug_port[(sizeof debug_port) - 1] = 0;
+
+ if (sock != -1)
+ {
+ close(sock);
+ sock = -1;
+ }
+}
+
+
+void DEBUG_Output(const char *format, ...)
+{
+ static char buff[4096];
+
+ if (debug_enabled)
+ {
+ va_list va;
+
+ OpenDebugConnection();
+
+ va_start(va, format);
+ vsnprintf(buff, 4096, format, va);
+ buff[4095] = 0;
+ va_end(va);
+
+ if (sock != -1)
+ {
+ send(sock, buff, strlen(buff), 0);
+ }
+ }
+}
+
+
+/* END OF FILE */
diff --git a/source/gui.c b/source/gui.c
index c3b402d..5e31ac5 100644
--- a/source/gui.c
+++ b/source/gui.c
@@ -802,41 +802,13 @@ int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen)
int ascii;
} keymap[] =
{
- {SK_1, '1'},
- {SK_2, '2'},
- {SK_3, '3'},
- {SK_4, '4'},
- {SK_5, '5'},
- {SK_6, '6'},
- {SK_7, '7'},
- {SK_8, '8'},
- {SK_9, '9'},
- {SK_0, '0'},
- {SK_A, 'A'},
- {SK_B, 'B'},
- {SK_C, 'C'},
- {SK_D, 'D'},
- {SK_E, 'E'},
- {SK_F, 'F'},
- {SK_G, 'G'},
- {SK_H, 'H'},
- {SK_I, 'I'},
- {SK_J, 'J'},
- {SK_K, 'K'},
- {SK_L, 'L'},
- {SK_M, 'M'},
- {SK_N, 'N'},
- {SK_O, 'O'},
- {SK_P, 'P'},
- {SK_Q, 'Q'},
- {SK_R, 'R'},
- {SK_S, 'S'},
- {SK_T, 'T'},
- {SK_U, 'U'},
- {SK_V, 'V'},
- {SK_W, 'W'},
- {SK_X, 'X'},
- {SK_Y, 'Y'},
+ {SK_1, '1'}, {SK_2, '2'}, {SK_3, '3'}, {SK_4, '4'}, {SK_5, '5'},
+ {SK_6, '6'}, {SK_7, '7'}, {SK_8, '8'}, {SK_9, '9'}, {SK_0, '0'},
+ {SK_A, 'A'}, {SK_B, 'B'}, {SK_C, 'C'}, {SK_D, 'D'}, {SK_E, 'E'},
+ {SK_F, 'F'}, {SK_G, 'G'}, {SK_H, 'H'}, {SK_I, 'I'}, {SK_J, 'J'},
+ {SK_K, 'K'}, {SK_L, 'L'}, {SK_M, 'M'}, {SK_N, 'N'}, {SK_O, 'O'},
+ {SK_P, 'P'}, {SK_Q, 'Q'}, {SK_R, 'R'}, {SK_S, 'S'}, {SK_T, 'T'},
+ {SK_U, 'U'}, {SK_V, 'V'}, {SK_W, 'W'}, {SK_X, 'X'}, {SK_Y, 'Y'},
{SK_Z, 'Z'},
{0, 0}
};
@@ -928,3 +900,112 @@ int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen)
return accept;
}
+
+int GUI_Input(const char *prompt, char text[], int maxlen)
+{
+ struct
+ {
+ SoftKey key;
+ int ascii;
+ } keymap[] =
+ {
+ {SK_1, '1'}, {SK_2, '2'}, {SK_3, '3'}, {SK_4, '4'}, {SK_5, '5'},
+ {SK_6, '6'}, {SK_7, '7'}, {SK_8, '8'}, {SK_9, '9'}, {SK_0, '0'},
+ {SK_A, 'A'}, {SK_B, 'B'}, {SK_C, 'C'}, {SK_D, 'D'}, {SK_E, 'E'},
+ {SK_F, 'F'}, {SK_G, 'G'}, {SK_H, 'H'}, {SK_I, 'I'}, {SK_J, 'J'},
+ {SK_K, 'K'}, {SK_L, 'L'}, {SK_M, 'M'}, {SK_N, 'N'}, {SK_O, 'O'},
+ {SK_P, 'P'}, {SK_Q, 'Q'}, {SK_R, 'R'}, {SK_S, 'S'}, {SK_T, 'T'},
+ {SK_U, 'U'}, {SK_V, 'V'}, {SK_W, 'W'}, {SK_X, 'X'}, {SK_Y, 'Y'},
+ {SK_Z, 'Z'}, {SK_SHIFT, '.'},
+ {0, 0}
+ };
+
+ SoftKeyEvent ev;
+ int done = FALSE;
+ int accept = FALSE;
+ Framebuffer upper;
+
+ text[0] = 0;
+
+ while(!done)
+ {
+ FB_StartFrame(&upper, NULL);
+
+ FB_Clear(&upper, COL_WHITE);
+ SK_DisplayKeyboard();
+
+ FB_printf(&upper, 0, 16, COL_BLACK, COL_TRANSPARENT, "%s", prompt);
+ FB_printf(&upper, 0, 8, COL_BLACK, COL_TRANSPARENT, "\"%s\001L\001\"",
+ text);
+
+ FB_Print(&upper, "PRESS ENTER TO ACCEPT", 0, 32,
+ COL_BLACK, COL_TRANSPARENT);
+ FB_Print(&upper, "PRESS SYMBOL SHIFT TO BACKSPACE", 0, 40,
+ COL_BLACK, COL_TRANSPARENT);
+ FB_Print(&upper, "PRESS CAPS SHIFT FOR PERIOD", 0, 48,
+ COL_BLACK, COL_TRANSPARENT);
+ FB_Print(&upper, "PRESS SPACE/BREAK TO CANCEL", 0, 56,
+ COL_BLACK, COL_TRANSPARENT);
+
+ FB_EndFrame();
+
+ while(SK_GetBareEvent(&ev))
+ {
+ if (!ev.pressed)
+ {
+ size_t l;
+ int f;
+ int ascii;
+
+ l = strlen(text);
+
+ switch(ev.key)
+ {
+ case SK_SYMBOL:
+ if (l)
+ {
+ text[--l] = 0;
+ }
+ break;
+
+ case SK_SPACE:
+ done = TRUE;
+ accept = FALSE;
+ break;
+
+ case SK_NEWLINE:
+ done = TRUE;
+ accept = TRUE;
+ break;
+
+ default:
+ if (l < maxlen)
+ {
+ f = 0;
+ ascii = 0;
+
+ while(!ascii && keymap[f].ascii)
+ {
+ if (ev.key == keymap[f].key)
+ {
+ ascii = keymap[f].ascii;
+ }
+
+ f++;
+ }
+
+ if (ascii)
+ {
+ text[l++] = ascii;
+ text[l] = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return accept;
+}
+
diff --git a/source/main.c b/source/main.c
index b5f9c72..30e9359 100644
--- a/source/main.c
+++ b/source/main.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <malloc.h>
#include <3ds.h>
#include "framebuffer.h"
@@ -32,6 +33,7 @@
#include "config.h"
#include "snapshot.h"
#include "snap.h"
+#include "debug.h"
#define DSSPEC_VERSION "0.1"
@@ -67,6 +69,7 @@ static const char *main_menu[]=
"Load Memory Snapshot",
"Save Joypad/Key State",
"Load Joypad/Key State",
+ "Enable Debug",
"Exit 3DSSPEC",
"Cancel",
NULL
@@ -82,6 +85,7 @@ typedef enum
MenuLoadSnapshot,
MenuSaveMappings,
MenuLoadMappings,
+ MenuDebug,
MenuExit
} MenuOpt;
@@ -236,6 +240,8 @@ int main(int argc, char *argv[])
Z80 *z80;
int quit = FALSE;
float mix[12] = {1.0, 1.0};
+ u32 *SOC_buffer;
+ int soc_initialised = FALSE;
gfxInit(GSP_RGB565_OES, GSP_RGB565_OES, FALSE);
ndspInit();
@@ -249,6 +255,29 @@ int main(int argc, char *argv[])
FB_Init();
GUI_Init();
+ SOC_buffer = (u32*)memalign(0x1000,0x100000);
+
+ if (SOC_buffer)
+ {
+ int ret;
+
+ if ((ret = socInit(SOC_buffer, 0x100000)) == 0)
+ {
+ soc_initialised = TRUE;
+ }
+ else
+ {
+ char msg[256];
+ snprintf(msg, sizeof msg, "Failed to initialise SOC\n0x%08X",
+ (unsigned int)ret);
+ GUI_Alert(FALSE, msg);
+ }
+ }
+ else
+ {
+ GUI_Alert(FALSE, "Failed to allocate memory for SOC!");
+ }
+
z80 = Z80Init(SPECReadPort, SPECWritePort);
if (!z80)
@@ -343,6 +372,31 @@ int main(int argc, char *argv[])
SNAP_Load(z80, NULL, SNAP_TYPE_KEYBOARD);
break;
+ case MenuDebug:
+ if (soc_initialised)
+ {
+ char host[32] = {0};
+ char port[32] = {0};
+
+ debug_enabled = TRUE;
+
+ GUI_Input("Enter host", host, 31);
+ GUI_Input("Enter port", port, 31);
+
+ if (!host[0])
+ {
+ strcpy(host, "192.168.0.77");
+ }
+
+ if (!port[0])
+ {
+ strcpy(port, "12345");
+ }
+
+ DEBUG_SetAddress(host, port);
+ }
+ break;
+
case MenuExit:
quit = TRUE;
break;
@@ -360,5 +414,10 @@ int main(int argc, char *argv[])
ndspExit();
gfxExit();
+ if (soc_initialised)
+ {
+ socExit();
+ }
+
return 0;
}
diff --git a/source/snap.c b/source/snap.c
index e998ba2..db8c785 100644
--- a/source/snap.c
+++ b/source/snap.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include "snap.h"
+#include "debug.h"
/* ---------------------------------------- MACROS
*/
@@ -111,6 +112,10 @@ int TAPLoad(Z80Byte id, Z80Word *addr, Z80Word *len, SNAP_Poke poke)
type=GetTAPByte();
csum=id;
+ SPEC_DEBUG("Read block. len=%u type=%u\n", (unsigned)blen, (unsigned)type);
+ SPEC_DEBUG("Requested block len=%u type=%u addr=%u\n",
+ (unsigned)*len, (unsigned)id, (unsigned)*addr);
+
/* Have we found the requested block?
*/
if (id==type)