view source/main.c @ 2:5ee81fece0fa

Fill the .hgignore, so that binaries don’t get listed in hg st.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 22 Feb 2015 18:22:35 +0100
parents 5ba54fc65608
children 4c4be527a8d5
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>

static u32 *SOC_buffer = NULL;

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

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

	return fd;
}

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

	struct sockaddr_in *addr = calloc(1, sizeof(struct sockaddr_in));
	if (!addr) {
		printf("calloc() failed.\n");
		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) {
		printf("calloc() failed.\n");
		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) {
		printf("calloc() failed.\n");
		return NULL;
	}

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

	//struct sockaddr *addr = get_sockaddr_from_hostname(hostname, port);
	struct sockaddr *addr = get_sockaddr_from_ip(hostname, port);
	if (!addr)
		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 sendKeys(struct network_t *n, u32 keys)
{
	const char *msg = (const char*) &keys;
	int msglen = sizeof(keys);
	return sendto(n->udp_fd, msg, msglen, 0, n->addr, n->addr_size);
}

int main(int argc, char **argv)
{
	//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);

	u32 old_keys = 0; //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) {
		printf("HORROR!");
		fflush(stdout);
		gfxFlushBuffers();
		gfxSwapBuffers();
		for(;;);
	}

	printf("\x1b[0;0HPress Start to exit.");
	printf("\x1b[1;0HCirclePad position:");

	// Main loop
	while (aptMainLoop())
	{
		//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
		u32 keys = hidKeysHeld();

		//if (keys & KEY_START) break; // break in order to return to hbmenu

		//Do the keys printing only if keys have changed
		if (keys != old_keys)
		{
			//Clear console
			consoleClear();

			//These two lines must be rewritten because we cleared the whole console
			printf("\x1b[0;0HPress Start to exit.");
			printf("\x1b[1;0HCirclePad position:");

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

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

			if (sendKeys(n, keys) < 0) {
				perror("sendKeys");
				printf("HORROR! sendKeys()!");
				fflush(stdout);
				gfxFlushBuffers();
				gfxSwapBuffers();
				for(;;);
			}
		}

		//Set keys old values for the next frame
		old_keys = keys;

		circlePosition pos;

		//Read the CirclePad position
		hidCircleRead(&pos);

		//Print the CirclePad position
		printf("\x1b[2;0H%04d; %04d", pos.dx, pos.dy);

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

		//Wait for VBlank
		gspWaitForVBlank();
	}

	// Exit services
	gfxExit();
	return 0;
}