mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2026-10-28 09:43:51 +00:00
implement communication with pipe
also adds support for local Unix domain socket mode
This commit is contained in:
1 parent
03b163cef1
commit
94d86f5bba
29 files changed
+752
-299
No files matched your search
+159
-108
@@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "audio.h"
|
||||
@@ -25,83 +26,142 @@
|
||||
|
||||
static const uint32_t STOP_CODE = 0xCAFEBABE;
|
||||
static uint32_t SERVER_ADDRESS = 0;
|
||||
|
||||
uint16_t PORT_MSG;
|
||||
uint16_t PORT_VID;
|
||||
uint16_t PORT_AUD;
|
||||
uint16_t PORT_HID;
|
||||
uint16_t PORT_CMD;
|
||||
static const int MAX_PIPE_RETRY = 5;
|
||||
|
||||
#define EVENT_BUFFER_SIZE 65536
|
||||
#define EVENT_BUFFER_ARENA_SIZE VANILLA_MAX_EVENT_COUNT * 2
|
||||
uint8_t *EVENT_BUFFER_ARENA[EVENT_BUFFER_ARENA_SIZE] = {0};
|
||||
pthread_mutex_t event_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void send_to_console(int fd, const void *data, size_t data_size, int port)
|
||||
in_addr_t get_real_server_address()
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = SERVER_ADDRESS;
|
||||
address.sin_port = htons((uint16_t) (port - 100));
|
||||
if (SERVER_ADDRESS == VANILLA_ADDRESS_DIRECT) {
|
||||
// The Wii U always places itself at this address
|
||||
return inet_addr("192.168.1.10");
|
||||
} else if (SERVER_ADDRESS != VANILLA_ADDRESS_LOCAL) {
|
||||
// If there's a remote pipe, we send to that
|
||||
return htonl(SERVER_ADDRESS);
|
||||
}
|
||||
|
||||
ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &address, sizeof(address));
|
||||
if (sent == -1) {
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &address.sin_addr, ip, INET_ADDRSTRLEN);
|
||||
print_info("Failed to send to Wii U socket: address: %s, fd: %d, port: %d, errno: %i", ip, fd, port - 100, errno);
|
||||
// Must be local, in which case we don't care
|
||||
return INADDR_ANY;
|
||||
}
|
||||
|
||||
void create_sockaddr(struct sockaddr_in *in, struct sockaddr_un *un, const struct sockaddr **addr, size_t *size, in_addr_t inaddr, uint16_t port)
|
||||
{
|
||||
if (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) {
|
||||
memset(un, 0, sizeof(struct sockaddr_un));
|
||||
un->sun_family = AF_UNIX;
|
||||
snprintf(un->sun_path, sizeof(un->sun_path) - 1, VANILLA_PIPE_LOCAL_SOCKET, port);
|
||||
|
||||
if (size) *size = sizeof(struct sockaddr_un);
|
||||
if (addr) *addr = (const struct sockaddr *) un;
|
||||
} else {
|
||||
memset(in, 0, sizeof(struct sockaddr_in));
|
||||
in->sin_family = AF_INET;
|
||||
in->sin_port = htons(port);
|
||||
in->sin_addr.s_addr = inaddr;
|
||||
|
||||
if (size) *size = sizeof(struct sockaddr_in);
|
||||
if (addr) *addr = (const struct sockaddr *) in;
|
||||
}
|
||||
}
|
||||
|
||||
int create_socket(int *socket_out, uint16_t port)
|
||||
void send_to_console(int fd, const void *data, size_t data_size, uint16_t port)
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(port);
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_un un;
|
||||
const struct sockaddr *addr;
|
||||
size_t addr_size;
|
||||
|
||||
int skt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (skt == -1) {
|
||||
print_info("FAILED TO CREATE SOCKET FOR PORT %i", port);
|
||||
return 0;
|
||||
in_port_t console_port = port - 100;
|
||||
|
||||
create_sockaddr(&in, &un, &addr, &addr_size, get_real_server_address(), console_port);
|
||||
|
||||
ssize_t sent = sendto(fd, data, data_size, 0, addr, addr_size);
|
||||
if (sent == -1) {
|
||||
print_info("Failed to send to Wii U socket: fd: %d, port: %d, errno: %i", fd, console_port, errno);
|
||||
}
|
||||
}
|
||||
|
||||
int create_socket(int *socket_out, in_port_t port)
|
||||
{
|
||||
int skt = -1;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_in in;
|
||||
|
||||
create_sockaddr(&in, &un, 0, 0, INADDR_ANY, port);
|
||||
|
||||
if (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) {
|
||||
skt = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (skt == -1) {
|
||||
print_info("FAILED TO CREATE SOCKET: %i", errno);
|
||||
return VANILLA_ERR_BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (connect(skt, (const struct sockaddr *) &un, sizeof(un)) == -1) {
|
||||
print_info("FAILED TO CONNECT TO LOCAL SOCKET %u: %i", port, errno);
|
||||
close(skt);
|
||||
return VANILLA_ERR_PIPE_UNRESPONSIVE;
|
||||
}
|
||||
|
||||
print_info("SUCCESSFULLY CONNECTED SOCKET TO PATH %s", un.sun_path);
|
||||
} else {
|
||||
in.sin_addr.s_addr = INADDR_ANY;
|
||||
skt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (skt == -1) {
|
||||
print_info("FAILED TO CREATE SOCKET: %i", errno);
|
||||
return VANILLA_ERR_BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (bind(skt, (const struct sockaddr *) &in, sizeof(in)) == -1) {
|
||||
print_info("FAILED TO BIND PORT %u: %i", port, errno);
|
||||
close(skt);
|
||||
return VANILLA_ERR_BAD_SOCKET;
|
||||
}
|
||||
|
||||
print_info("SUCCESSFULLY BOUND SOCKET ON PORT %i", port);
|
||||
}
|
||||
|
||||
(*socket_out) = skt;
|
||||
|
||||
if (bind((*socket_out), (const struct sockaddr *) &address, sizeof(address)) == -1) {
|
||||
print_info("FAILED TO BIND PORT %u: %i", port, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_info("SUCCESSFULLY BOUND SOCKET %i on PORT %i", skt, port);
|
||||
return 1;
|
||||
return VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
void send_stop_code(int from_socket, in_port_t port)
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_un un;
|
||||
const struct sockaddr *addr;
|
||||
size_t addr_size;
|
||||
|
||||
address.sin_port = htons(port);
|
||||
sendto(from_socket, &STOP_CODE, sizeof(STOP_CODE), 0, (struct sockaddr *)&address, sizeof(address));
|
||||
// FIXME: There are probably better ways of stopping the sockets than this
|
||||
|
||||
create_sockaddr(&in, &un, &addr, &addr_size, inet_addr("127.0.0.1"), htons(port));
|
||||
sendto(from_socket, &STOP_CODE, sizeof(STOP_CODE), 0, addr, addr_size);
|
||||
}
|
||||
|
||||
int send_pipe_cc(int skt, uint32_t cc, int wait_for_reply)
|
||||
{
|
||||
struct sockaddr_in addr = {0};
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_un un;
|
||||
const struct sockaddr *addr;
|
||||
size_t addr_size;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = SERVER_ADDRESS;
|
||||
addr.sin_port = htons(VANILLA_PIPE_CMD_SERVER_PORT);
|
||||
create_sockaddr(&in, &un, &addr, &addr_size, get_real_server_address(), VANILLA_PIPE_CMD_PORT);
|
||||
|
||||
ssize_t read_size;
|
||||
uint32_t send_cc = htonl(cc);
|
||||
uint32_t recv_cc;
|
||||
|
||||
do {
|
||||
sendto(skt, &send_cc, sizeof(send_cc), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
for (int retries = 0; retries < MAX_PIPE_RETRY; retries++) {
|
||||
// sendto(skt, &send_cc, sizeof(send_cc), 0, addr, addr_size);
|
||||
if (write(skt, &send_cc, sizeof(send_cc)) == -1) {
|
||||
print_info("Failed to write control code to socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!wait_for_reply) {
|
||||
if (!wait_for_reply || is_interrupted()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -110,8 +170,10 @@ int send_pipe_cc(int skt, uint32_t cc, int wait_for_reply)
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_info("STILL WAITING FOR REPLY");
|
||||
|
||||
sleep(1);
|
||||
} while (!is_interrupted());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -119,9 +181,10 @@ int send_pipe_cc(int skt, uint32_t cc, int wait_for_reply)
|
||||
int connect_to_backend(int *socket, uint32_t cc)
|
||||
{
|
||||
// Try to bind with backend
|
||||
int pipe_cc_skt;
|
||||
if (!create_socket(&pipe_cc_skt, VANILLA_PIPE_CMD_CLIENT_PORT)) {
|
||||
return VANILLA_ERROR;
|
||||
int pipe_cc_skt = -1;
|
||||
int ret = create_socket(&pipe_cc_skt, VANILLA_PIPE_CMD_PORT);
|
||||
if (ret != VANILLA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct timeval tv = {0};
|
||||
@@ -131,7 +194,7 @@ int connect_to_backend(int *socket, uint32_t cc)
|
||||
if (!send_pipe_cc(pipe_cc_skt, cc, 1)) {
|
||||
print_info("FAILED TO BIND TO PIPE");
|
||||
close(pipe_cc_skt);
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_PIPE_UNRESPONSIVE;
|
||||
}
|
||||
|
||||
*socket = pipe_cc_skt;
|
||||
@@ -139,79 +202,67 @@ int connect_to_backend(int *socket, uint32_t cc)
|
||||
return VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
int sync_internal(uint16_t code, uint32_t server_address)
|
||||
void sync_internal(thread_data_t *data)
|
||||
{
|
||||
clear_interrupt();
|
||||
|
||||
if (server_address == 0) {
|
||||
SERVER_ADDRESS = inet_addr("192.168.1.10");
|
||||
} else {
|
||||
SERVER_ADDRESS = htonl(server_address);
|
||||
}
|
||||
|
||||
int skt = 0;
|
||||
int ret = VANILLA_ERROR;
|
||||
if (server_address != 0) {
|
||||
ret = connect_to_backend(&skt, VANILLA_PIPE_SYNC_CODE(code));
|
||||
if (ret != VANILLA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
SERVER_ADDRESS = data->server_address;
|
||||
|
||||
// Wait for sync result from pipe
|
||||
uint32_t recv_cc;
|
||||
while (1) {
|
||||
ssize_t read_size = recv(skt, &recv_cc, sizeof(recv_cc), 0);
|
||||
if (read_size == sizeof(recv_cc)) {
|
||||
recv_cc = ntohl(recv_cc);
|
||||
if (recv_cc >> 8 == VANILLA_PIPE_CC_SYNC_STATUS >> 8) {
|
||||
ret = recv_cc & 0xFF;
|
||||
uint16_t code = (uintptr_t) data->thread_data;
|
||||
|
||||
int skt = -1;
|
||||
int ret = connect_to_backend(&skt, VANILLA_PIPE_SYNC_CODE(code));
|
||||
|
||||
if (ret == VANILLA_SUCCESS) {
|
||||
// Wait for sync result from pipe
|
||||
uint32_t recv_cc;
|
||||
ret = VANILLA_ERR_PIPE_UNRESPONSIVE;
|
||||
for (int retries = 0; retries < MAX_PIPE_RETRY; retries++) {
|
||||
ssize_t read_size = recv(skt, &recv_cc, sizeof(recv_cc), 0);
|
||||
if (read_size == sizeof(recv_cc)) {
|
||||
recv_cc = ntohl(recv_cc);
|
||||
if (recv_cc >> 8 == VANILLA_PIPE_CC_SYNC_STATUS >> 8) {
|
||||
ret = recv_cc & 0xFF;
|
||||
break;
|
||||
} else if (recv_cc == VANILLA_PIPE_CC_SYNC_PING) {
|
||||
// Pipe is still responsive but hasn't found anything yet
|
||||
printf("received ping from pipe\n");
|
||||
retries = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_interrupted()) {
|
||||
send_pipe_cc(skt, VANILLA_PIPE_CC_UNBIND, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_interrupted()) {
|
||||
send_pipe_cc(skt, VANILLA_PIPE_CC_UNBIND, 0);
|
||||
break;
|
||||
}
|
||||
push_event(data->event_loop, VANILLA_EVENT_SYNC, &ret, sizeof(ret));
|
||||
|
||||
// Wait for interrupt so frontend has a chance to receive event
|
||||
while (!is_interrupted()) {
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
exit_pipe:
|
||||
if (skt)
|
||||
if (skt != -1)
|
||||
close(skt);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connect_as_gamepad_internal(event_loop_t *event_loop, uint32_t server_address)
|
||||
void connect_as_gamepad_internal(thread_data_t *data)
|
||||
{
|
||||
clear_interrupt();
|
||||
|
||||
PORT_MSG = 50110;
|
||||
PORT_VID = 50120;
|
||||
PORT_AUD = 50121;
|
||||
PORT_HID = 50122;
|
||||
PORT_CMD = 50123;
|
||||
|
||||
if (server_address == 0) {
|
||||
SERVER_ADDRESS = inet_addr("192.168.1.10");
|
||||
} else {
|
||||
SERVER_ADDRESS = htonl(server_address);
|
||||
PORT_MSG += 200;
|
||||
PORT_VID += 200;
|
||||
PORT_AUD += 200;
|
||||
PORT_HID += 200;
|
||||
PORT_CMD += 200;
|
||||
}
|
||||
SERVER_ADDRESS = data->server_address;
|
||||
|
||||
gamepad_context_t info;
|
||||
info.event_loop = event_loop;
|
||||
info.event_loop = data->event_loop;
|
||||
|
||||
int ret = VANILLA_ERROR;
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
|
||||
int pipe_cc_skt = 0;
|
||||
if (server_address != 0) {
|
||||
if (SERVER_ADDRESS != 0) {
|
||||
ret = connect_to_backend(&pipe_cc_skt, VANILLA_PIPE_CC_CONNECT);
|
||||
if (ret != VANILLA_SUCCESS) {
|
||||
goto exit;
|
||||
@@ -219,11 +270,11 @@ int connect_as_gamepad_internal(event_loop_t *event_loop, uint32_t server_addres
|
||||
}
|
||||
|
||||
// Open all required sockets
|
||||
if (!create_socket(&info.socket_vid, PORT_VID)) goto exit_pipe;
|
||||
if (!create_socket(&info.socket_msg, PORT_MSG)) goto exit_vid;
|
||||
if (!create_socket(&info.socket_hid, PORT_HID)) goto exit_msg;
|
||||
if (!create_socket(&info.socket_aud, PORT_AUD)) goto exit_hid;
|
||||
if (!create_socket(&info.socket_cmd, PORT_CMD)) goto exit_aud;
|
||||
if (create_socket(&info.socket_vid, PORT_VID) != VANILLA_SUCCESS) goto exit_pipe;
|
||||
if (create_socket(&info.socket_msg, PORT_MSG) != VANILLA_SUCCESS) goto exit_vid;
|
||||
if (create_socket(&info.socket_hid, PORT_HID) != VANILLA_SUCCESS) goto exit_msg;
|
||||
if (create_socket(&info.socket_aud, PORT_AUD) != VANILLA_SUCCESS) goto exit_hid;
|
||||
if (create_socket(&info.socket_cmd, PORT_CMD) != VANILLA_SUCCESS) goto exit_aud;
|
||||
|
||||
pthread_t video_thread, audio_thread, input_thread, msg_thread, cmd_thread;
|
||||
|
||||
@@ -255,7 +306,7 @@ int connect_as_gamepad_internal(event_loop_t *event_loop, uint32_t server_addres
|
||||
pthread_join(input_thread, NULL);
|
||||
pthread_join(cmd_thread, NULL);
|
||||
|
||||
if (server_address != 0) {
|
||||
if (SERVER_ADDRESS != 0) {
|
||||
send_pipe_cc(pipe_cc_skt, VANILLA_PIPE_CC_UNBIND, 0);
|
||||
}
|
||||
|
||||
@@ -281,7 +332,7 @@ exit_pipe:
|
||||
close(pipe_cc_skt);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
// TODO: Return error code to frontend?
|
||||
}
|
||||
|
||||
int is_stop_code(const char *data, size_t data_length)
|
||||
@@ -301,7 +352,7 @@ int push_event(event_loop_t *loop, int type, const void *data, size_t size)
|
||||
ev->data = get_event_buffer();
|
||||
if (!ev->data) {
|
||||
print_info("OUT OF MEMORY FOR NEW EVENTS");
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ev->type = type;
|
||||
|
||||
+14
-8
@@ -6,11 +6,7 @@
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint16_t PORT_MSG;
|
||||
extern uint16_t PORT_VID;
|
||||
extern uint16_t PORT_AUD;
|
||||
extern uint16_t PORT_HID;
|
||||
extern uint16_t PORT_CMD;
|
||||
#include "../pipe/ports.h"
|
||||
|
||||
struct wpa_ctrl;
|
||||
|
||||
@@ -35,9 +31,19 @@ typedef struct
|
||||
int socket_cmd;
|
||||
} gamepad_context_t;
|
||||
|
||||
int sync_internal(uint16_t code, uint32_t server_address);
|
||||
int connect_as_gamepad_internal(event_loop_t *ctx, uint32_t server_address);
|
||||
void send_to_console(int fd, const void *data, size_t data_size, int port);
|
||||
typedef struct thread_data_t thread_data_t;
|
||||
typedef void (*thread_start_t)(thread_data_t *);
|
||||
typedef struct thread_data_t
|
||||
{
|
||||
uint32_t server_address;
|
||||
event_loop_t *event_loop;
|
||||
thread_start_t thread_start;
|
||||
void *thread_data;
|
||||
} thread_data_t;
|
||||
|
||||
void sync_internal(thread_data_t *data);
|
||||
void connect_as_gamepad_internal(thread_data_t *data);
|
||||
void send_to_console(int fd, const void *data, size_t data_size, uint16_t port);
|
||||
int is_stop_code(const char *data, size_t data_length);
|
||||
int push_event(event_loop_t *loop, int type, const void *data, size_t size);
|
||||
int get_event(event_loop_t *loop, vanilla_event_t *event, int wait);
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ void print_info(const char *errstr, ...)
|
||||
va_list args;
|
||||
va_start(args, errstr);
|
||||
|
||||
vanilla_log_no_newline(VANILLA_STATUS_STRINGS[-VANILLA_INFO]);
|
||||
vanilla_log_no_newline(" ");
|
||||
// vanilla_log_no_newline(VANILLA_STATUS_STRINGS[-VANILLA_INFO]);
|
||||
// vanilla_log_no_newline(" ");
|
||||
vanilla_log_no_newline_va(errstr, args);
|
||||
vanilla_log_no_newline("\n");
|
||||
|
||||
|
||||
+22
-14
@@ -20,14 +20,9 @@ pthread_mutex_t main_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t gamepad_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
event_loop_t event_loop = {{0}, 0, 0, 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
|
||||
|
||||
struct gamepad_data_t
|
||||
void *start_event_loop(void *arg)
|
||||
{
|
||||
uint32_t server_address;
|
||||
};
|
||||
|
||||
void *start_gamepad(void *arg)
|
||||
{
|
||||
struct gamepad_data_t *data = (struct gamepad_data_t *) arg;
|
||||
thread_data_t *data = (thread_data_t *) arg;
|
||||
|
||||
pthread_mutex_lock(&event_loop.mutex);
|
||||
init_event_buffer_arena();
|
||||
@@ -40,12 +35,22 @@ void *start_gamepad(void *arg)
|
||||
pthread_cond_broadcast(&event_loop.waitcond);
|
||||
pthread_mutex_unlock(&event_loop.mutex);
|
||||
|
||||
connect_as_gamepad_internal(&event_loop, data->server_address);
|
||||
data->event_loop = &event_loop;
|
||||
|
||||
data->thread_start(data);
|
||||
free(data);
|
||||
|
||||
pthread_mutex_lock(&event_loop.mutex);
|
||||
event_loop.active = 0;
|
||||
|
||||
// Free any unconsumed events
|
||||
while (event_loop.used_index < event_loop.new_index) {
|
||||
// Output data to pointer
|
||||
vanilla_event_t *pull_event = &event_loop.events[event_loop.used_index % VANILLA_MAX_EVENT_COUNT];
|
||||
vanilla_free_event(pull_event);
|
||||
event_loop.used_index++;
|
||||
}
|
||||
|
||||
free_event_buffer_arena();
|
||||
pthread_cond_broadcast(&event_loop.waitcond);
|
||||
pthread_mutex_unlock(&event_loop.mutex);
|
||||
@@ -54,19 +59,21 @@ void *start_gamepad(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vanilla_start_internal(uint32_t server_address)
|
||||
int vanilla_start_internal(uint32_t server_address, thread_start_t thread_start, void *thread_data)
|
||||
{
|
||||
if (pthread_mutex_trylock(&main_mutex) == 0) {
|
||||
pthread_t other;
|
||||
|
||||
struct gamepad_data_t *data = malloc(sizeof(struct gamepad_data_t));
|
||||
thread_data_t *data = malloc(sizeof(thread_data_t));
|
||||
data->server_address = server_address;
|
||||
data->thread_start = thread_start;
|
||||
data->thread_data = thread_data;
|
||||
|
||||
// Lock event loop mutex so it can't be set to active until we're ready
|
||||
pthread_mutex_lock(&event_loop.mutex);
|
||||
|
||||
// Start other thread (which will set event loop to active)
|
||||
pthread_create(&other, NULL, start_gamepad, data);
|
||||
pthread_create(&other, NULL, start_event_loop, data);
|
||||
pthread_setname_np(other, "vanilla-gamepad");
|
||||
|
||||
// Wait for event loop to be set active before returning
|
||||
@@ -77,13 +84,14 @@ int vanilla_start_internal(uint32_t server_address)
|
||||
|
||||
return VANILLA_SUCCESS;
|
||||
} else {
|
||||
return VANILLA_ERROR;
|
||||
// We're already doing something
|
||||
return VANILLA_ERR_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
int vanilla_start(uint32_t server_address)
|
||||
{
|
||||
return vanilla_start_internal(server_address);
|
||||
return vanilla_start_internal(server_address, connect_as_gamepad_internal, 0);
|
||||
}
|
||||
|
||||
void vanilla_stop()
|
||||
@@ -164,7 +172,7 @@ void vanilla_set_battery_status(int battery_status)
|
||||
|
||||
int vanilla_sync(uint16_t code, uint32_t server_address)
|
||||
{
|
||||
return sync_internal(code, server_address);
|
||||
return vanilla_start_internal(server_address, sync_internal, (void *) (uintptr_t) code);
|
||||
}
|
||||
|
||||
int vanilla_poll_event(vanilla_event_t *event)
|
||||
|
||||
+14
-8
@@ -9,12 +9,17 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static const int VANILLA_SUCCESS = 0;
|
||||
static const int VANILLA_ERROR = -1;
|
||||
static const int VANILLA_READY = -2;
|
||||
static const int VANILLA_INFO = -3;
|
||||
static const int VANILLA_UNKNOWN_COMMAND = -4;
|
||||
static const int VANILLA_INVALID_ARGUMENT = -5;
|
||||
static const int VANILLA_SUCCESS = 0;
|
||||
static const int VANILLA_ERR_GENERIC = -1;
|
||||
static const int VANILLA_ERR_UNKNOWN_COMMAND = -2;
|
||||
static const int VANILLA_ERR_INVALID_ARGUMENT = -3;
|
||||
static const int VANILLA_ERR_PIPE_UNRESPONSIVE = -4;
|
||||
static const int VANILLA_ERR_OUT_OF_MEMORY = -5;
|
||||
static const int VANILLA_ERR_BUSY = -6;
|
||||
static const int VANILLA_ERR_BAD_SOCKET = -7;
|
||||
|
||||
static const uint32_t VANILLA_ADDRESS_LOCAL = 0xFFFFFFFF;
|
||||
static const uint32_t VANILLA_ADDRESS_DIRECT = 0x0;
|
||||
|
||||
enum VanillaGamepadButtons
|
||||
{
|
||||
@@ -63,7 +68,8 @@ enum VanillaEvent
|
||||
VANILLA_EVENT_NONE,
|
||||
VANILLA_EVENT_VIDEO,
|
||||
VANILLA_EVENT_AUDIO,
|
||||
VANILLA_EVENT_VIBRATE
|
||||
VANILLA_EVENT_VIBRATE,
|
||||
VANILLA_EVENT_SYNC
|
||||
};
|
||||
|
||||
enum VanillaRegion
|
||||
@@ -136,7 +142,7 @@ void vanilla_set_button(int button, int32_t value);
|
||||
*
|
||||
* This can be called from another thread to change the button state while vanilla_connect_to_console() is running.
|
||||
*
|
||||
* `x` and `y` are expected to be in gamepad screen coordinates (0x0 to 853x479).
|
||||
* `x` and `y` are expected to be in gamepad screen coordinates (0x0 to 853x479 inclusive).
|
||||
* If either `x` or `y` are -1, this point will be disabled.
|
||||
*/
|
||||
void vanilla_set_touch(int x, int y);
|
||||
|
||||
+4
-2
@@ -1,15 +1,17 @@
|
||||
#ifndef VANILLA_PIPE_DEF_H
|
||||
#define VANILLA_PIPE_DEF_H
|
||||
|
||||
#define VANILLA_PIPE_CMD_SERVER_PORT 51000
|
||||
#define VANILLA_PIPE_CMD_CLIENT_PORT 51001
|
||||
#define VANILLA_PIPE_CMD_PORT 51000
|
||||
#define VANILLA_PIPE_CC_SYNC 0x56530000
|
||||
#define VANILLA_PIPE_CC_CONNECT 0x56414249
|
||||
#define VANILLA_PIPE_CC_BIND_ACK 0x56414245
|
||||
#define VANILLA_PIPE_CC_SYNC_STATUS 0x53595300
|
||||
#define VANILLA_PIPE_CC_SYNC_PING 0x5359504E
|
||||
#define VANILLA_PIPE_CC_BUSY 0x56414255
|
||||
#define VANILLA_PIPE_CC_UNBIND 0x5641554E
|
||||
|
||||
#define VANILLA_PIPE_SYNC_CODE(x) (VANILLA_PIPE_CC_SYNC | (x & 0xFFFF))
|
||||
|
||||
#define VANILLA_PIPE_LOCAL_SOCKET "/tmp/vanilla-pipe.%i"
|
||||
|
||||
#endif // VANILLA_PIPE_DEF_H
|
||||
+29
-6
@@ -13,11 +13,11 @@ int main(int argc, const char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
if (argc != 3) {
|
||||
pprint("vanilla-pipe - brokers a connection between Vanilla and the Wii U\n");
|
||||
pprint("--------------------------------------------------------------------------------\n");
|
||||
pprint("\n");
|
||||
pprint("Usage: %s <wireless-interface>\n", argv[0]);
|
||||
pprint("Usage: %s <-local | -udp> <wireless-interface>\n", argv[0]);
|
||||
pprint("\n");
|
||||
pprint("Connecting to the Wii U as a gamepad requires some modifications to the 802.11n\n");
|
||||
pprint("protocol, and not all platforms allow such modifications to be made.\n");
|
||||
@@ -33,16 +33,39 @@ int main(int argc, const char **argv)
|
||||
pprint("embedded devices such as MCUs or SBCs, providing more versatility in hardware\n");
|
||||
pprint("configurations.\n");
|
||||
pprint("\n");
|
||||
pprint("`vanilla-pipe` cannot be controlled directly, it can only be controlled via UDP\n");
|
||||
pprint("sockets by a compatible frontend.\n");
|
||||
pprint("`vanilla-pipe` cannot be controlled directly, it can only be controlled via\n");
|
||||
pprint("sockets by a compatible frontend. By choosing '-local' or '-udp', you can\n");
|
||||
pprint("choose what type of socket to use to best suit the environment.\n");
|
||||
pprint("\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *wireless_interface = argv[1];
|
||||
int udp_mode = 0;
|
||||
int local_mode = 0;
|
||||
const char *wireless_interface = 0;
|
||||
|
||||
vanilla_listen(wireless_interface);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-udp")) {
|
||||
udp_mode = 1;
|
||||
} else if (!strcmp(argv[i], "-local")) {
|
||||
local_mode = 1;
|
||||
} else {
|
||||
wireless_interface = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (udp_mode == local_mode) {
|
||||
pprint("Must choose either '-local' OR '-udp'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!wireless_interface) {
|
||||
pprint("Must identify a wireless interface to use\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vanilla_listen(local_mode, wireless_interface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+129
-64
@@ -13,12 +13,13 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <wpa_ctrl.h>
|
||||
|
||||
#include "../def.h"
|
||||
#include "ports.h"
|
||||
#include "../ports.h"
|
||||
#include "status.h"
|
||||
#include "util.h"
|
||||
#include "vanilla.h"
|
||||
@@ -51,10 +52,13 @@ struct sync_args {
|
||||
uint16_t code;
|
||||
void *(*start_routine)(void *);
|
||||
struct wpa_ctrl *ctrl;
|
||||
int local;
|
||||
int skt;
|
||||
};
|
||||
|
||||
struct relay_info {
|
||||
const char *wireless_interface;
|
||||
int local;
|
||||
in_port_t port;
|
||||
};
|
||||
|
||||
@@ -226,7 +230,7 @@ int start_process(const char **argv, pid_t *pid_out, int *stdout_pipe, int *stde
|
||||
_exit(1);
|
||||
} else if (pid < 0) {
|
||||
// Fork error
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
} else {
|
||||
// Continuation of parent
|
||||
close(out_pipes[1]);
|
||||
@@ -293,7 +297,7 @@ int start_wpa_supplicant(const char *wireless_interface, const char *config_file
|
||||
// Give up
|
||||
give_up:
|
||||
kill((*pid), SIGTERM);
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,6 +311,13 @@ void quit_loop()
|
||||
pthread_mutex_unlock(&running_mutex);
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
pthread_mutex_lock(&running_mutex);
|
||||
running = 0;
|
||||
pthread_mutex_unlock(&running_mutex);
|
||||
}
|
||||
|
||||
void sigint_handler(int signum)
|
||||
{
|
||||
if (signum == SIGINT) {
|
||||
@@ -341,7 +352,7 @@ void *read_stdin(void *)
|
||||
|
||||
void *wpa_setup_environment(void *data)
|
||||
{
|
||||
void *ret = THREADRESULT(VANILLA_ERROR);
|
||||
void *ret = THREADRESULT(VANILLA_ERR_GENERIC);
|
||||
|
||||
struct sync_args *args = (struct sync_args *) data;
|
||||
|
||||
@@ -446,7 +457,7 @@ int call_dhcp(const char *network_interface, pid_t *dhclient_pid)
|
||||
print_info("FAILED TO ESTABLISH DHCP");
|
||||
kill(*dhclient_pid, SIGTERM);
|
||||
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,11 +483,11 @@ int is_networkmanager_managing_device(const char *wireless_interface, int *is_ma
|
||||
if (!WIFEXITED(status)) {
|
||||
// Something went wrong
|
||||
print_info("NMCLI DID NOT EXIT NORMALLY");
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
|
||||
char buf[100];
|
||||
int ret = VANILLA_ERROR;
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
while (read_line_from_fd(pipe, buf, sizeof(buf))) {
|
||||
if (memcmp(buf, "GENERAL.STATE", 13) == 0) {
|
||||
*is_managed = !strstr(buf, "unmanaged");
|
||||
@@ -505,7 +516,7 @@ int set_networkmanager_on_device(const char *wireless_interface, int on)
|
||||
if (WIFEXITED(status)) {
|
||||
return VANILLA_SUCCESS;
|
||||
} else {
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,14 +565,29 @@ relay_ports create_ports(int from_socket, in_port_t from_port, int to_socket, in
|
||||
return ports;
|
||||
}
|
||||
|
||||
int open_socket(in_port_t port)
|
||||
int open_socket(int local, in_port_t port)
|
||||
{
|
||||
struct sockaddr_in in = {0};
|
||||
in.sin_family = AF_INET;
|
||||
in.sin_addr.s_addr = INADDR_ANY;
|
||||
in.sin_port = htons(port);
|
||||
|
||||
int skt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
struct sockaddr_un un = {0};
|
||||
|
||||
const struct sockaddr *sa;
|
||||
size_t sa_size;
|
||||
|
||||
int skt;
|
||||
if (local) {
|
||||
skt = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
un.sun_family = AF_UNIX;
|
||||
snprintf(un.sun_path, sizeof(un.sun_path) - 1, VANILLA_PIPE_LOCAL_SOCKET, port);
|
||||
sa = (const struct sockaddr *) &un;
|
||||
sa_size = sizeof(un);
|
||||
} else {
|
||||
skt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
in.sin_family = AF_INET;
|
||||
in.sin_addr.s_addr = INADDR_ANY;
|
||||
in.sin_port = htons(port);
|
||||
sa = (const struct sockaddr *) ∈
|
||||
sa_size = sizeof(in);
|
||||
}
|
||||
if (skt == -1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -570,12 +596,18 @@ int open_socket(in_port_t port)
|
||||
tv.tv_usec = 250000;
|
||||
setsockopt(skt, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
if (bind(skt, (const struct sockaddr *) &in, sizeof(in)) == -1) {
|
||||
print_info("FAILED TO BIND PORT %u: %i\n", port, errno);
|
||||
if (bind(skt, sa, sa_size) == -1) {
|
||||
print_info("FAILED TO BIND PORT %u: %i", port, errno);
|
||||
close(skt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local) {
|
||||
if (listen(skt, 20) == -1) {
|
||||
print_info("FAILED TO LISTEN ON LOCAL SOCKET: %i", errno);
|
||||
}
|
||||
}
|
||||
|
||||
return skt;
|
||||
}
|
||||
|
||||
@@ -586,7 +618,7 @@ void *open_relay(void *data)
|
||||
int ret = -1;
|
||||
|
||||
// Open an incoming port from the console
|
||||
int from_console = open_socket(port);
|
||||
int from_console = open_socket(0, port);
|
||||
if (from_console == -1) {
|
||||
goto close;
|
||||
}
|
||||
@@ -594,7 +626,7 @@ void *open_relay(void *data)
|
||||
setsockopt(from_console, SOL_SOCKET, SO_BINDTODEVICE, info->wireless_interface, strlen(info->wireless_interface));
|
||||
|
||||
// Open an incoming port from the frontend
|
||||
int from_frontend = open_socket(port + 100);
|
||||
int from_frontend = open_socket(info->local, port + 100);
|
||||
if (from_frontend == -1) {
|
||||
goto close_console_connection;
|
||||
}
|
||||
@@ -631,13 +663,14 @@ close:
|
||||
return THREADRESULT(ret);
|
||||
}
|
||||
|
||||
void create_all_relays(const char *wireless_interface)
|
||||
void create_all_relays(int local, const char *wireless_interface)
|
||||
{
|
||||
pthread_t vid_thread, aud_thread, msg_thread, cmd_thread, hid_thread;
|
||||
struct relay_info vid_info, aud_info, msg_info, cmd_info, hid_info;
|
||||
|
||||
// Set wireless interface on all
|
||||
// Set common info for all
|
||||
vid_info.wireless_interface = aud_info.wireless_interface = msg_info.wireless_interface = cmd_info.wireless_interface = hid_info.wireless_interface = wireless_interface;
|
||||
vid_info.local = aud_info.local = msg_info.local = cmd_info.local = hid_info.local = local;
|
||||
|
||||
vid_info.port = PORT_VID;
|
||||
aud_info.port = PORT_AUD;
|
||||
@@ -670,9 +703,7 @@ void *thread_handler(void *data)
|
||||
|
||||
free(args);
|
||||
|
||||
pthread_mutex_lock(&running_mutex);
|
||||
running = 0;
|
||||
pthread_mutex_unlock(&running_mutex);
|
||||
interrupt();
|
||||
|
||||
// Locked by calling thread
|
||||
pthread_mutex_unlock(&action_mutex);
|
||||
@@ -751,14 +782,14 @@ int create_connect_config(const char *input_config, const char *bssid)
|
||||
FILE *in_file = fopen(input_config, "r");
|
||||
if (!in_file) {
|
||||
print_info("FAILED TO OPEN INPUT CONFIG FILE");
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
|
||||
FILE *out_file = fopen(get_wireless_connect_config_filename(), "w");
|
||||
if (!out_file) {
|
||||
print_info("FAILED TO OPEN OUTPUT CONFIG FILE");
|
||||
fclose(in_file);
|
||||
return VANILLA_ERROR;
|
||||
return VANILLA_ERR_GENERIC;
|
||||
}
|
||||
|
||||
int len;
|
||||
@@ -800,6 +831,13 @@ void *sync_with_console_internal(void *data)
|
||||
while (1) {
|
||||
if (is_interrupted()) goto exit_loop;
|
||||
|
||||
uint32_t cc = htonl(VANILLA_PIPE_CC_SYNC_PING);
|
||||
if (send(args->skt, &cc, sizeof(cc), MSG_NOSIGNAL) == -1) {
|
||||
// Client has probably disconnected
|
||||
interrupt();
|
||||
goto exit_loop;
|
||||
}
|
||||
|
||||
// print_info("SCANNING");
|
||||
actual_buf_len = buf_len;
|
||||
wpa_ctrl_command(args->ctrl, "SCAN", buf, &actual_buf_len);
|
||||
@@ -884,7 +922,7 @@ void *sync_with_console_internal(void *data)
|
||||
} while (!found_console);
|
||||
|
||||
exit_loop:
|
||||
return THREADRESULT(found_console ? VANILLA_SUCCESS : VANILLA_ERROR);
|
||||
return THREADRESULT(found_console ? VANILLA_SUCCESS : VANILLA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
void *do_connect(void *data)
|
||||
@@ -896,7 +934,7 @@ void *do_connect(void *data)
|
||||
sleep(2);
|
||||
print_info("WAITING FOR CONNECTION");
|
||||
|
||||
if (is_interrupted()) return THREADRESULT(VANILLA_ERROR);
|
||||
if (is_interrupted()) return THREADRESULT(VANILLA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
@@ -911,7 +949,7 @@ void *do_connect(void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_interrupted()) return THREADRESULT(VANILLA_ERROR);
|
||||
if (is_interrupted()) return THREADRESULT(VANILLA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
print_info("CONNECTED TO CONSOLE");
|
||||
@@ -926,7 +964,7 @@ void *do_connect(void *data)
|
||||
print_info("DHCP ESTABLISHED");
|
||||
}
|
||||
|
||||
create_all_relays(args->wireless_interface);
|
||||
create_all_relays(args->local, args->wireless_interface);
|
||||
|
||||
int kill_ret = kill(dhclient_pid, SIGTERM);
|
||||
print_info("KILLING DHCLIENT %i", dhclient_pid);
|
||||
@@ -945,7 +983,7 @@ void *vanilla_sync_with_console(void *data)
|
||||
config = fopen(wireless_conf_file, "w");
|
||||
if (!config) {
|
||||
print_info("FAILED TO WRITE TEMP CONFIG: %s", wireless_conf_file);
|
||||
return THREADRESULT(VANILLA_ERROR);
|
||||
return THREADRESULT(VANILLA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
fprintf(config, "ctrl_interface=%s\nupdate_config=1\n", wpa_ctrl_interface);
|
||||
@@ -972,9 +1010,12 @@ void *vanilla_connect_to_console(void *data)
|
||||
return wpa_setup_environment(args);
|
||||
}
|
||||
|
||||
void vanilla_listen(const char *wireless_interface)
|
||||
void vanilla_listen(int local, const char *wireless_interface)
|
||||
{
|
||||
int skt = open_socket(VANILLA_PIPE_CMD_SERVER_PORT);
|
||||
// Ensure local domain sockets can be written to by everyone
|
||||
umask(0000);
|
||||
|
||||
int skt = open_socket(local, VANILLA_PIPE_CMD_PORT);
|
||||
if (skt == -1) {
|
||||
pprint("Failed to open server socket\n");
|
||||
return;
|
||||
@@ -1013,46 +1054,70 @@ void vanilla_listen(const char *wireless_interface)
|
||||
}
|
||||
pthread_mutex_unlock(&sync_mutex);
|
||||
|
||||
ssize_t r = recvfrom(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, &addr_size);
|
||||
if (r <= 0) {
|
||||
int data_socket = accept(skt, 0, 0);
|
||||
if (data_socket == -1) {
|
||||
if (errno != EAGAIN)
|
||||
print_info("Failed to accept: %i", errno);
|
||||
goto repeat_loop;
|
||||
}
|
||||
|
||||
control_code = ntohl(control_code);
|
||||
pthread_mutex_lock(&main_loop_mutex);
|
||||
|
||||
if ((control_code >> 16) == (VANILLA_PIPE_CC_SYNC >> 16) || control_code == VANILLA_PIPE_CC_CONNECT) {
|
||||
print_info("RECEIVED SYNC/CONNECT SIGNAL");
|
||||
|
||||
if (pthread_mutex_trylock(&action_mutex) == 0) {
|
||||
struct sync_args *args = malloc(sizeof(struct sync_args));
|
||||
args->wireless_interface = wireless_interface;
|
||||
args->code = control_code & 0xFFFF;
|
||||
args->start_routine = (control_code == VANILLA_PIPE_CC_CONNECT) ? vanilla_connect_to_console : vanilla_sync_with_console;
|
||||
|
||||
client_address = addr.sin_addr;
|
||||
while (main_loop) {
|
||||
pthread_mutex_unlock(&main_loop_mutex);
|
||||
|
||||
// Acknowledge
|
||||
control_code = htonl(VANILLA_PIPE_CC_BIND_ACK);
|
||||
sendto(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
|
||||
pthread_t thread;
|
||||
int thread_ret;
|
||||
if (pthread_create(&thread, NULL, thread_handler, args) != 0) {
|
||||
print_info("FAILED TO CREATE THREAD");
|
||||
free(args);
|
||||
}
|
||||
} else {
|
||||
// Busy
|
||||
control_code = htonl(VANILLA_PIPE_CC_BUSY);
|
||||
sendto(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
// ssize_t r = recvfrom(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, &addr_size);
|
||||
ssize_t r = read(data_socket, &control_code, sizeof(control_code));
|
||||
if (r <= 0) {
|
||||
break;
|
||||
}
|
||||
} else if (control_code == VANILLA_PIPE_CC_UNBIND) {
|
||||
print_info("RECEIVED UNBIND SIGNAL");
|
||||
pthread_mutex_lock(&running_mutex);
|
||||
running = 0;
|
||||
pthread_mutex_unlock(&running_mutex);
|
||||
|
||||
control_code = ntohl(control_code);
|
||||
|
||||
if ((control_code >> 16) == (VANILLA_PIPE_CC_SYNC >> 16) || control_code == VANILLA_PIPE_CC_CONNECT) {
|
||||
if (pthread_mutex_trylock(&action_mutex) == 0) {
|
||||
struct sync_args *args = malloc(sizeof(struct sync_args));
|
||||
args->wireless_interface = wireless_interface;
|
||||
args->code = control_code & 0xFFFF;
|
||||
args->local = local;
|
||||
args->start_routine = (control_code == VANILLA_PIPE_CC_CONNECT) ? vanilla_connect_to_console : vanilla_sync_with_console;
|
||||
args->skt = data_socket;
|
||||
|
||||
client_address = addr.sin_addr;
|
||||
|
||||
// Acknowledge
|
||||
control_code = htonl(VANILLA_PIPE_CC_BIND_ACK);
|
||||
// sendto(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
write(data_socket, &control_code, sizeof(control_code));
|
||||
|
||||
pthread_t thread;
|
||||
int thread_ret;
|
||||
if (pthread_create(&thread, NULL, thread_handler, args) != 0) {
|
||||
print_info("FAILED TO CREATE THREAD");
|
||||
free(args);
|
||||
}
|
||||
} else {
|
||||
// Busy
|
||||
control_code = htonl(VANILLA_PIPE_CC_BUSY);
|
||||
// sendto(skt, &control_code, sizeof(control_code), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
write(data_socket, &control_code, sizeof(control_code));
|
||||
}
|
||||
} else if (control_code == VANILLA_PIPE_CC_UNBIND) {
|
||||
print_info("RECEIVED UNBIND SIGNAL");
|
||||
interrupt();
|
||||
}
|
||||
|
||||
repeat_read_loop:
|
||||
pthread_mutex_lock(&main_loop_mutex);
|
||||
}
|
||||
|
||||
if (data_socket != -1) {
|
||||
close(data_socket);
|
||||
data_socket = -1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&main_loop_mutex);
|
||||
|
||||
repeat_loop:
|
||||
pthread_mutex_lock(&main_loop_mutex);
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,6 +19,6 @@ int enable_networkmanager_on_device(const char *wireless_interface);
|
||||
|
||||
void pprint(const char *fmt, ...);
|
||||
|
||||
void vanilla_listen(const char *wireless_interface);
|
||||
void vanilla_listen(int local, const char *wireless_interface);
|
||||
|
||||
#endif // VANILLA_WPA_H
|
||||
File renamed without changes.
@@ -5,9 +5,12 @@ find_package(FFmpeg REQUIRED COMPONENTS avformat avcodec avutil avfilter swscale
|
||||
|
||||
add_executable(vanilla-pi
|
||||
drm.c
|
||||
lang.c
|
||||
main2.c
|
||||
menu/menu.c
|
||||
menu/menu_common.c
|
||||
menu/menu_main.c
|
||||
menu/menu_sudo.c
|
||||
menu/menu_sync.c
|
||||
ui/ui.c
|
||||
ui/ui_anim.c
|
||||
@@ -21,6 +24,7 @@ install(TARGETS vanilla-pi)
|
||||
target_include_directories(vanilla-pi PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/lib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
|
||||
# xf86drm.h needs this
|
||||
/usr/include/libdrm
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#include "lang.h"
|
||||
|
||||
static const char *lang_str[__VPI_LANG_T_COUNT] = {
|
||||
"Sync",
|
||||
"Connect",
|
||||
"Edit",
|
||||
"Settings",
|
||||
"OK",
|
||||
"Cancel",
|
||||
"Touch the symbols in the order they are displayed on the TV screen from left to right.",
|
||||
"If the symbols are not displayed on the TV screen, press the SYNC Button on the Wii U console.",
|
||||
"Connecting to the Wii U console...",
|
||||
"Sync Failed",
|
||||
"Vanilla needs root permission to configure the wireless interface for connection.",
|
||||
"Please enter your \"sudo\" password here.",
|
||||
};
|
||||
|
||||
const char *lang(vpi_lang_t id)
|
||||
{
|
||||
return lang_str[id];
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#ifndef VANILLA_PI_LANG_H
|
||||
#define VANILLA_PI_LANG_H
|
||||
|
||||
typedef enum {
|
||||
VPI_LANG_SYNC_BTN,
|
||||
VPI_LANG_CONNECT_BTN,
|
||||
VPI_LANG_EDIT_BTN,
|
||||
VPI_LANG_SETTINGS_BTN,
|
||||
VPI_LANG_OK_BTN,
|
||||
VPI_LANG_CANCEL_BTN,
|
||||
VPI_LANG_SYNC_HELP_1,
|
||||
VPI_LANG_SYNC_HELP_2,
|
||||
VPI_LANG_SYNC_CONNECTING,
|
||||
VPI_LANG_SYNC_FAILED,
|
||||
VPI_LANG_SUDO_HELP_1,
|
||||
VPI_LANG_SUDO_HELP_2,
|
||||
__VPI_LANG_T_COUNT
|
||||
} vpi_lang_t;
|
||||
|
||||
const char *lang(vpi_lang_t id);
|
||||
|
||||
#endif // VANILLA_PI_LANG_H
|
||||
+1
-1
@@ -27,7 +27,7 @@ int main(int argc, const char **argv)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
vanilla_menu_init(vui);
|
||||
vpi_menu_init(vui);
|
||||
|
||||
while (vui_update_sdl(vui)) {
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
|
||||
#include "menu_main.h"
|
||||
|
||||
void vanilla_menu_init(vui_context_t *vui)
|
||||
void vpi_menu_init(vui_context_t *vui)
|
||||
{
|
||||
// Start with main menu
|
||||
vanilla_menu_main(vui, 0);
|
||||
vpi_menu_main(vui, 0);
|
||||
}
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vanilla_menu_init(vui_context_t *vui);
|
||||
void vpi_menu_init(vui_context_t *vui);
|
||||
|
||||
#endif // VANILLA_PI_MENU_H
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "menu_common.h"
|
||||
|
||||
void vpi_menu_create_background(vui_context_t *vui, int layer, vui_rect_t *bkg_rect, int *margin)
|
||||
{
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
int m = scrw/75;
|
||||
*margin = m;
|
||||
bkg_rect->x = m;
|
||||
bkg_rect->y = m;
|
||||
bkg_rect->w = scrw-m-m;
|
||||
bkg_rect->h = scrh-m-m;
|
||||
|
||||
vui_rect_create(vui, bkg_rect->x, bkg_rect->y, bkg_rect->w, bkg_rect->h, scrh*2/10, vui_color_create(0, 0, 0, 0.66f), layer);
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef VANILLA_MENU_COMMON_H
|
||||
#define VANILLA_MENU_COMMON_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
#define BTN_SZ 80
|
||||
|
||||
void vpi_menu_create_background(vui_context_t *vui, int layer, vui_rect_t *bkg_rect, int *margin);
|
||||
|
||||
#endif // VANILLA_MENU_COMMON_H
|
||||
+20
-19
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lang.h"
|
||||
#include "menu_common.h"
|
||||
#include "menu_sync.h"
|
||||
#include "ui/ui_anim.h"
|
||||
@@ -15,12 +16,12 @@ static int main_menu_current = 0;
|
||||
|
||||
static int console_menu_layer = 0;
|
||||
|
||||
void vanilla_menu_main_sync_action(vui_context_t *vui, int btn, void *v)
|
||||
void vpi_menu_main_sync_action(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vanilla_menu_sync, 0);
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vpi_menu_sync, 0);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_populate(vui_context_t *vui)
|
||||
void vpi_menu_main_populate(vui_context_t *vui)
|
||||
{
|
||||
for (int i = 0; i < MAIN_MENU_ENTRIES; i++) {
|
||||
int b = main_menu_btns[i];
|
||||
@@ -30,7 +31,7 @@ void vanilla_menu_main_populate(vui_context_t *vui)
|
||||
}
|
||||
}
|
||||
|
||||
void vanilla_menu_main_finish_transition(vui_context_t *vui, void *v)
|
||||
void vpi_menu_main_finish_transition(vui_context_t *vui, void *v)
|
||||
{
|
||||
intptr_t data = (intptr_t) v;
|
||||
|
||||
@@ -39,32 +40,32 @@ void vanilla_menu_main_finish_transition(vui_context_t *vui, void *v)
|
||||
|
||||
main_menu_current = target;
|
||||
|
||||
vanilla_menu_main_populate(vui);
|
||||
vpi_menu_main_populate(vui);
|
||||
|
||||
vui_transition_fade_layer_in(vui, layer, 0, 0);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_start_transition(vui_context_t *vui, int layer, int to)
|
||||
void vpi_menu_main_start_transition(vui_context_t *vui, int layer, int to)
|
||||
{
|
||||
if (to < 0) {
|
||||
// Can't go into negatives
|
||||
return;
|
||||
}
|
||||
|
||||
vui_transition_fade_layer_out(vui, layer, vanilla_menu_main_finish_transition, (void *) (intptr_t) (layer | to << 8));
|
||||
vui_transition_fade_layer_out(vui, layer, vpi_menu_main_finish_transition, (void *) (intptr_t) (layer | to << 8));
|
||||
}
|
||||
|
||||
void vanilla_menu_main_left_arrow(vui_context_t *vui, int btn, void *v)
|
||||
void vpi_menu_main_left_arrow(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vanilla_menu_main_start_transition(vui, (intptr_t) v, main_menu_current - MAIN_MENU_ENTRIES);
|
||||
vpi_menu_main_start_transition(vui, (intptr_t) v, main_menu_current - MAIN_MENU_ENTRIES);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_right_arrow(vui_context_t *vui, int btn, void *v)
|
||||
void vpi_menu_main_right_arrow(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vanilla_menu_main_start_transition(vui, (intptr_t) v, main_menu_current + MAIN_MENU_ENTRIES);
|
||||
vpi_menu_main_start_transition(vui, (intptr_t) v, main_menu_current + MAIN_MENU_ENTRIES);
|
||||
}
|
||||
|
||||
void vanilla_menu_main(vui_context_t *vui, void *v)
|
||||
void vpi_menu_main(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
@@ -78,20 +79,20 @@ void vanilla_menu_main(vui_context_t *vui, void *v)
|
||||
console_menu_layer = vui_layer_create(vui);
|
||||
|
||||
// Left arrow
|
||||
vui_button_create(vui, 0, arrow_y, BTN_SZ, BTN_SZ, "<", NULL, VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_left_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
vui_button_create(vui, 0, arrow_y, BTN_SZ, BTN_SZ, "<", NULL, VUI_BUTTON_STYLE_BUTTON, layer, vpi_menu_main_left_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
|
||||
// Right arrow
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, arrow_y, BTN_SZ, BTN_SZ, ">", NULL, VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_right_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, arrow_y, BTN_SZ, BTN_SZ, ">", NULL, VUI_BUTTON_STYLE_BUTTON, layer, vpi_menu_main_right_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
|
||||
// Sync button
|
||||
vui_button_create(vui, BTN_SZ, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Sync", NULL, VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_sync_action, (void *) (intptr_t) layer);
|
||||
vui_button_create(vui, BTN_SZ, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, lang(VPI_LANG_SYNC_BTN), NULL, VUI_BUTTON_STYLE_BUTTON, layer, vpi_menu_main_sync_action, (void *) (intptr_t) layer);
|
||||
|
||||
// Connect button
|
||||
vui_button_create(vui, BTN_SZ + (SCREEN_WIDTH-BTN_SZ*2)/2, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Connect", "/home/matt/src/vanilla/rpi/tex/red.png", VUI_BUTTON_STYLE_BUTTON, layer, NULL, NULL);
|
||||
vui_button_create(vui, BTN_SZ + (SCREEN_WIDTH-BTN_SZ*2)/2, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, lang(VPI_LANG_CONNECT_BTN), NULL, VUI_BUTTON_STYLE_BUTTON, layer, NULL, NULL);
|
||||
|
||||
// Delete button
|
||||
vui_button_create(vui, 0, 0, BTN_SZ, BTN_SZ, "Edit", NULL, VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, 0, BTN_SZ, BTN_SZ, "Settings", NULL, VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
vui_button_create(vui, 0, 0, BTN_SZ, BTN_SZ, lang(VPI_LANG_EDIT_BTN), NULL, VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, 0, BTN_SZ, BTN_SZ, lang(VPI_LANG_SETTINGS_BTN), NULL, VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
|
||||
// Console list
|
||||
int list_item_width = SCREEN_WIDTH - BTN_SZ - BTN_SZ;
|
||||
@@ -99,7 +100,7 @@ void vanilla_menu_main(vui_context_t *vui, void *v)
|
||||
for (int i = 0; i < MAIN_MENU_ENTRIES; i++) {
|
||||
main_menu_btns[i] = vui_button_create(vui, BTN_SZ, BTN_SZ + list_item_height * i, list_item_width, list_item_height, NULL, NULL, VUI_BUTTON_STYLE_LIST, console_menu_layer, NULL, NULL);
|
||||
}
|
||||
vanilla_menu_main_populate(vui);
|
||||
vpi_menu_main_populate(vui);
|
||||
|
||||
if (main_menu_first_run) {
|
||||
vui_transition_fade_black_out(vui, NULL, NULL);
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vanilla_menu_main(vui_context_t *vui, void *v);
|
||||
void vpi_menu_main(vui_context_t *vui, void *v);
|
||||
|
||||
#endif // VANILLA_PI_MENU_MAIN_H
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "menu_sudo.h"
|
||||
|
||||
#include "menu_common.h"
|
||||
#include "lang.h"
|
||||
#include "ui/ui_anim.h"
|
||||
|
||||
static int sudo_fglayer;
|
||||
static vui_callback_t sudo_success;
|
||||
static void *sudo_success_data;
|
||||
static vui_callback_t sudo_cancel;
|
||||
static void *sudo_cancel_data;
|
||||
|
||||
void cancel_sudo(vui_context_t *vui, int button, void *data)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, sudo_fglayer, sudo_cancel, sudo_cancel_data);
|
||||
}
|
||||
|
||||
void ok_sudo(vui_context_t *vui, int button, void *data)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, sudo_fglayer, sudo_success, sudo_success_data);
|
||||
}
|
||||
|
||||
void vpi_menu_sudo(vui_context_t *vui, vui_callback_t success, void *success_data, vui_callback_t cancel, void *cancel_data)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
sudo_success = success;
|
||||
sudo_success_data = success_data;
|
||||
sudo_cancel = cancel;
|
||||
sudo_cancel_data = cancel_data;
|
||||
|
||||
int bglayer = vui_layer_create(vui);
|
||||
sudo_fglayer = vui_layer_create(vui);
|
||||
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, bglayer, &bkg_rect, &margin);
|
||||
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
const int lbl_margin = margin * 3;
|
||||
vui_label_create(vui, bkg_rect.x + lbl_margin, bkg_rect.y + lbl_margin, bkg_rect.w - lbl_margin - lbl_margin, bkg_rect.h - lbl_margin - lbl_margin, lang(VPI_LANG_SUDO_HELP_1), vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sudo_fglayer);
|
||||
|
||||
const int lbl2_width = scrw/2;
|
||||
vui_label_create(vui, scrw/2 - lbl2_width/2, bkg_rect.y + lbl_margin + scrh/5, lbl2_width, bkg_rect.h - lbl_margin - lbl_margin, lang(VPI_LANG_SUDO_HELP_2), vui_color_create(0.66f,0.66f,0.66f,1), VUI_FONT_SIZE_SMALL, sudo_fglayer);
|
||||
|
||||
static const int ok_btn_w = BTN_SZ * 3;
|
||||
static const int cancel_btn_w = BTN_SZ * 3;
|
||||
|
||||
vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - (ok_btn_w + cancel_btn_w)/2, bkg_rect.y + bkg_rect.h * 3 / 4, ok_btn_w, BTN_SZ, lang(VPI_LANG_OK_BTN), 0, VUI_BUTTON_STYLE_BUTTON, sudo_fglayer, ok_sudo, 0);
|
||||
vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - (ok_btn_w + cancel_btn_w)/2 + ok_btn_w, bkg_rect.y + bkg_rect.h * 3 / 4, cancel_btn_w, BTN_SZ, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_BUTTON, sudo_fglayer, cancel_sudo, 0);
|
||||
|
||||
vui_transition_fade_layer_in(vui, sudo_fglayer, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef VANILLA_PI_MENU_SUDO_H
|
||||
#define VANILLA_PI_MENU_SUDO_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vpi_menu_sudo(vui_context_t *vui, vui_callback_t success, void *success_data, vui_callback_t cancel, void *cancel_data);
|
||||
|
||||
#endif // VANILLA_PI_MENU_SUDO_H
|
||||
+149
-30
@@ -1,10 +1,15 @@
|
||||
#include "menu_sync.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
#include "lang.h"
|
||||
#include "menu_common.h"
|
||||
#include "menu_main.h"
|
||||
#include "menu_sudo.h"
|
||||
#include "ui/ui_anim.h"
|
||||
#include "ui/ui_util.h"
|
||||
|
||||
@@ -31,38 +36,157 @@ static const char *suit_icons_white[4] = {
|
||||
"club_white.svg",
|
||||
};
|
||||
|
||||
void sync_return_to_main(vui_context_t *vui, int button, void *data)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, sync_fglayer, vpi_menu_sync, (void *) (intptr_t) 1);
|
||||
}
|
||||
|
||||
void sync_show_success(vui_context_t *vui, void *data)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int bglayer = vui_layer_create(vui);
|
||||
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, bglayer, &bkg_rect, &margin);
|
||||
|
||||
sync_fglayer = vui_layer_create(vui);
|
||||
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h/4, bkg_rect.w, bkg_rect.h, "TEMP: Sync successful!", vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
}
|
||||
|
||||
void sync_show_error(vui_context_t *vui, void *data)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int bglayer = vui_layer_create(vui);
|
||||
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, bglayer, &bkg_rect, &margin);
|
||||
|
||||
sync_fglayer = vui_layer_create(vui);
|
||||
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h/4, bkg_rect.w, bkg_rect.h, lang(VPI_LANG_SYNC_FAILED), vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
|
||||
int ret = (int) (intptr_t) data;
|
||||
char buf[20];
|
||||
sprintf(buf, "%i", ret);
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h/2, bkg_rect.w, bkg_rect.h, buf, vui_color_create(1,0,0,1), VUI_FONT_SIZE_SMALL, sync_fglayer);
|
||||
|
||||
vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - BTN_SZ, bkg_rect.y + bkg_rect.h * 3 / 4, BTN_SZ*2, BTN_SZ, lang(VPI_LANG_OK_BTN), 0, VUI_BUTTON_STYLE_BUTTON, sync_fglayer, sync_return_to_main, 0);
|
||||
|
||||
vui_transition_fade_layer_in(vui, sync_fglayer, 0, 0);
|
||||
}
|
||||
|
||||
void sync_success(void *data)
|
||||
{
|
||||
vui_context_t *vui = data;
|
||||
vui_transition_fade_layer_out(vui, sync_fglayer, sync_show_success, 0);
|
||||
}
|
||||
|
||||
int intpow(int x, unsigned int p)
|
||||
{
|
||||
if (p == 0) return 1;
|
||||
if (p == 1) return x;
|
||||
|
||||
int tmp = intpow(x, p/2);
|
||||
if (p%2 == 0) return tmp * tmp;
|
||||
else return x * tmp * tmp;
|
||||
}
|
||||
|
||||
void sync_animation_step(vui_context_t *ctx, int64_t time, void *userdata)
|
||||
{
|
||||
int progress_lbl = (int) (intptr_t) userdata;
|
||||
|
||||
static const int utf8_char_len = 3; // Somewhat hacky, but the important thing is that it works
|
||||
static const int progress_txt_len = 9;
|
||||
static const size_t progress_txt_sz = progress_txt_len * utf8_char_len + 1;
|
||||
|
||||
char progress_txt[progress_txt_sz];
|
||||
progress_txt[progress_txt_sz-1] = 0;
|
||||
|
||||
int64_t m = int64min((sin(time * 0.000004) * 0.5 + 0.5) * progress_txt_len, progress_txt_len - 1);
|
||||
for (int i = 0; i < progress_txt_len; i++) {
|
||||
memcpy(progress_txt + utf8_char_len * i, (i == m) ? "\xE2\xAC\xA4" : "\xE2\x80\xA2", utf8_char_len);
|
||||
}
|
||||
|
||||
vui_label_update_text(ctx, progress_lbl, progress_txt);
|
||||
|
||||
// Poll Vanilla for sync status
|
||||
// if (time > 0) {
|
||||
vanilla_event_t event;
|
||||
while (vanilla_poll_event(&event)) {
|
||||
if (event.type == VANILLA_EVENT_SYNC) {
|
||||
int sync_ret;
|
||||
memcpy(&sync_ret, event.data, sizeof(int));
|
||||
vanilla_free_event(&event);
|
||||
vanilla_stop();
|
||||
vui_transition_fade_layer_out(ctx, sync_fglayer, sync_show_error, (void *) (intptr_t) sync_ret);
|
||||
} else {
|
||||
vanilla_free_event(&event);
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void cancel_sync(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
vanilla_stop();
|
||||
sync_return_to_main(vui, button, 0);
|
||||
}
|
||||
|
||||
void start_syncing(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int bglayer = vui_layer_create(vui);
|
||||
int fglayer = vui_layer_create(vui);
|
||||
sync_fglayer = vui_layer_create(vui);
|
||||
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
const int margin = scrw/75;
|
||||
vui_rect_t bkg_rect;
|
||||
bkg_rect.x = margin;
|
||||
bkg_rect.y = margin;
|
||||
bkg_rect.w = scrw-margin-margin;
|
||||
bkg_rect.h = scrh-margin-margin;
|
||||
|
||||
vui_rect_create(vui, bkg_rect.x, bkg_rect.y, bkg_rect.w, bkg_rect.h, scrh*2/10, vui_color_create(0, 0, 0, 0.66f), bglayer);
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, bglayer, &bkg_rect, &margin);
|
||||
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h/4, bkg_rect.w, bkg_rect.h, "Connecting to the Wii U console...", vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, fglayer);
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h*1/5, bkg_rect.w, bkg_rect.h, lang(VPI_LANG_SYNC_CONNECTING), vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
|
||||
vui_transition_fade_layer_in(vui, fglayer, 0, 0);
|
||||
uint16_t code = 0;
|
||||
for (int i = 0; i < SYNC_BTN_COUNT; i++) {
|
||||
code += sync_str[i] * intpow(10, SYNC_BTN_COUNT - 1 - i);
|
||||
}
|
||||
|
||||
int progress_lbl = vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h*2/5, bkg_rect.w, bkg_rect.h, "", vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
sync_animation_step(vui, 0, (void *) (intptr_t) progress_lbl);
|
||||
|
||||
vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - BTN_SZ*3/2, bkg_rect.y + bkg_rect.h * 3 / 4, BTN_SZ*3, BTN_SZ, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_BUTTON, sync_fglayer, cancel_sync, 0);
|
||||
|
||||
int ret = vanilla_sync(code, VANILLA_ADDRESS_LOCAL);
|
||||
if (ret == VANILLA_SUCCESS) {
|
||||
vui_transition_fade_layer_in(vui, sync_fglayer, 0, 0);
|
||||
vui_start_passive_animation(vui, sync_animation_step, (void *) (intptr_t) progress_lbl);
|
||||
} else {
|
||||
sync_show_error(vui, (void *) (intptr_t) ret);
|
||||
}
|
||||
}
|
||||
|
||||
void start_syncing_or_sudo(vui_context_t *vui, void *v)
|
||||
{
|
||||
const int sudo_required = 1;
|
||||
if (sudo_required) {
|
||||
vpi_menu_sudo(vui, start_syncing, v, vpi_menu_sync, (void *) (intptr_t) 1);
|
||||
} else {
|
||||
start_syncing(vui, v);
|
||||
}
|
||||
}
|
||||
|
||||
void transition_to_sync_window(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, sync_fglayer, start_syncing, 0);
|
||||
vui_transition_fade_layer_out(vui, sync_fglayer, start_syncing_or_sudo, 0);
|
||||
}
|
||||
|
||||
void vanilla_sync_menu_back_action(vui_context_t *vui, int btn, void *v)
|
||||
void vpi_sync_menu_back_action(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vanilla_menu_main, 0);
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vpi_menu_main, 0);
|
||||
}
|
||||
|
||||
void sync_btn_clicked(vui_context_t *vui, int button, void *data)
|
||||
@@ -115,7 +239,7 @@ void create_sync_btn(vui_context_t *vui, int x, int data, int layer, int origin_
|
||||
sync_btns[data] = btn;
|
||||
}
|
||||
|
||||
void vanilla_menu_sync(vui_context_t *vui, void *d)
|
||||
void vpi_menu_sync(vui_context_t *vui, void *d)
|
||||
{
|
||||
// Clears all extra layers
|
||||
vui_reset(vui);
|
||||
@@ -129,23 +253,18 @@ void vanilla_menu_sync(vui_context_t *vui, void *d)
|
||||
sync_bglayer = vui_layer_create(vui);
|
||||
sync_fglayer = vui_layer_create(vui);
|
||||
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, sync_bglayer, &bkg_rect, &margin);
|
||||
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
const int margin = scrw/75;
|
||||
vui_rect_t bkg_rect;
|
||||
bkg_rect.x = margin;
|
||||
bkg_rect.y = margin;
|
||||
bkg_rect.w = scrw-margin-margin;
|
||||
bkg_rect.h = scrh-margin-margin;
|
||||
|
||||
vui_rect_create(vui, bkg_rect.x, bkg_rect.y, bkg_rect.w, bkg_rect.h, scrh*2/10, vui_color_create(0, 0, 0, 0.66f), sync_bglayer);
|
||||
|
||||
const int lbl_margin = margin * 3;
|
||||
vui_label_create(vui, bkg_rect.x + lbl_margin, bkg_rect.y + lbl_margin, bkg_rect.w - lbl_margin - lbl_margin, bkg_rect.h - lbl_margin - lbl_margin, "Touch the symbols in the order they are displayed on the TV screen from left to right.", vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
vui_label_create(vui, bkg_rect.x + lbl_margin, bkg_rect.y + lbl_margin, bkg_rect.w - lbl_margin - lbl_margin, bkg_rect.h - lbl_margin - lbl_margin, lang(VPI_LANG_SYNC_HELP_1), vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, sync_fglayer);
|
||||
|
||||
const int lbl2_width = scrw/2;
|
||||
vui_label_create(vui, scrw/2 - lbl2_width/2, bkg_rect.y + lbl_margin + scrh/5, lbl2_width, bkg_rect.h - lbl_margin - lbl_margin, "If the symbols are not displayed on the TV screen, press the SYNC Button on the Wii U console.", vui_color_create(0.66f,0.66f,0.66f,1), VUI_FONT_SIZE_SMALL, sync_fglayer);
|
||||
vui_label_create(vui, scrw/2 - lbl2_width/2, bkg_rect.y + lbl_margin + scrh/5, lbl2_width, bkg_rect.h - lbl_margin - lbl_margin, lang(VPI_LANG_SYNC_HELP_2), vui_color_create(0.66f,0.66f,0.66f,1), VUI_FONT_SIZE_SMALL, sync_fglayer);
|
||||
|
||||
// Create 4 symbol buttons
|
||||
const int sync_btn_x = scrw/2 - (BTN_SZ*SYNC_BTN_COUNT)/2;
|
||||
@@ -170,7 +289,7 @@ void vanilla_menu_sync(vui_context_t *vui, void *d)
|
||||
vui_button_create(vui, sync_btn_x + BTN_SZ * 3, sync_entry_rect.y, BTN_SZ, sync_entry_rect.h, 0, "backspace_black.svg", VUI_BUTTON_STYLE_BUTTON, sync_fglayer, bksp_btn_clicked, 0);
|
||||
|
||||
int back_btn_h = scrh/6;
|
||||
vui_button_create(vui, 0, scrh-back_btn_h, scrw/4, back_btn_h, "Cancel", 0, VUI_BUTTON_STYLE_CORNER, sync_fglayer, vanilla_sync_menu_back_action, (void *) (intptr_t) sync_bglayer);
|
||||
vui_button_create(vui, 0, scrh-back_btn_h, scrw/4, back_btn_h, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_CORNER, sync_fglayer, vpi_sync_menu_back_action, (void *) (intptr_t) sync_bglayer);
|
||||
|
||||
vui_transition_fade_layer_in(vui, sync_bglayer, 0, 0);
|
||||
vui_transition_fade_layer_in(vui, d ? sync_fglayer : sync_bglayer, 0, 0);
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vanilla_menu_sync(vui_context_t *vui, void *d);
|
||||
void vpi_menu_sync(vui_context_t *vui, void *d);
|
||||
|
||||
#endif // VANILLA_PI_MENU_SYNC_H
|
||||
+37
-5
@@ -30,6 +30,7 @@ int vui_reset(vui_context_t *ctx)
|
||||
ctx->button_count = 0;
|
||||
ctx->label_count = 0;
|
||||
ctx->rect_count = 0;
|
||||
ctx->passive_animation_count = 0;
|
||||
memset(ctx->images, 0, sizeof(ctx->images));
|
||||
ctx->animation_enabled = 0;
|
||||
ctx->button_active = -1;
|
||||
@@ -203,12 +204,29 @@ void vui_cancel_animation(vui_context_t *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
int vui_start_passive_animation(vui_context_t *ctx, vui_anim_step_callback_t step, void *step_data)
|
||||
{
|
||||
int cur_anim = ctx->passive_animation_count;
|
||||
if (cur_anim == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->passive_animation_count++;
|
||||
|
||||
// Set layer defaults
|
||||
vui_animation_t *a = &ctx->passive_animations[cur_anim];
|
||||
a->step = step;
|
||||
a->step_data = step_data;
|
||||
gettimeofday(&a->start_time, NULL);
|
||||
|
||||
return cur_anim;
|
||||
}
|
||||
|
||||
void vui_start_animation(vui_context_t *ctx, int64_t length, vui_anim_step_callback_t step, void *step_data, vui_callback_t complete, void *complete_data)
|
||||
{
|
||||
vui_cancel_animation(ctx);
|
||||
|
||||
ctx->animation_enabled = 1;
|
||||
ctx->animation.progress = 0;
|
||||
ctx->animation.length = length;
|
||||
ctx->animation.step = step;
|
||||
ctx->animation.step_data = step_data;
|
||||
@@ -222,10 +240,10 @@ void vui_start_animation(vui_context_t *ctx, int64_t length, vui_anim_step_callb
|
||||
|
||||
void vui_update(vui_context_t *ctx)
|
||||
{
|
||||
if (ctx->animation_enabled) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (ctx->animation_enabled) {
|
||||
int64_t diff = (now.tv_sec - ctx->animation.start_time.tv_sec) * 1000000 + (now.tv_usec - ctx->animation.start_time.tv_usec);
|
||||
|
||||
if (diff > ctx->animation.length) {
|
||||
@@ -244,6 +262,14 @@ void vui_update(vui_context_t *ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ctx->passive_animation_count; i++) {
|
||||
vui_animation_t *a = &ctx->passive_animations[i];
|
||||
int64_t diff = (now.tv_sec - a->start_time.tv_sec) * 1000000 + (now.tv_usec - a->start_time.tv_usec);
|
||||
if (a->step) {
|
||||
a->step(ctx, diff, a->step_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vui_layer_create(vui_context_t *ctx)
|
||||
@@ -318,13 +344,19 @@ int vui_label_create(vui_context_t *ctx, int x, int y, int w, int h, const char
|
||||
lbl->size = size;
|
||||
|
||||
lbl->layer = layer;
|
||||
vui_strcpy(lbl->text, text);
|
||||
vui_label_update_text(ctx, index, text);
|
||||
|
||||
ctx->label_count++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int vui_label_update_text(vui_context_t *ctx, int index, const char *text)
|
||||
{
|
||||
vui_label_t *lbl = &ctx->labels[index];
|
||||
vui_strcpy(lbl->text, text);
|
||||
}
|
||||
|
||||
int vui_rect_create(vui_context_t *ctx, int x, int y, int w, int h, int border_radius, vui_color_t color, int layer)
|
||||
{
|
||||
if (ctx->rect_count == MAX_BUTTON_COUNT) {
|
||||
|
||||
@@ -72,6 +72,7 @@ void vui_button_update_style(vui_context_t *ctx, int button, vui_button_style_t
|
||||
* Label-related functions
|
||||
*/
|
||||
int vui_label_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_color_t color, vui_font_size_t size, int layer);
|
||||
int vui_label_update_text(vui_context_t *ctx, int label, const char *text);
|
||||
|
||||
/**
|
||||
* Rect-related functions
|
||||
@@ -94,6 +95,7 @@ vui_color_t vui_color_create(float r, float g, float b, float a);
|
||||
*/
|
||||
void vui_start_animation(vui_context_t *ctx, int64_t length, vui_anim_step_callback_t step, void *step_data, vui_callback_t complete, void *complete_data);
|
||||
void vui_cancel_animation(vui_context_t *ctx);
|
||||
int vui_start_passive_animation(vui_context_t *ctx, vui_anim_step_callback_t step, void *step_data);
|
||||
|
||||
/**
|
||||
* Input-related functions
|
||||
|
||||
+2
-3
@@ -60,9 +60,6 @@ typedef struct {
|
||||
/// @brief System/game time that the animation starts
|
||||
struct timeval start_time;
|
||||
|
||||
/// @brief Progress stored in microseconds
|
||||
int64_t progress;
|
||||
|
||||
/// @brief Length stored in microseconds
|
||||
int64_t length;
|
||||
|
||||
@@ -90,6 +87,8 @@ typedef struct vui_context_t {
|
||||
vui_image_t images[MAX_BUTTON_COUNT];
|
||||
vui_animation_t animation;
|
||||
int animation_enabled;
|
||||
vui_animation_t passive_animations[MAX_BUTTON_COUNT];
|
||||
int passive_animation_count;
|
||||
int button_active;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
|
||||
+28
-23
@@ -4,6 +4,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
#include "ui_priv.h"
|
||||
#include "ui_util.h"
|
||||
@@ -25,6 +26,7 @@ typedef struct {
|
||||
SDL_Rect dst_rect;
|
||||
SDL_Texture *background;
|
||||
SDL_Texture *layer_data[MAX_BUTTON_COUNT];
|
||||
SDL_Texture *label_data[MAX_BUTTON_COUNT];
|
||||
vui_sdl_cached_texture_t button_cache[MAX_BUTTON_COUNT];
|
||||
vui_sdl_cached_texture_t image_cache[MAX_BUTTON_COUNT];
|
||||
} vui_sdl_context_t;
|
||||
@@ -83,6 +85,7 @@ int vui_init_sdl(vui_context_t *ctx, int fullscreen)
|
||||
|
||||
sdl_ctx->background = 0;
|
||||
memset(sdl_ctx->layer_data, 0, sizeof(sdl_ctx->layer_data));
|
||||
memset(sdl_ctx->label_data, 0, sizeof(sdl_ctx->label_data));
|
||||
memset(sdl_ctx->button_cache, 0, sizeof(sdl_ctx->button_cache));
|
||||
memset(sdl_ctx->image_cache, 0, sizeof(sdl_ctx->image_cache));
|
||||
|
||||
@@ -343,33 +346,34 @@ void vui_draw_sdl(vui_context_t *ctx, SDL_Renderer *renderer)
|
||||
// Draw labels
|
||||
for (int i = 0; i < ctx->label_count; i++) {
|
||||
vui_label_t *lbl = &ctx->labels[i];
|
||||
if (lbl->text[0]) {
|
||||
SDL_SetRenderTarget(renderer, sdl_ctx->layer_data[lbl->layer]);
|
||||
|
||||
SDL_SetRenderTarget(renderer, sdl_ctx->layer_data[lbl->layer]);
|
||||
SDL_Color c;
|
||||
c.r = lbl->color.r * 0xFF;
|
||||
c.g = lbl->color.g * 0xFF;
|
||||
c.b = lbl->color.b * 0xFF;
|
||||
c.a = lbl->color.a * 0xFF;
|
||||
|
||||
SDL_Color c;
|
||||
c.r = lbl->color.r * 0xFF;
|
||||
c.g = lbl->color.g * 0xFF;
|
||||
c.b = lbl->color.b * 0xFF;
|
||||
c.a = lbl->color.a * 0xFF;
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(lbl->size == VUI_FONT_SIZE_SMALL ? sysfont_mini : sysfont, lbl->text, c, lbl->w);
|
||||
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(lbl->size == VUI_FONT_SIZE_SMALL ? sysfont_mini : sysfont, lbl->text, c, lbl->w);
|
||||
SDL_Rect sr;
|
||||
sr.x = 0;
|
||||
sr.y = 0;
|
||||
sr.w = intmin(lbl->w, surface->w);
|
||||
sr.h = intmin(lbl->h, surface->h);
|
||||
|
||||
SDL_Rect sr;
|
||||
sr.x = 0;
|
||||
sr.y = 0;
|
||||
sr.w = intmin(lbl->w, surface->w);
|
||||
sr.h = intmin(lbl->h, surface->h);
|
||||
|
||||
SDL_Rect dr;
|
||||
dr.x = lbl->x;
|
||||
dr.y = lbl->y;
|
||||
dr.w = sr.w;
|
||||
dr.h = sr.h;
|
||||
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_RenderCopy(renderer, texture, &sr, &dr);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_Rect dr;
|
||||
dr.x = lbl->x;
|
||||
dr.y = lbl->y;
|
||||
dr.w = sr.w;
|
||||
dr.h = sr.h;
|
||||
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_RenderCopy(renderer, texture, &sr, &dr);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw buttons
|
||||
@@ -452,6 +456,7 @@ int vui_update_sdl(vui_context_t *vui)
|
||||
SDL_Event ev;
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
if (ev.type == SDL_QUIT) {
|
||||
vanilla_stop();
|
||||
return 0;
|
||||
} else if (ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP) {
|
||||
if (dst_rect->w > 0 && dst_rect->h > 0) {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#ifndef VANILLA_PI_UI_UTIL_H
|
||||
#define VANILLA_PI_UI_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void vui_strcpy(char *dst, const char *src);
|
||||
|
||||
static inline int intmin(int a, int b) { return a < b ? a : b; }
|
||||
static inline int intmax(int a, int b) { return a > b ? a : b; }
|
||||
static inline int64_t int64min(int64_t a, int64_t b) { return a < b ? a : b; }
|
||||
static inline int64_t int64max(int64_t a, int64_t b) { return a > b ? a : b; }
|
||||
|
||||
#endif // VANILLA_PI_UI_UTIL_H
|
||||
Reference in new issue
Block a user