view source/main.c @ 3:4c4be527a8d5

Send the entire state (including both pads and touch screen), and other fixes.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 18 Aug 2015 00:25:10 +0100
parents 5ba54fc65608
children 557d35fcf15a
line wrap: on
line source

/*
	Circle Pad example made by Aurelio Mannara for ctrulib
	Please refer to https://github.com/smealum/ctrulib/blob/master/libctru/include/3ds/services/hid.h for more information
	This code was modified for the last time on: 12/13/2014 2:20 UTC+1

	This wouldn't be possible without the amazing work done by:
	-Smealum
	-fincs
	-WinterMute
	-yellows8
	-plutoo
	-mtheall
	-Many others who worked on 3DS and I'm surely forgetting about
*/

#include <3ds.h>
#include <arpa/inet.h>
#include <assert.h>
#include <malloc.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>

struct state_t {
	u32 keys;
	circlePosition pad, cpad;
	touchPosition touch;
};

static u32 *SOC_buffer = NULL;

int create_socket(int domain, int type, struct sockaddr *addr)
{
	int fd = socket(domain, type, 0);
	if (fd < 0) {
		puts("socket() failed.");
		return -1;
	}

	if (addr) {
		if (connect(fd, addr, sizeof(*addr)) < 0) {
			puts("connect() failed.");
			return -1;
		}
	}

	return fd;
}

struct sockaddr* get_sockaddr_from_hostname(const char *hostname, int port)
{
	struct hostent *server = gethostbyname(hostname);
	if (!server) {
		puts("gethostbyname() failed.");
		return NULL;
	}

	struct sockaddr_in *addr = calloc(1, sizeof(struct sockaddr_in));
	if (!addr) {
		puts("calloc() failed.");
		return NULL;
	}

	//memset(&addr, 0, sizeof(struct sockaddr_in));
	addr->sin_family = AF_INET;
	addr->sin_port = htons(port);
	memcpy(&addr->sin_addr.s_addr, server->h_addr_list[0], server->h_length);

	return (struct sockaddr*) addr;
}

struct sockaddr* get_sockaddr_from_ip(const char *hostname, int port)
{
	struct sockaddr_in *addr = calloc(1, sizeof(struct sockaddr_in));
	if (!addr) {
		puts("calloc() failed.");
		return NULL;
	}

	//memset(&addr, 0, sizeof(struct sockaddr_in));
	addr->sin_family = AF_INET;
	addr->sin_port = htons(port);
	addr->sin_addr.s_addr = inet_addr(hostname);

	return (struct sockaddr*) addr;
}

struct network_t {
	int tcp_fd;
	int udp_fd;
	struct sockaddr *addr;
	int addr_size;
};

struct network_t *networkInit(const char *hostname, int port)
{
	const unsigned SOC_ALIGN       = 0x1000;
	const unsigned SOC_BUFFERSIZE  = 0x100000;

	SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
	if (!SOC_buffer) {
		puts("memalign() failed.");
		return NULL;
	}

	unsigned initialized = SOC_Initialize(SOC_buffer, SOC_BUFFERSIZE);
	if (initialized) {
		puts("SOC_Initialize() failed.");
		return NULL;
	}

	//struct sockaddr *addr = get_sockaddr_from_hostname(hostname, port);
	struct sockaddr *addr = get_sockaddr_from_ip(hostname, port);
	if (!addr) {
		puts("get_sockaddr_from_ip() failed.");
		return NULL;
	}

	// TODO: IPv6
	int domain = AF_INET;

	struct network_t *n = malloc(sizeof(struct network_t));
	//n->tcp_fd = create_socket(domain, SOCK_STREAM, addr);
	n->udp_fd = create_socket(domain, SOCK_DGRAM, NULL);
	n->addr = addr;
	n->addr_size = sizeof(struct sockaddr_in);
	return n;
}

int sendState(struct network_t *n, struct state_t *state)
{
	const char *msg = (const char*) state;
	const int msglen = sizeof(struct state_t);
	return sendto(n->udp_fd, msg, msglen, 0, n->addr, n->addr_size);
}

void exitWithMessage(const char *message)
{
	puts(message);
	fflush(stdout);
	gfxFlushBuffers();
	gfxSwapBuffers();
	for (int i=0; i < 60; ++i)
		gspWaitForVBlank();
	gfxExit();
}

int main(void)
{
	//Matrix containing the name of each key. Useful for printing when a key is pressed
	char keysNames[32][32] = {
		"KEY_A", "KEY_B", "KEY_SELECT", "KEY_START",
		"KEY_DRIGHT", "KEY_DLEFT", "KEY_DUP", "KEY_DDOWN",
		"KEY_R", "KEY_L", "KEY_X", "KEY_Y",
		"", "", "KEY_ZL", "KEY_ZR",
		"", "", "", "",
		"KEY_TOUCH", "", "", "",
		"KEY_CSTICK_RIGHT", "KEY_CSTICK_LEFT", "KEY_CSTICK_UP", "KEY_CSTICK_DOWN",
		"KEY_CPAD_RIGHT", "KEY_CPAD_LEFT", "KEY_CPAD_UP", "KEY_CPAD_DOWN"
	};

	// Initialize services
	gfxInitDefault();

	//Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one
	consoleInit(GFX_TOP, NULL);

	struct state_t old_state = {0xffffffff, {0xffff, 0xffff}, {0xffff, 0xffff}, {0xffff, 0xffff}}; //In these variables there will be information about keys detected in the previous frame

	// Initialize the network
	struct network_t *n = networkInit("192.168.0.13", 16150);
	if (!n) {
		exitWithMessage("networkInit() failed.");
		return 1;
	}

	// Main loop
	while (aptMainLoop())
	{
		static struct state_t state;

		//Scan all the inputs. This should be done once for each frame
		hidScanInput();

		//hidKeysHeld returns information about which buttons have are held down in this frame
		state.keys = hidKeysHeld();

		//Read both pads position
		hidCircleRead(&state.pad);
		hidCstickRead(&state.cpad);

		// FIXME: use HOME instead
		if (state.keys & KEY_START) break; // break in order to return to hbmenu

		//Do the keys printing only if keys have changed
		if (memcmp(&state, &old_state, sizeof(struct state_t)))
		{
			//Clear console
			consoleClear();

			//Every line must be rewritten because we cleared the whole console
			printf("\x1b[0;0HPress Start to exit.\n");

			//Print both pads position
			printf("CirclePad position: %04d; %04d\n", state.pad.dx, state.pad.dy);
			printf("CPad position:      %04d; %04d\n", state.cpad.dx, state.cpad.dy);

			//Move the cursor to the fourth row because on the third one we'll write the circle pad position
			printf("\x1b[3;0H");

			//Check if some of the keys are down, held or up
			for (int i = 0; i < 32; i++)
			{
				if (state.keys & BIT(i))
					printf("%s\n", keysNames[i]);
			}

			if (sendState(n, &state) < 0) {
				exitWithMessage("sendState() failed.");
				return 1;
			}
		}

		//Set keys old values for the next frame
		memcpy(&old_state, &state, sizeof(struct state_t));

		// Flush and swap framebuffers
		gfxFlushBuffers();
		gfxSwapBuffers();

		//Wait for VBlank
		gspWaitForVBlank();
	}

	// Exit services
	exitWithMessage("Exiting...");
	return 0;
}